command_handler/
command_handler.rs1use std::io::{
5 self,
6 BufRead,
7 Write,
8};
9
10use malachi::{
11 Args,
12 Command,
13};
14
15type Callback = Box<dyn for<'a> Fn(Args<'a, 'a>)>;
16
17struct Handler {
18 cmd: Command,
19 callback: Callback,
20}
21
22struct Handlers(Vec<Handler>);
23
24impl Handlers {
25 fn execute(&self, msg: &str) {
26 for cmd in &self.0 {
28 if let Some(args) = cmd.cmd.get_matches(msg) {
30 (cmd.callback)(args);
31 return;
32 }
33 }
34
35 println!("No command matched the input.");
36 }
37
38 fn add<F>(&mut self, cmd: &str, callback: F) -> Result<&mut Self, malachi::Error>
39 where
40 F: for<'a> Fn(Args<'a, 'a>) + 'static,
41 {
42 println!("adding new command: {}", cmd);
43 self.0.push(Handler {
44 cmd: Command::new(cmd)?,
45 callback: Box::new(callback),
46 });
47
48 Ok(self)
49 }
50}
51
52fn cmd_join(args: Args) {
53 let sep = args.get_once("separator").unwrap_or("-");
55 let tokens = args.get_many("words").unwrap();
57
58 println!("{}", tokens.join(sep));
59}
60
61fn cmd_sort(args: Args) {
62 let descending = args.is_present("descending");
63 let mut words = args.get_many("words").unwrap().clone();
65
66 words.sort_by(|a, b| if descending { b.cmp(a) } else { a.cmp(b) });
67
68 println!("sorted:");
69 for s in words {
70 println!("{}", s);
71 }
72}
73
74fn main() -> Result<(), malachi::Error> {
75 let mut cmds = Handlers(vec![]);
76 cmds.add(
77 ".sort [
78 <descending?: nocase(), `-desc`, `-descending`, `-reverse`>
79 <words+>
80]",
81 cmd_sort,
82 )?
83 .add(
84 ".join [
85 <separator?: nocase(), starts(`sep=`, `separator=`)>
86 <words+>
87]",
88 cmd_join,
89 )?;
90
91 println!(
92 "Available commands:
93.sort [-desc] <words>
94 Sorts the given input lexicographically.
95 examples:
96 .sort foo banana wow
97 .sort -desc house tree hi sup
98
99.join [sep=?] <words>
100 Join the given words with the separator given. The default separator is `-`.
101 examples:
102 .join sep=_ snake case
103 .join kebab case
104 .join sep=:: std io stdin"
105 );
106
107 let stdin = io::stdin();
108 let stdin = stdin.lock();
109 print!("> ");
110 io::stdout().flush().unwrap();
111
112 for msg in stdin.lines().filter_map(Result::ok) {
113 cmds.execute(&msg);
114 print!("> ");
115 io::stdout().flush().unwrap();
116 }
117
118 Ok(())
119}