diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/format/mod.rs | 4 | ||||
-rw-r--r-- | src/main.rs | 100 |
2 files changed, 91 insertions, 13 deletions
diff --git a/src/format/mod.rs b/src/format/mod.rs index 4ac5612..baae301 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs | |||
@@ -35,7 +35,7 @@ fn radix_fmt(number: f64, obase: usize) -> Result<String, CalcError> { | |||
35 | let table: Vec<char> = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars().collect(); | 35 | let table: Vec<char> = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars().collect(); |
36 | 36 | ||
37 | // format integral part of float | 37 | // format integral part of float |
38 | let mut integral = number.trunc() as i64; | 38 | let mut integral = number.abs().trunc() as i64; |
39 | let mut obase_int = String::new(); | 39 | let mut obase_int = String::new(); |
40 | while integral >= obase as i64 { | 40 | while integral >= obase as i64 { |
41 | obase_int.push(table[(integral % obase as i64) as usize]); | 41 | obase_int.push(table[(integral % obase as i64) as usize]); |
@@ -55,7 +55,7 @@ fn radix_fmt(number: f64, obase: usize) -> Result<String, CalcError> { | |||
55 | fract *= obase as f64; | 55 | fract *= obase as f64; |
56 | obase_fract.push(table[fract.trunc() as usize]); | 56 | obase_fract.push(table[fract.trunc() as usize]); |
57 | i += 1; | 57 | i += 1; |
58 | if fract.fract() == 0. || i > 10 { | 58 | if fract.fract() == 0. || i >= CONFIGURATION.fix { |
59 | break; | 59 | break; |
60 | } | 60 | } |
61 | fract = fract.fract(); | 61 | fract = fract.fract(); |
diff --git a/src/main.rs b/src/main.rs index ddfa75b..d6883d5 100644 --- a/src/main.rs +++ b/src/main.rs | |||
@@ -6,6 +6,7 @@ | |||
6 | 6 | ||
7 | // std | 7 | // std |
8 | use std::f64; | 8 | use std::f64; |
9 | use std::borrow::Cow::{self, Borrowed, Owned}; | ||
9 | 10 | ||
10 | // modules | 11 | // modules |
11 | mod lex; | 12 | mod lex; |
@@ -19,11 +20,81 @@ use crate::format::*; | |||
19 | 20 | ||
20 | // extern crates | 21 | // extern crates |
21 | use rustyline::error::ReadlineError; | 22 | use rustyline::error::ReadlineError; |
22 | use rustyline::Editor; | 23 | use rustyline::{ Editor, Context, Helper }; |
23 | use rustyline::config::{ Builder, ColorMode, EditMode }; | 24 | use rustyline::config::{ Builder, ColorMode, EditMode, CompletionType }; |
25 | use rustyline::hint::Hinter; | ||
26 | use rustyline::completion::{ FilenameCompleter, Completer, Pair }; | ||
27 | use rustyline::highlight::{ Highlighter, MatchingBracketHighlighter }; | ||
28 | |||
24 | use clap::{Arg, App}; | 29 | use clap::{Arg, App}; |
25 | use lazy_static::lazy_static; | 30 | use lazy_static::lazy_static; |
26 | 31 | ||
32 | |||
33 | struct RLHelper { | ||
34 | completer: FilenameCompleter, | ||
35 | highlighter: LineHighlighter, | ||
36 | hinter: AnswerHinter, | ||
37 | } | ||
38 | |||
39 | struct AnswerHinter { } | ||
40 | impl Hinter for AnswerHinter { | ||
41 | fn hint(&self, line: &str, _: usize, _: &Context) -> Option<String> { | ||
42 | let input = line.trim(); | ||
43 | let input = input.replace(" ", ""); | ||
44 | if input.len() == 0 { | ||
45 | return Some("".into()) | ||
46 | } | ||
47 | let dry_run = eval_math_expression(&input); | ||
48 | match dry_run { | ||
49 | Ok(ans) => return Some(format!(" = {}", ans)), | ||
50 | Err(_) => return Some(format!("")) | ||
51 | }; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | struct LineHighlighter { } | ||
56 | impl Highlighter for LineHighlighter { | ||
57 | fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { | ||
58 | Owned(format!("\x1b[90m{}\x1b[0m", hint)) | ||
59 | } | ||
60 | fn highlight<'l>(&self, line: &'l str, _: usize) -> Cow<'l, str> { | ||
61 | let op = eval_math_expression(line); | ||
62 | match op { | ||
63 | Ok(_) => Owned(line.into()), | ||
64 | Err(_) => Owned(format!("\x1b[31m{}\x1b[0m", line)) | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | |||
69 | impl Highlighter for RLHelper { | ||
70 | fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> { | ||
71 | self.highlighter.highlight_hint(hint) | ||
72 | } | ||
73 | fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> { | ||
74 | self.highlighter.highlight(line, pos) | ||
75 | } | ||
76 | } | ||
77 | |||
78 | impl Completer for RLHelper { | ||
79 | type Candidate = Pair; | ||
80 | fn complete( | ||
81 | &self, | ||
82 | line: &str, | ||
83 | pos: usize, | ||
84 | ctx: &Context<'_>, | ||
85 | ) -> Result<(usize, Vec<Pair>), ReadlineError> { | ||
86 | self.completer.complete(line, pos, ctx) | ||
87 | } | ||
88 | } | ||
89 | |||
90 | impl Hinter for RLHelper { | ||
91 | fn hint(&self, line: &str, a: usize, b: &Context) -> Option<String> { | ||
92 | self.hinter.hint(line, a, b) | ||
93 | } | ||
94 | } | ||
95 | |||
96 | impl Helper for RLHelper {} | ||
97 | |||
27 | struct Configuration { | 98 | struct Configuration { |
28 | radian_mode: bool, | 99 | radian_mode: bool, |
29 | fix: usize, | 100 | fix: usize, |
@@ -50,12 +121,19 @@ fn main() { | |||
50 | let config = config_builder.color_mode(ColorMode::Enabled) | 121 | let config = config_builder.color_mode(ColorMode::Enabled) |
51 | .edit_mode(EditMode::Emacs) | 122 | .edit_mode(EditMode::Emacs) |
52 | .history_ignore_space(true) | 123 | .history_ignore_space(true) |
124 | .completion_type(CompletionType::Circular) | ||
53 | .max_history_size(1000) | 125 | .max_history_size(1000) |
54 | .build(); | 126 | .build(); |
55 | let mut rl = Editor::<()>::with_config(config); | 127 | let mut rl = Editor::with_config(config); |
128 | let h = RLHelper { | ||
129 | completer: FilenameCompleter::new(), | ||
130 | highlighter: LineHighlighter {}, | ||
131 | hinter: AnswerHinter {} | ||
132 | }; | ||
133 | rl.set_helper(Some(h)); | ||
56 | if rl.load_history("history.txt").is_err() { | 134 | if rl.load_history("history.txt").is_err() { |
57 | println!("No previous history."); | 135 | println!("No previous history.") |
58 | } | 136 | }; |
59 | 137 | ||
60 | loop { | 138 | loop { |
61 | let readline = rl.readline("> "); | 139 | let readline = rl.readline("> "); |
@@ -102,7 +180,7 @@ fn parse_arguments() -> Configuration { | |||
102 | .long("base") | 180 | .long("base") |
103 | .takes_value(true) | 181 | .takes_value(true) |
104 | .value_name("RADIX") | 182 | .value_name("RADIX") |
105 | .help("set the radix of calculation output (2, 8, 10, 16 etc.)")) | 183 | .help("set the radix of calculation output (1 - 36)")) |
106 | .arg(Arg::with_name("INPUT") | 184 | .arg(Arg::with_name("INPUT") |
107 | .help("optional expression string to run eva in command mode") | 185 | .help("optional expression string to run eva in command mode") |
108 | .index(1)) | 186 | .index(1)) |
@@ -122,11 +200,11 @@ fn parse_arguments() -> Configuration { | |||
122 | .unwrap_or("10") | 200 | .unwrap_or("10") |
123 | .parse() | 201 | .parse() |
124 | .unwrap(), | 202 | .unwrap(), |
125 | base: config.value_of("base") | 203 | base: config.value_of("base") |
126 | .unwrap_or("10") | 204 | .unwrap_or("10") |
127 | .parse() | 205 | .parse() |
128 | .unwrap(), | 206 | .unwrap(), |
129 | input, | 207 | input, |
130 | } | 208 | } |
131 | } | 209 | } |
132 | 210 | ||