-
-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Derive Subcommands #15
Comments
I have thought about adding support for deriving the trait for enums, which would allow a limited form of subcommand parsing. The reason it hasn't been done is because there are some ambiguities to resolve between subcommands and positional arguments. Consider a naive example: #[derive(Debug, OnlyArgs)]
struct Args {
/// Some subcommand.
cmd: SubCommand,
/// Put everything else into a vector.
comment: Vec<String>,
}
#[derive(Debug, OnlyArgs)]
enum SubCommand {
/// Addition.
Add(i32, i32),
/// Subtraction.
Sub(i32, i32),
} Passing "unknown" or "non-argument" strings to the CLI should push the strings to the $ ./cli this is a comment add 2 2
Args {
cmd: SubCommand::Add(2, 2),
comment: ["this", "is", "a", "comment"],
}
$ ./cli add 1 3 this is also a comment
Args {
cmd: SubCommand::Add(1, 3),
comment: ["this", "is", "also", "a", "comment"],
}
$ ./cli this will add the numbers add 2 2
Error: `add` expects `(i32, i32)` Using a hand-written parser doesn't have this problem because the parsing rules are explicitly encoded in the [hand-written] trait implementation. The author decides how to resolve the ambiguity, possibly with a fallback mechanism to push unparseable strings into the I don't think there is a good way to provide this kind of CLI with the macro because the "best" ambiguity resolution depends on what the application author wants. The most conservative solution is that the macro should just disallow ambiguous command lines by construction. For instance, declaring an enum and a I also have not thought about how to handle recursive types or structs with more than one enum field (which could themselves have ambiguous variant names between them). And so forth. In short, it needs a good design to put this feature into the derive macro. |
Yea I've had a think about how to solve the issue too. FWIW Clap compiles fine, but complains at runtime about an unexpected argument: use clap::Parser;
#[derive(clap::Parser, Debug, Clone)]
#[command(name = "test_cmd")]
pub struct Args {
#[command(subcommand)]
pub cmd: SubCommand,
pub comment: Vec<String>,
}
#[derive(Clone, Debug, clap::Subcommand)]
#[command(about = "A subcommand")]
pub enum SubCommand {
Add { opa: i32, opb: i32 },
Sub { opa: i32, opb: i32 },
}
fn main() -> anyhow::Result<()> {
let args = Args::parse();
let result = match args.cmd {
SubCommand::Add { opa, opb } => opa + opb,
SubCommand::Sub { opa, opb } => opa - opb,
};
println!("result: {result}");
println!("comment: {}", args.comment.join(", "));
Ok(())
}
|
There was a recent blog post about difficulties with subcommands in clap, which is relevant to this issue: https://gribnau.dev/posts/puzzle-sharing-declarative-args-between-top-level-and-subcommand/ |
Is there a plan to add subcommands to the derive macro?
The text was updated successfully, but these errors were encountered: