repl_derive/
repl-derive.rs

1use std::io::Write;
2
3use clap::{Parser, Subcommand};
4
5fn 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
29fn respond(line: &str) -> Result<bool, String> {
30    let args = shlex::split(line).ok_or("error: Invalid quoting")?;
31    let cli = Cli::try_parse_from(args).map_err(|e| e.to_string())?;
32    match cli.command {
33        Commands::Ping => {
34            write!(std::io::stdout(), "Pong").map_err(|e| e.to_string())?;
35            std::io::stdout().flush().map_err(|e| e.to_string())?;
36        }
37        Commands::Exit => {
38            write!(std::io::stdout(), "Exiting ...").map_err(|e| e.to_string())?;
39            std::io::stdout().flush().map_err(|e| e.to_string())?;
40            return Ok(true);
41        }
42    }
43    Ok(false)
44}
45
46#[derive(Debug, Parser)]
47#[command(multicall = true)]
48struct Cli {
49    #[command(subcommand)]
50    command: Commands,
51}
52
53#[derive(Debug, Subcommand)]
54enum Commands {
55    Ping,
56    Exit,
57}
58
59fn readline() -> Result<String, String> {
60    write!(std::io::stdout(), "$ ").map_err(|e| e.to_string())?;
61    std::io::stdout().flush().map_err(|e| e.to_string())?;
62    let mut buffer = String::new();
63    std::io::stdin()
64        .read_line(&mut buffer)
65        .map_err(|e| e.to_string())?;
66    Ok(buffer)
67}