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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::collections::HashMap;
use std::io::{BufRead, BufReader, Stdin, Stdout, Write};
use std::sync::Arc;
use std::vec::Vec;
use crate::CliHandler;
pub const PROMPT: &str = "> ";
pub const HELP: &str = "help";
pub const EXIT: &str = "exit";
pub const INVALID_COMMAND: &str = "Invalid command";
pub struct CliManager<R: BufRead, W: Write> {
reader: R,
writer: W,
handlers: HashMap<String, Arc<dyn CliHandler>>,
}
impl Default for CliManager<BufReader<Stdin>, Stdout> {
fn default() -> Self {
CliManager {
reader: BufReader::new(std::io::stdin()),
writer: std::io::stdout(),
handlers: HashMap::default(),
}
}
}
impl CliManager<BufReader<Stdin>, Stdout> {
pub fn new() -> Self {
Self::default()
}
}
impl<R: BufRead, W: 'static + Write> CliManager<R, W> {
pub fn with_reader_writer(reader: R, writer: W) -> CliManager<R, W> {
CliManager {
reader,
writer,
handlers: HashMap::new(),
}
}
pub fn start(&mut self) {
loop {
write!(self.writer, "{}", PROMPT).expect("Failed to print prompt");
self.writer.flush().expect("Failed to flush prompt");
let mut input = String::new();
self.reader.read_line(&mut input).expect("Failed to read line");
let input = input.trim().to_owned();
if input.is_empty() {
continue;
}
let (command, args) = parse_input(input);
if command.is_empty() {
writeln!(self.writer, "{}", INVALID_COMMAND).expect("Failed to print `Invalid command`");
continue;
}
if EXIT.eq_ignore_ascii_case(&command) {
break;
} else if HELP.eq_ignore_ascii_case(&command) {
let mut cmds: Vec<String> = self.handlers.iter().map(|(cmd, _)| cmd.clone()).collect();
cmds.sort();
for cmd in cmds {
writeln!(self.writer, "{}", cmd).expect("Failed to print help output");
}
} else {
let handler = self.handlers.get(&command);
match handler {
Some(ref value) => {
if let Err(msg) = value.handle_command(&command, args, &mut self.writer) {
writeln!(self.writer, "{}", msg).expect("Failed to print error message");
}
}
None => writeln!(self.writer, "{}", INVALID_COMMAND).expect("Failed to print `Invalid command`"),
};
}
}
}
pub fn add_handler(&mut self, handler: Arc<dyn CliHandler>) {
for cmd in handler.get_commands() {
self.handlers.insert(cmd.to_string(), Arc::clone(&handler));
}
}
}
fn parse_input(input: String) -> (String, Vec<String>) {
let quoted_vars: Vec<&str> = input.split('\"').collect();
let mut command = String::new();
let mut vars: Vec<String> = Vec::new();
for element in quoted_vars.iter().enumerate() {
if element.0 % 2 == 0 {
let space_vars: Vec<&str> = element.1.split(' ').collect();
for var in space_vars {
let var = var.trim();
if !var.is_empty() {
if command.is_empty() {
command.push_str(var);
} else {
vars.push(var.to_string());
}
}
}
} else {
vars.push(element.1.to_string());
}
}
(command, vars)
}