1#[warn(missing_docs)]
6use doc_comment::doc_comment;
7doc_comment!(include_str!("../README.md"));
8
9use colored::Colorize as Colourise; use rustyline::{error::ReadlineError, Cmd, Editor, KeyEvent};
11use std::collections::HashMap;
12use std::error::Error;
13
14pub mod error;
15pub mod lex;
16pub mod prelude;
17mod scan;
18mod tests;
19
20pub type Command = fn(lex::Arguments) -> Result<(), error::Error>;
22
23pub struct Console {
25 pub command_table: HashMap<String, Command>,
27 pub prompt: String,
29}
30
31impl Console {
32 pub fn new(command_table: HashMap<String, Command>, prompt: &str) -> Console {
34 Console {
35 command_table,
36 prompt: prompt.to_owned(),
37 }
38 }
39 pub fn run_repl(&self) {
41 loop {
42 let mut rl = Editor::<()>::new();
43
44 rl.bind_sequence(KeyEvent::ctrl('A'), Cmd::HistorySearchForward);
45 rl.bind_sequence(KeyEvent::ctrl('B'), Cmd::HistorySearchBackward);
46
47 if rl.load_history(".rusterm_history").is_err() {
48 eprintln!("Could not load history file.");
49 }
50
51 let input = match rl.readline(&self.prompt) {
52 Ok(x) if x.is_empty() => continue,
53 Ok(x) if x == *"exit" => break,
54 Ok(x) => {
55 rl.add_history_entry(x.clone());
56 x
57 }
58 Err(ReadlineError::Interrupted) => {
59 eprintln!("^C");
60 break;
61 }
62 Err(ReadlineError::Eof) => {
63 eprintln!("^D");
64 break;
65 }
66 Err(x) => {
67 eprintln!(
68 "{}{} {}",
69 "Error while reading input".red().bold(),
70 ":".bold(),
71 x
72 );
73 break;
74 }
75 };
76 if let Err(x) = self.parse(input) {
77 eprintln!("{}", x);
78 }
79 if rl.append_history(".rusterm_history").is_err() {
80 eprintln!("Could not append to history file.");
81 }
82 }
83 }
84 fn parse(&self, input: String) -> Result<(), Box<dyn Error>> {
85 let mut scanned_input = scan::scan(input);
86 let function_name = scanned_input.get(0).unwrap_or(&"".to_string()).clone();
87 if !function_name.is_empty() {
88 scanned_input.remove(0);
89 }
90 let lexed_input = lex::lex(scanned_input);
91 let function = match function_name {
92 x if x == *"help" => {
93 self.help();
94 return Ok(());
95 }
96 _ => self
97 .command_table
98 .get(&function_name)
99 .ok_or(error::Error::NoSuchCommand)?,
100 };
101 if let Err(x) = function(lexed_input) {
102 println!("{}", x)
103 }
104 Ok(())
105 }
106
107 fn help(&self) {
108 println!("{}", "List of commands:".bold());
109 for name in self.command_table.keys() {
110 println!("{}", name);
111 }
112 println!("help");
113 println!("exit")
114 }
115}