Optional flag at top-level conflicts with required top-level subcommands #5353
-
I have a flag ("--about") at the "top level", meaning as a child argument of the program's command. It's a bool so is optional. I don't need it to be required. I also have a subcommand at the same level, which points to an enum of subcommands, whose variants point to other enums (nested subcommands). As a config option, I have "args_conflicts_with_subcommands" set to true. Also, I have "arg_required_else_help" set to false, so I can see the generated error, when I fail to provide a command name. The error and usage makes good sense, and when not providing a subcommand, this message makes good suggestions about what to try:
The above happens when my subcommand is configured to be required (through not configuring it as an Option<T>). Question is: is there a way to have the functionality where:
Here's some code I'm using:
In summary, when I make my top-level commands required ("commands: CliCmds"), I can't use the "--about" top-level flag. But when I make those subcommands optional ("command: Option<CliCmds>"), then I can use the flag, but the helpful error doesn't display (when neither "--about" nor a subcommand is passed). |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
This appears to be a bug in clap. You should be able to do: #!/usr/bin/env nargo
---
[dependencies]
clap = { version = "4", features = ["derive"] }
---
use clap::Parser;
use clap::Subcommand;
#[derive(Parser, Debug)]
#[command(about, version)]
#[command(
arg_required_else_help = false,
args_conflicts_with_subcommands = true,
)]
struct Cli {
/// Print about
#[arg(long, short)]
about: bool,
#[command(subcommand)]
commands: Option<CliCmds>, // or `commands: Option<CliCmds>,` ???
}
#[derive(Subcommand, Debug)]
#[command(subcommand_required = true)]
enum CliCmds {
#[command(subcommand)]
Manage(CliManageCmds),
#[command(subcommand)]
Track(CliTrackCmds),
}
/// Manage expense definitions
#[derive(Subcommand, Debug)]
#[command(arg_required_else_help = false)]
enum CliManageCmds {
/// List existing expense definitions
List,
/// Search for existing expense definitions
Search,
/// Modify an existing expense definition
Modify,
/// Register a new expense definition
Register,
/// Archive an existing expense definition
Archive,
}
/// Track defined expenses
#[derive(Subcommand, Debug)]
#[command(arg_required_else_help = false)]
enum CliTrackCmds {
/// Mark an expense as staged to be paid
Staged,
/// Mark an expense as deferred (until a future pay period)
Deferred,
/// Mark an expense as paid (either fully or partially)
Paid,
}
fn main() {
dbg!(Cli::parse());
} (the key part being that the subcommand is required but wrapped in Generally in clap, conflicts disable required and this should go both ways. We fixed one direction in #3974 but not the other despite this being acknowledged in #3940 (I think I had assumed the other way was already done). This might be disruptive enough of a change that we would have to treat it as a breaking change and wait until clap v5 (with maybe having it implemented under Feel free to create an issue for this. |
Beta Was this translation helpful? Give feedback.
This appears to be a bug in clap. You should be able to do: