• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::io::Write;
2 
3 use clap::Command;
4 
main() -> Result<(), String>5 fn main() -> Result<(), String> {
6     loop {
7         let line = readline()?;
8         let line = line.trim();
9         if line.is_empty() {
10             continue;
11         }
12 
13         match respond(line) {
14             Ok(quit) => {
15                 if quit {
16                     break;
17                 }
18             }
19             Err(err) => {
20                 write!(std::io::stdout(), "{}", err).map_err(|e| e.to_string())?;
21                 std::io::stdout().flush().map_err(|e| e.to_string())?;
22             }
23         }
24     }
25 
26     Ok(())
27 }
28 
respond(line: &str) -> Result<bool, String>29 fn respond(line: &str) -> Result<bool, String> {
30     let args = shlex::split(line).ok_or("error: Invalid quoting")?;
31     let matches = cli()
32         .try_get_matches_from(args)
33         .map_err(|e| e.to_string())?;
34     match matches.subcommand() {
35         Some(("ping", _matches)) => {
36             write!(std::io::stdout(), "Pong").map_err(|e| e.to_string())?;
37             std::io::stdout().flush().map_err(|e| e.to_string())?;
38         }
39         Some(("quit", _matches)) => {
40             write!(std::io::stdout(), "Exiting ...").map_err(|e| e.to_string())?;
41             std::io::stdout().flush().map_err(|e| e.to_string())?;
42             return Ok(true);
43         }
44         Some((name, _matches)) => unimplemented!("{}", name),
45         None => unreachable!("subcommand required"),
46     }
47 
48     Ok(false)
49 }
50 
cli() -> Command51 fn cli() -> Command {
52     // strip out usage
53     const PARSER_TEMPLATE: &str = "\
54         {all-args}
55     ";
56     // strip out name/version
57     const APPLET_TEMPLATE: &str = "\
58         {about-with-newline}\n\
59         {usage-heading}\n    {usage}\n\
60         \n\
61         {all-args}{after-help}\
62     ";
63 
64     Command::new("repl")
65         .multicall(true)
66         .arg_required_else_help(true)
67         .subcommand_required(true)
68         .subcommand_value_name("APPLET")
69         .subcommand_help_heading("APPLETS")
70         .help_template(PARSER_TEMPLATE)
71         .subcommand(
72             Command::new("ping")
73                 .about("Get a response")
74                 .help_template(APPLET_TEMPLATE),
75         )
76         .subcommand(
77             Command::new("quit")
78                 .alias("exit")
79                 .about("Quit the REPL")
80                 .help_template(APPLET_TEMPLATE),
81         )
82 }
83 
readline() -> Result<String, String>84 fn readline() -> Result<String, String> {
85     write!(std::io::stdout(), "$ ").map_err(|e| e.to_string())?;
86     std::io::stdout().flush().map_err(|e| e.to_string())?;
87     let mut buffer = String::new();
88     std::io::stdin()
89         .read_line(&mut buffer)
90         .map_err(|e| e.to_string())?;
91     Ok(buffer)
92 }
93