| use std::io::Write; |
| |
| use clap::Command; |
| |
| fn main() -> Result<(), String> { |
| loop { |
| let line = readline()?; |
| let line = line.trim(); |
| if line.is_empty() { |
| continue; |
| } |
| |
| match respond(line) { |
| Ok(quit) => { |
| if quit { |
| break; |
| } |
| } |
| Err(err) => { |
| write!(std::io::stdout(), "{err}").map_err(|e| e.to_string())?; |
| std::io::stdout().flush().map_err(|e| e.to_string())?; |
| } |
| } |
| } |
| |
| Ok(()) |
| } |
| |
| fn respond(line: &str) -> Result<bool, String> { |
| let args = shlex::split(line).ok_or("error: Invalid quoting")?; |
| let matches = cli() |
| .try_get_matches_from(args) |
| .map_err(|e| e.to_string())?; |
| match matches.subcommand() { |
| Some(("ping", _matches)) => { |
| write!(std::io::stdout(), "Pong").map_err(|e| e.to_string())?; |
| std::io::stdout().flush().map_err(|e| e.to_string())?; |
| } |
| Some(("quit", _matches)) => { |
| write!(std::io::stdout(), "Exiting ...").map_err(|e| e.to_string())?; |
| std::io::stdout().flush().map_err(|e| e.to_string())?; |
| return Ok(true); |
| } |
| Some((name, _matches)) => unimplemented!("{name}"), |
| None => unreachable!("subcommand required"), |
| } |
| |
| Ok(false) |
| } |
| |
| fn cli() -> Command { |
| // strip out usage |
| const PARSER_TEMPLATE: &str = "\ |
| {all-args} |
| "; |
| // strip out name/version |
| const APPLET_TEMPLATE: &str = "\ |
| {about-with-newline}\n\ |
| {usage-heading}\n {usage}\n\ |
| \n\ |
| {all-args}{after-help}\ |
| "; |
| |
| Command::new("repl") |
| .multicall(true) |
| .arg_required_else_help(true) |
| .subcommand_required(true) |
| .subcommand_value_name("APPLET") |
| .subcommand_help_heading("APPLETS") |
| .help_template(PARSER_TEMPLATE) |
| .subcommand( |
| Command::new("ping") |
| .about("Get a response") |
| .help_template(APPLET_TEMPLATE), |
| ) |
| .subcommand( |
| Command::new("quit") |
| .alias("exit") |
| .about("Quit the REPL") |
| .help_template(APPLET_TEMPLATE), |
| ) |
| } |
| |
| fn readline() -> Result<String, String> { |
| write!(std::io::stdout(), "$ ").map_err(|e| e.to_string())?; |
| std::io::stdout().flush().map_err(|e| e.to_string())?; |
| let mut buffer = String::new(); |
| std::io::stdin() |
| .read_line(&mut buffer) |
| .map_err(|e| e.to_string())?; |
| Ok(buffer) |
| } |