1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use crate::repl::{settings::SessionSettings, Session};
use ansi_term::{Colour, Style};
use rustyline::error::ReadlineError;
use rustyline::Editor;
use std::io::{stdin, stdout, Write};
const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");
const HISTORY_FILE: Option<&'static str> = option_env!("CLARITY_REPL_HISTORY_FILE");
fn complete_input(str: &str) -> Result<Option<char>, (char, char)> {
let mut brackets = vec![];
for character in str.chars() {
match character {
'(' | '{' => brackets.push(character),
')' | '}' => match (brackets.pop(), character) {
(Some('('), '}') => return Err((')', '}')),
(Some('{'), ')') => return Err(('}', ')')),
_ => {}
},
_ => {}
}
}
match brackets.last() {
Some(char) => Ok(Some(*char)),
_ => Ok(None),
}
}
pub struct Terminal {
pub session: Session,
}
impl Terminal {
pub fn new(session_settings: SessionSettings) -> Terminal {
let mut session = Session::new(session_settings);
session.is_interactive = true;
Terminal { session }
}
pub fn start(&mut self) {
println!("{}", green!(format!("clarity-repl v{}", VERSION.unwrap())));
println!("{}", black!("Enter \"::help\" for usage hints."));
println!("{}", black!("Connected to a transient in-memory database."));
let output = match self.session.start() {
Ok((output, _)) => output,
Err(e) => {
println!("{}", e);
std::process::exit(1);
}
};
println!("{}", output);
let mut editor = Editor::<()>::new();
let mut ctrl_c_acc = 0;
let mut input_buffer = vec![];
let mut prompt = String::from(">> ");
editor
.load_history(HISTORY_FILE.unwrap_or("history.txt"))
.ok();
loop {
let readline = editor.readline(prompt.as_str());
match readline {
Ok(command) => {
ctrl_c_acc = 0;
input_buffer.push(command);
let input = input_buffer.join("\n");
match complete_input(&input) {
Ok(None) => {
let output = self.session.handle_command(&input);
for line in output {
println!("{}", line);
}
prompt = String::from(">> ");
self.session.executed.push(input.clone());
editor.add_history_entry(&input);
input_buffer.clear();
}
Ok(Some(str)) => {
prompt = format!("{}.. ", str);
}
Err((expected, got)) => {
println!("Error: expected closing {}, got {}", expected, got);
input_buffer.pop();
}
}
}
Err(ReadlineError::Interrupted) => {
ctrl_c_acc += 1;
if ctrl_c_acc == 2 {
break;
} else {
println!("{}", yellow!("Hit CTRL-C a second time to quit."));
}
}
Err(ReadlineError::Eof) => {
println!("CTRL-D");
break;
}
Err(err) => {
println!("Error: {:?}", err);
break;
}
}
}
editor
.save_history(HISTORY_FILE.unwrap_or("history.txt"))
.unwrap();
}
}