aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--readme.md6
-rw-r--r--src/format/mod.rs4
-rw-r--r--src/main.rs100
3 files changed, 95 insertions, 15 deletions
diff --git a/readme.md b/readme.md
index ea96c76..2c1998a 100644
--- a/readme.md
+++ b/readme.md
@@ -23,7 +23,7 @@ $ cargo run
23### usage 23### usage
24 24
25```shell 25```shell
26eva 0.2.3 26eva 0.2.4
27NerdyPepper <[email protected]> 27NerdyPepper <[email protected]>
28Calculator REPL similar to bc(1) 28Calculator REPL similar to bc(1)
29 29
@@ -36,10 +36,12 @@ FLAGS:
36 -V, --version Prints version information 36 -V, --version Prints version information
37 37
38OPTIONS: 38OPTIONS:
39 -f, --fix <FIX> set number of decimal places in the output 39 -b, --base <RADIX> set the radix of calculation output (2, 8, 10, 16 etc.)
40 -f, --fix <FIX> set number of decimal places in the output
40 41
41ARGS: 42ARGS:
42 <INPUT> optional expression string to run eva in command mode 43 <INPUT> optional expression string to run eva in command mode
44
43``` 45```
44 46
45type out an expression and hit enter, repeat. 47type out an expression and hit enter, repeat.
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
8use std::f64; 8use std::f64;
9use std::borrow::Cow::{self, Borrowed, Owned};
9 10
10// modules 11// modules
11mod lex; 12mod lex;
@@ -19,11 +20,81 @@ use crate::format::*;
19 20
20// extern crates 21// extern crates
21use rustyline::error::ReadlineError; 22use rustyline::error::ReadlineError;
22use rustyline::Editor; 23use rustyline::{ Editor, Context, Helper };
23use rustyline::config::{ Builder, ColorMode, EditMode }; 24use rustyline::config::{ Builder, ColorMode, EditMode, CompletionType };
25use rustyline::hint::Hinter;
26use rustyline::completion::{ FilenameCompleter, Completer, Pair };
27use rustyline::highlight::{ Highlighter, MatchingBracketHighlighter };
28
24use clap::{Arg, App}; 29use clap::{Arg, App};
25use lazy_static::lazy_static; 30use lazy_static::lazy_static;
26 31
32
33struct RLHelper {
34 completer: FilenameCompleter,
35 highlighter: LineHighlighter,
36 hinter: AnswerHinter,
37}
38
39struct AnswerHinter { }
40impl 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
55struct LineHighlighter { }
56impl 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
69impl 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
78impl 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
90impl 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
96impl Helper for RLHelper {}
97
27struct Configuration { 98struct 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