4 个版本
0.2.0 | 2024年5月23日 |
---|---|
0.1.2 | 2024年5月22日 |
0.1.1 | 2023年12月3日 |
0.1.0 | 2023年6月22日 |
#2 在 #rustyline
每月 71 次下载
18KB
134 行代码(不含注释)
clap-repl
repl(读取-评估-打印循环)是命令提示用户界面的典型之一。在 repl 中表示命令的最好方法之一是使用空格分隔的参数,这正是终端外壳所做的事情。在 Rust 中解析此类命令的方法是使用 clap
crate。该 crate 使用 clap
和 reedline
以一种只关注您应用逻辑的方式提供此类用户界面。
特性
感谢 clap
和 reedline
,此 crate 处理以下功能:
- 将空格分隔的命令解析到您的数据结构中。
- 每个命令的帮助标志。
- 验证命令是否有效,否则生成有用的错误和建议。
- 命令的自动完成和提示。
示例
use std::path::PathBuf;
use clap::{Parser, ValueEnum};
use clap_repl::ClapEditor;
use reedline::{DefaultPrompt, DefaultPromptSegment, FileBackedHistory, Reedline, Signal};
#[derive(Debug, Parser)]
#[command(name = "")] // This name will show up in clap's error messages, so it is important to set it to "".
enum SampleCommand {
Download {
path: PathBuf,
/// Check the integrity of the downloaded object
///
/// Uses SHA256
#[arg(long)]
check_sha: bool,
},
/// A command to upload things.
Upload,
/// Login into the system.
Login {
/// Optional. You will be prompted if you don't provide it.
#[arg(short, long)]
username: Option<String>,
#[arg(short, long, value_enum, default_value_t = Mode::Secure)]
mode: Mode,
},
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum Mode {
/// Encrypt the password
Secure,
/// Send the password plain
///
/// This paragraph is ignored because there is no long help text for possible values in clap.
Insecure,
}
fn main() {
let mut prompt = DefaultPrompt::default();
prompt.left_prompt = DefaultPromptSegment::Basic("simple-example".to_owned());
let mut rl = ClapEditor::<SampleCommand>::new_with_prompt(Box::new(prompt), |reed| {
// Do custom things with `Reedline` instance here
reed.with_history(Box::new(
FileBackedHistory::with_file(10000, "/tmp/clap-repl-simple-example-history".into())
.unwrap(),
))
});
loop {
// Use `read_command` instead of `readline`.
let Some(command) = rl.read_command() else {
continue;
};
match command {
SampleCommand::Download { path, check_sha } => {
println!("Downloaded {path:?} with checking = {check_sha}");
}
SampleCommand::Upload => {
println!("Uploaded");
}
SampleCommand::Login { username, mode } => {
// You can use another `reedline::Reedline` inside the loop.
let mut rl = Reedline::create();
let username = username
.unwrap_or_else(|| read_line_with_reedline(&mut rl, "What is your username? "));
let password = read_line_with_reedline(&mut rl, "What is your password? ");
println!("Logged in with {username} and {password} in mode {mode:?}");
}
}
}
}
fn read_line_with_reedline(rl: &mut Reedline, prompt: &str) -> String {
let Signal::Success(x) = rl
.read_line(&DefaultPrompt::new(
DefaultPromptSegment::Basic(prompt.to_owned()),
DefaultPromptSegment::Empty,
))
.unwrap()
else {
panic!();
};
x
}
依赖项
~7–17MB
~234K SLoC