-
Notifications
You must be signed in to change notification settings - Fork 152
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
Using AppSettings::SubcommandsNegateReqs #124
Comments
I didn't know this command. But what behavior do you expect, because |
I understand that My thinking is, since I have a Now, what I don't know is if this is even possible. I don't know what we can and cannot do with |
@kbknapp what do you think about that? |
I run into this issue as well. Here's my workaround: define an almost identical struct but make the fields optional, and use it to access match result. use structopt::StructOpt;
#[derive(Debug, StructOpt)]
struct OptionsAndSubcommand {
#[structopt(long)]
arg: i32,
#[structopt(subcommand)]
cmd: Option<Cmd>,
}
#[derive(Debug, StructOpt)]
enum Cmd {
Get {
name: String,
},
}
#[derive(Debug, StructOpt)]
struct OptionalOptions {
// Proper support should allow something like:
// #[structopt(required_unless_subcommand)]
arg: Option<i32>,
#[structopt(subcommand)]
cmd: Option<Cmd>,
}
fn main() {
let matches = OptionsAndSubcommand::clap()
.setting(structopt::clap::AppSettings::SubcommandsNegateReqs)
.get_matches();
println!("Options: {:?}", OptionalOptions::from_clap(&matches));
} If you don't expect any args when there is a subcommand, you can do this: use structopt::StructOpt;
#[derive(Debug, StructOpt)]
struct OptionsAndSubcommand {
#[structopt(long)]
arg: i32,
#[structopt(subcommand)]
cmd: Option<Cmd>,
}
#[derive(Debug, StructOpt)]
enum Cmd {
Get {
name: String,
},
}
fn main() {
let matches = OptionsAndSubcommand::clap()
.setting(structopt::clap::AppSettings::SubcommandsNegateReqs)
.setting(structopt::clap::AppSettings::ArgsNegateSubcommands)
.get_matches();
if matches.subcommand_name().is_none() {
println!("Options: {:?}", OptionsAndSubcommand::from_clap(&matches));
} else {
println!("Subcommand: {:?}", Cmd::from_clap(&matches));
}
} |
First I tried #[structopt(required=true)]
arg: Option<i32>, but structopt complained I was contradicting myself. So I was somewhat surprised to discover that this seems to work: #[structopt(required_unless="cmd")]
arg: Option<i32>, Not ideal, since it requires duplicating the name of the subcommand (or names, using Could structopt ease up on that "required is meaningless for Option" error when SubcommandsNegateReqs is on? Perhaps not where that error is raised currently, it doesn't look like that has any way to see what the app settings are. Maybe some kind of Or could that validation be done later, when it's known what the app settings are? (maybe even at runtime, if necessary) |
We can remove the error and do a warning, with some mechanism to remove the warning. |
There's no way to issue warnings on stable. |
I'm not sure that's the way I'd want to go. Ideally, what I had in mind was: enum Opt {
#[structopt(default_command)]
MainCommandWithLotsOfArgs {
...
},
Other,
Subcommands,
Here { some_arg: i32 },
} The reason for this being just that the main command may involve lots of args that you don't feel like marking separately. At this point, of course, I'm just spitballing about ergonomics. I'm coming at this from the standpoint of a consumer, not a library author. |
Actually, this design looks neat and unambigous! 👌 If @TeXitoi doesn't mind, would you like to take a stab at implementation? I can mentor it and give you a hand.
It is always about ergonomics to some extend. Does stuff feel intuitive enough (define intuitive, aha), does it meld into other parts of the library, etc. The more people come and propose ideas, the better the chances that something worthy will eventually be found. I personally thing your proposal is great. |
@CreepySkeleton I'd be cool with that. |
@TeXitoi What do you think about @archer884 design above? |
Not found of It must work
|
@TeXitoi, regarding the first bullet point: if the purpose of this is to make it possible not to have common args between all subcommands, how much value lies in making it work within a struct defining common args for subcommands? I could be somewhat biased. As a user of this library (I think practically all of my tools are based on structopt), I don't think I have ever intentionally made use of the common arguments feature. To avoid rewriting the same code from subcommand to subcommand, my preferred strategy has been to define common arguments as a struct and An example: #[derive(Clone, Debug, StructOpt)]
enum SubCommands {
Foo(Foo),
Bar(Bar),
}
#[derive(Clone, Debug, StructOpt)]
struct Foo {
#[structopt(flatten)]
common_args: CommonArgs,
other: String,
args: String,
}
#[derive(Clone, Debug, StructOpt)]
struct Bar {
#[structopt(flatten)]
common_args: CommonArgs,
other: i32,
args: String,
}
#[derive(Clone, Debug, StructOpt)]
struct CommonArgs {
name: String,
date: String,
} |
The goal is to be consistent: you can without this feature, so this feature must not be an exception. |
Guys, I suspect you're speaking past each other here. Regarding the first point, @TeXitoi could you please elaborate? A bit of code example would help immensely! The second: @TeXitoi was talking about enum Opt {
#[structopt(default_command)]
MainCommandWithLotsOfArgs(MainApp),
Other,
Subcommands,
Here { some_arg: i32 },
}
struct MainApp { ... } Super easy to implement, about +10 LOC. |
Oh. I thought that was what I proposed in the first place.
…On Apr 29, 2020, 8:22 AM -0500, CreepySkeleton ***@***.***>, wrote:
Guys, I suspect you're speaking past each other here.
Regarding the first point, @TeXitoi could you please elaborate? A bit of code example would help immensely!
The second: @TeXitoi was talking about
enum Opt {
#[structopt(default_command)]
MainCommandWithLotsOfArgs(MainApp),
Other,
Subcommands,
Here { some_arg: i32 },
}
struct MainApp { ... }
Super easy to implement, about +10 LOC.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
enum Opt {
#[structopt(default_command)]
MainCommandWithLotsOfArgs(MainApp),
Other,
Subcommands,
Here { some_arg: i32 },
}
struct BigOpt {
#[structopt(subcommand)]
cmd: Opt,
#[structopt(long, short)]]
config: String,
} StructOpt on Opt and on BigOpt should work as expected (i.e. config always accessible). |
This is an enhancement, and structopt is now feature frozen. |
I'm sorry if I'm missing something here, but I was unable to find any information on the documentation or in the examples.
I have a use case where my program has a required Arg (for example a input file name). I would like to implement shell completions generation using clap during runtime by passing a
completions
subcommand and the shell to generate the completions for (the same wayrustup
does). For this to happen I need to setAppSettings::SubcommandsNegateReqs
. Using the examples as a guide I did this:But now, when I run
cargo run completions zsh
for example, my program panics atOpt::from_args()
due to aNone
beenunwrap
'd.I've found a workaround this by getting the clap matches via
Opt::clap().get_matches()
and matching against the subcommands (and exiting early if the subcommand was found), but I found this very ugly and was thinking that there must be a clean way to do this usingstructopt
.The text was updated successfully, but these errors were encountered: