119625d8cSopenharmony_ciuse std::io::Write;
219625d8cSopenharmony_ci
319625d8cSopenharmony_ciuse clap::Command;
419625d8cSopenharmony_ci
519625d8cSopenharmony_cifn main() -> Result<(), String> {
619625d8cSopenharmony_ci    loop {
719625d8cSopenharmony_ci        let line = readline()?;
819625d8cSopenharmony_ci        let line = line.trim();
919625d8cSopenharmony_ci        if line.is_empty() {
1019625d8cSopenharmony_ci            continue;
1119625d8cSopenharmony_ci        }
1219625d8cSopenharmony_ci
1319625d8cSopenharmony_ci        match respond(line) {
1419625d8cSopenharmony_ci            Ok(quit) => {
1519625d8cSopenharmony_ci                if quit {
1619625d8cSopenharmony_ci                    break;
1719625d8cSopenharmony_ci                }
1819625d8cSopenharmony_ci            }
1919625d8cSopenharmony_ci            Err(err) => {
2019625d8cSopenharmony_ci                write!(std::io::stdout(), "{err}").map_err(|e| e.to_string())?;
2119625d8cSopenharmony_ci                std::io::stdout().flush().map_err(|e| e.to_string())?;
2219625d8cSopenharmony_ci            }
2319625d8cSopenharmony_ci        }
2419625d8cSopenharmony_ci    }
2519625d8cSopenharmony_ci
2619625d8cSopenharmony_ci    Ok(())
2719625d8cSopenharmony_ci}
2819625d8cSopenharmony_ci
2919625d8cSopenharmony_cifn respond(line: &str) -> Result<bool, String> {
3019625d8cSopenharmony_ci    let args = shlex::split(line).ok_or("error: Invalid quoting")?;
3119625d8cSopenharmony_ci    let matches = cli()
3219625d8cSopenharmony_ci        .try_get_matches_from(args)
3319625d8cSopenharmony_ci        .map_err(|e| e.to_string())?;
3419625d8cSopenharmony_ci    match matches.subcommand() {
3519625d8cSopenharmony_ci        Some(("ping", _matches)) => {
3619625d8cSopenharmony_ci            write!(std::io::stdout(), "Pong").map_err(|e| e.to_string())?;
3719625d8cSopenharmony_ci            std::io::stdout().flush().map_err(|e| e.to_string())?;
3819625d8cSopenharmony_ci        }
3919625d8cSopenharmony_ci        Some(("quit", _matches)) => {
4019625d8cSopenharmony_ci            write!(std::io::stdout(), "Exiting ...").map_err(|e| e.to_string())?;
4119625d8cSopenharmony_ci            std::io::stdout().flush().map_err(|e| e.to_string())?;
4219625d8cSopenharmony_ci            return Ok(true);
4319625d8cSopenharmony_ci        }
4419625d8cSopenharmony_ci        Some((name, _matches)) => unimplemented!("{}", name),
4519625d8cSopenharmony_ci        None => unreachable!("subcommand required"),
4619625d8cSopenharmony_ci    }
4719625d8cSopenharmony_ci
4819625d8cSopenharmony_ci    Ok(false)
4919625d8cSopenharmony_ci}
5019625d8cSopenharmony_ci
5119625d8cSopenharmony_cifn cli() -> Command {
5219625d8cSopenharmony_ci    // strip out usage
5319625d8cSopenharmony_ci    const PARSER_TEMPLATE: &str = "\
5419625d8cSopenharmony_ci        {all-args}
5519625d8cSopenharmony_ci    ";
5619625d8cSopenharmony_ci    // strip out name/version
5719625d8cSopenharmony_ci    const APPLET_TEMPLATE: &str = "\
5819625d8cSopenharmony_ci        {about-with-newline}\n\
5919625d8cSopenharmony_ci        {usage-heading}\n    {usage}\n\
6019625d8cSopenharmony_ci        \n\
6119625d8cSopenharmony_ci        {all-args}{after-help}\
6219625d8cSopenharmony_ci    ";
6319625d8cSopenharmony_ci
6419625d8cSopenharmony_ci    Command::new("repl")
6519625d8cSopenharmony_ci        .multicall(true)
6619625d8cSopenharmony_ci        .arg_required_else_help(true)
6719625d8cSopenharmony_ci        .subcommand_required(true)
6819625d8cSopenharmony_ci        .subcommand_value_name("APPLET")
6919625d8cSopenharmony_ci        .subcommand_help_heading("APPLETS")
7019625d8cSopenharmony_ci        .help_template(PARSER_TEMPLATE)
7119625d8cSopenharmony_ci        .subcommand(
7219625d8cSopenharmony_ci            Command::new("ping")
7319625d8cSopenharmony_ci                .about("Get a response")
7419625d8cSopenharmony_ci                .help_template(APPLET_TEMPLATE),
7519625d8cSopenharmony_ci        )
7619625d8cSopenharmony_ci        .subcommand(
7719625d8cSopenharmony_ci            Command::new("quit")
7819625d8cSopenharmony_ci                .alias("exit")
7919625d8cSopenharmony_ci                .about("Quit the REPL")
8019625d8cSopenharmony_ci                .help_template(APPLET_TEMPLATE),
8119625d8cSopenharmony_ci        )
8219625d8cSopenharmony_ci}
8319625d8cSopenharmony_ci
8419625d8cSopenharmony_cifn readline() -> Result<String, String> {
8519625d8cSopenharmony_ci    write!(std::io::stdout(), "$ ").map_err(|e| e.to_string())?;
8619625d8cSopenharmony_ci    std::io::stdout().flush().map_err(|e| e.to_string())?;
8719625d8cSopenharmony_ci    let mut buffer = String::new();
8819625d8cSopenharmony_ci    std::io::stdin()
8919625d8cSopenharmony_ci        .read_line(&mut buffer)
9019625d8cSopenharmony_ci        .map_err(|e| e.to_string())?;
9119625d8cSopenharmony_ci    Ok(buffer)
9219625d8cSopenharmony_ci}
93