interactcli-rs 是一个命令行程序框架,用于解决命令行与交互模式一体化问题,包括命令行交互模式统一、子命令提示等功能。该框架集成了clap和shellwords。
框架中包含了访问www.baidu.com的例子
快速上手过程如下:
-
clone 项目
git clone https://github.com/jiashiwen/interactcli-rs.git cd interactcli-rs
-
命令行模式
cargo run requestsample baidu
-
交互模式
cargo run -- -i interact-rs> requestsample baidu
交互模式下使用"Tab"键,进行命令提示
-
定义命令 cmd 模块用于定义命令以及相关子命令
use clap::Command; pub fn new_requestsample_cmd() -> Command<'static> { clap::Command::new("requestsample") .about("requestsample") .subcommand(get_baidu_cmd()) } pub fn get_baidu_cmd() -> Command<'static> { clap::Command::new("baidu").about("request www.baidu.com") }
new_requestsample_cmd 函数定义了命令 "requestsample",get_baidu_cmd 函数定义了 requestsample 的子命令 baidu
-
注册命令 src/cmd/rootcmd.rs 文件中定义了命令树,可以在此注册定义好的子命令
lazy_static! { static ref CLIAPP: clap::Command<'static> = clap::Command::new("interact-rs") .version("1.0") .author("Shiwen Jia. <[email protected]>") .about("command line sample") .arg_required_else_help(true) .arg( Arg::new("config") .short('c') .long("config") .value_name("FILE") .help("Sets a custom config file") .takes_value(true) ) .arg( Arg::new("daemon") .short('d') .long("daemon") .help("run as daemon") ) .arg( Arg::new("interact") .short('i') .long("interact") .conflicts_with("daemon") .help("run as interact mod") ) .arg( Arg::new("v") .short('v') .multiple_occurrences(true) .takes_value(true) .help("Sets the level of verbosity") ) .subcommand(new_requestsample_cmd()) .subcommand(new_config_cmd()) .subcommand(new_multi_cmd()) .subcommand(new_task_cmd()) .subcommand(new_loop_cmd()) .subcommand( clap::Command::new("test") .about("controls testing features") .version("1.3") .author("Someone E. <[email protected]>") .arg( Arg::new("debug") .short('d') .help("print debug information verbosely") ) ); static ref SUBCMDS: Vec<SubCmd> = subcommands(); } pub fn run_app() { let matches = CLIAPP.clone().get_matches(); if let Some(c) = matches.value_of("config") { println!("config path is:{}", c); set_config_file_path(c.to_string()); } set_config(&get_config_file_path()); cmd_match(&matches); } pub fn run_from(args: Vec<String>) { match clap_Command::try_get_matches_from(CLIAPP.to_owned(), args.clone()) { Ok(matches) => { cmd_match(&matches); } Err(err) => { err.print().expect("Error writing Error"); } }; }
定义好的命令不需其他处理,框架会在系统运行时生成子命令树,用于命令提示的支持
-
命令解析 src/cmd/rootcmd.rs 中的 cmd_match 负责解析命令,可以把解析逻辑写在该函数中
fn cmd_match(matches: &ArgMatches) { if let Some(ref matches) = matches.subcommand_matches("requestsample") { if let Some(_) = matches.subcommand_matches("baidu") { let rt = tokio::runtime::Runtime::new().unwrap(); let async_req = async { let result = req::get_baidu().await; println!("{:?}", result); }; rt.block_on(async_req); }; } }
-
修改交互模式的命令提示 提示符可以在src/interact/cli.rs 中定义
pub fn run() { ... loop { let p = format!("{}> ", "interact-rs"); rl.helper_mut().expect("No helper").colored_prompt = format!("\x1b[1;32m{}\x1b[0m", p); ... } ... }