clap-rs / clap

A full featured, fast Command Line Argument Parser for Rust
docs.rs/clap
Apache License 2.0
14.13k stars 1.03k forks source link

Allow global args in top-level multicall #4521

Open jaskij opened 1 year ago

jaskij commented 1 year ago

Please complete the following tasks

Clap Version

4.0.27

Describe your use case

When writing a multicall program, I have some options that I'd like to be available to all commands. In addition, to reduce boilerplate, I would like them to be in the top-level struct.

A prime example of this would be log level, which is set once, just after parsing the commandline, before entering a specific subcommand.

Describe the solution you'd like

This looks good enough - as is, this is rejected by debug asserts.

#[derive(Debug, clap::Parser)]
#[command(multicall(true))]
struct Cli {
    #[command(subcommand)]
    command: Command,

    #[arg(global = true)]
    log_level: LogLevel,
}

Alternatives, if applicable

A workaround would be to add the log level enum as an option on all subcommands - doable, but seems to require some amount of repetitive code, which is always an issue when it comes to later changes.

The amount of repetition could perhaps be eased by using a declarative macro, but those are somewhat annoying to write and not everyone is comfortable with them.

Additional Context

No response

epage commented 1 year ago

When I prevented arguments on the multicall command, I was trying to balance

It would be nice to support global arguments but any solution should maintain the above balance unless we find a reason to re-evaluate our priorities for this feature.

paulyoung commented 1 year ago

I’m trying to understand if this is the same as my use case or not, and if my use case is supported even if the one in this issue isn’t.

I have an existing program set up with the derive API that takes 2 positional arguments, e.g. foo a b

I’d like to also be able to call this as bar a b and behave differently based on the executable name.

Is this possible when using multicall(true)?

I was only able to get trivial examples like hostname to work but couldn’t figure out how to port what I already have.

It seems like a reasonable thing to support so perhaps I’m overlooking how to do it.

epage commented 1 year ago

Yes, this is supported. Could you open a Discussion with more details to figure out what is going on? This issue is specifically for Arg::global which I'm assuming is unrelated.

paulyoung commented 1 year ago

I created https://github.com/clap-rs/clap/discussions/4541. Sorry for the confusion.