繁体   English   中英

如何使用 clap 和 derive 创建默认子命令

[英]How to make a default subcommand with clap and derive

如果用户没有提供任何参数并且我找不到任何方法来执行此操作,我将尝试启动一个子命令。

如果没有提供子命令,当我想要执行某些操作而不是传递时,帮助将出现。

基于官方拍手文档

通过将 Subcommand 包装在Option中进行修改,使其成为可选的:

use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[command(propagate_version = true)]
struct Cli {
    #[command(subcommand)]
    command: Option<Commands>,
}

#[derive(Subcommand)]
enum Commands {
    /// Adds files to myapp
    Add { name: Option<String> },
}

fn main() {
    let cli = Cli::parse();

    // You can check for the existence of subcommands, and if found use their
    // matches just as you would the top level cmd
    match &cli.command {
        Some(Commands::Add { name }) => {
            println!("'myapp add' was used, name is: {:?}", name)
        }
        None => {
            println!("Default subcommand");
        }
    }
}

在上面的示例中,如果您需要默认选项/参数,clap 可能会认为您的可能参数可能是一个子命令。

如果 arguments 在基于其他地方的子命令后单独解析,则可能会发生这种情况。

默认情况下也会发生这种情况,因为默认命令不会在映射到进一步 arguments 的子命令下实现所选变体,因此必须“外部”处理它。

例如。 仅使用Option<SubCommands>可能会导致:

error: unrecognized subcommand 'argument'

为此,您可能需要allow_external_subcommands上面的例子:

#[command(allow_external_subcommands(true))]

导致允许在没有子命令的情况下运行的预期行为:

$ app run file

Run was used, name is: RunArgs { path: "file" }

$ app init

Init was used

$ app file

Default subcommand RunArgs { path: "file" }

但是现在你有另一个问题,当 f.ex. 时你不会得到信息错误。 可能没有足够的 arguments。

你将不得不做一些复杂的事情,比如增加参数:

use regex::Regex;
use std::collections::VecDeque;

// app run [OPTIONS] <file> -> explicit run
// app [OPTIONS] <file>     -> implicit run
// app <file>               -> implicit run
fn is_run_implied() -> bool {
    if std::env::args().count() < 2 {
        return false;
    }

    let test_re = Regex::new(r"^(--bench|--dir|[^\s]+\.wasm)")
        .expect("BUG: Regex error");

    test_re.is_match(&std::env::args().nth(1).unwrap())
}

fn main() {
    let augmented_args = if is_run_implied() {
        let mut augmented_args: VecDeque<String> = std::env::args().collect();
        augmented_args.insert(1, "run".to_owned());
        Args::parse_from(augmented_args)
    } else {
        Args::parse()
    };

考虑到这一点,我本以为非详尽的Option<CommandEnum>只会扫描 CommandEnum 变体,而不会扫描其他任何“可能的”子命令,但可惜不是。 将不得不调查并提出拍手的错误/功能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM