aboutsummaryrefslogtreecommitdiff
path: root/src/readline.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/readline.rs')
-rw-r--r--src/readline.rs121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/readline.rs b/src/readline.rs
new file mode 100644
index 0000000..ea195ee
--- /dev/null
+++ b/src/readline.rs
@@ -0,0 +1,121 @@
1use std::borrow::Cow::{self, Owned};
2use std::path::PathBuf;
3
4use rustyline::completion::{Completer, FilenameCompleter, Pair};
5use rustyline::config::{Builder, ColorMode, CompletionType, EditMode};
6use rustyline::error::ReadlineError;
7use rustyline::highlight::Highlighter;
8use rustyline::hint::{Hinter, HistoryHinter};
9use rustyline::{Context, Editor, Helper};
10
11use directories::ProjectDirs;
12
13use regex::Regex;
14
15use crate::eval_math_expression;
16
17pub struct RLHelper {
18 completer: FilenameCompleter,
19 highlighter: LineHighlighter,
20 hinter: HistoryHinter,
21}
22
23struct LineHighlighter {}
24impl Highlighter for LineHighlighter {
25 fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
26 Owned(format!("\x1b[90m{}\x1b[0m", hint))
27 }
28 fn highlight<'l>(&self, line: &'l str, _: usize) -> Cow<'l, str> {
29 use std::fs::OpenOptions;
30 use std::io::{BufRead, BufReader};
31
32 let eva_dirs = ProjectDirs::from("com", "NerdyPepper", "eva").unwrap();
33 let eva_data_dir = eva_dirs.data_dir();
34 let mut previous_ans_path = PathBuf::from(eva_data_dir);
35 previous_ans_path.push("previous_ans.txt");
36
37 let file = OpenOptions::new()
38 .create(true)
39 .read(true)
40 .append(true)
41 .open(&previous_ans_path)
42 .unwrap();
43
44 let rdr = BufReader::new(file);
45 let lines = rdr.lines().map(|l| l.unwrap());
46 let prev_ans = match lines.last() {
47 Some(val) => val.parse::<f64>().ok(),
48 None => None,
49 };
50 let op = eval_math_expression(line, prev_ans);
51 match op {
52 Ok(_) => {
53 let constants = ["e", "pi"];
54 let functions = [
55 "sin", "cos", "tan", "csc", "sec", "cot", "sinh", "cosh", "tanh", "ln", "log",
56 "sqrt", "ceil", "floor", "rad", "deg", "abs", "asin", "acos", "atan", "acsc",
57 "asec", "acot",
58 ];
59 let ops = Regex::new(r"(?P<o>[\+-/\*%\^!])").unwrap();
60 let mut coloured: String = ops.replace_all(line, "\x1b[35m$o\x1b[0m").into();
61
62 for c in &constants {
63 coloured = coloured.replace(c, &format!("\x1b[33m{}\x1b[0m", c));
64 }
65 for f in &functions {
66 coloured = coloured.replace(f, &format!("\x1b[34m{}\x1b[0m", f));
67 }
68 Owned(coloured)
69 }
70 Err(_) => Owned(format!("\x1b[31m{}\x1b[0m", line)),
71 }
72 }
73}
74
75impl Highlighter for RLHelper {
76 fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
77 self.highlighter.highlight_hint(hint)
78 }
79 fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> {
80 self.highlighter.highlight(line, pos)
81 }
82}
83
84impl Completer for RLHelper {
85 type Candidate = Pair;
86 fn complete(
87 &self,
88 line: &str,
89 pos: usize,
90 ctx: &Context<'_>,
91 ) -> Result<(usize, Vec<Pair>), ReadlineError> {
92 self.completer.complete(line, pos, ctx)
93 }
94}
95
96impl Hinter for RLHelper {
97 fn hint(&self, line: &str, a: usize, b: &Context) -> Option<String> {
98 self.hinter.hint(line, a, b)
99 }
100}
101
102impl Helper for RLHelper {}
103
104pub fn create_readline() -> Editor<RLHelper> {
105 let config_builder = Builder::new();
106 let config = config_builder
107 .color_mode(ColorMode::Enabled)
108 .edit_mode(EditMode::Emacs)
109 .history_ignore_space(true)
110 .completion_type(CompletionType::Circular)
111 .max_history_size(1000)
112 .build();
113 let mut rl = Editor::with_config(config);
114 let h = RLHelper {
115 completer: FilenameCompleter::new(),
116 highlighter: LineHighlighter {},
117 hinter: HistoryHinter {},
118 };
119 rl.set_helper(Some(h));
120 rl
121}