Skip to content
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

Add ability to define pairs of flags that set / unset a boolean flag #482

Closed
Emerentius opened this issue Jun 6, 2021 · 5 comments
Closed

Comments

@Emerentius
Copy link

I'd like to have a pair of flags where one of them sets a boolean to true and the other one to false. The two flags should override each other so only the last one counts.
This is pretty much the same behavior as in python for the flags from the click package. This is useful because you can set the default value of the flag to either false or true, change the default at a later point both in the program and in wrappers (or aliases) without taking away the configurability by the end user.

alias foo="bar --use-x"
foo --dont-use-x           # end user still has full control

The way click lets you define these flags would look roughly like this in structopt:

#[derive(structopt)]
struct Command {
    #[structopt(long = "do-x / dont-do-x), default_value = "true"]
    flag: bool,
}

But I have no opinion for how the actual implementation should look like.

This could be implemented via clap's overrides_with. I think that method's functionality isn't already exposed anywhere in structopt?
Alternatively, the two flags could be set to conflict with each other via conflicts_with, but I would prefer the alias-friendly override behavior.

This seems related to #104 and #141, but it differs in that it is for the special case of two opposing flags that result in a boolean. I believe they also want mutually exclusive (conflicting) behavior, where as I'd like overrides.

@TeXitoi
Copy link
Owner

TeXitoi commented Jun 7, 2021

Direct translation from the overrides_with clap example:

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
struct Opt {
    #[structopt(short, long, conflicts_with = "debug")]
    flag: bool,
    #[structopt(short, long)]
    debug: bool,
    #[structopt(short, long, overrides_with = "flag")]
    color: bool,
}

fn main() {
    let opt = Opt::from_args();
    println!("{:?}", opt);
}

But I don't care of the second bool value!

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
struct Opt {
    #[structopt(short, long)]
    verbose: bool,
}

fn main() {
    let clap = Opt::clap().arg(
        structopt::clap::Arg::from_usage("-q, --quiet")
            .overrides_with("verbose")
            .multiple(true),
    );
    let opt = Opt::from_clap(&clap.get_matches());
    println!("{:?}", opt);
}

@Emerentius
Copy link
Author

I see, so conflicts_with and override_with are available in structopt after all. I found no mention of either one in the docs.

Both of these solutions are cumbersome to implement and result in non-obvious code. Imagine repeating this for every flag you have.
To define the default, you'd have to check for both args being false in the first example.
In the second example, switching the default requires swapping which argument is part of the options struct.

I found a related issue in clap's issue tracker: clap-rs/clap/issues/815. It makes a good point that without support by clap, anything you do pollutes the help with flags that appear unrelated on first glance.

@TeXitoi
Copy link
Owner

TeXitoi commented Jun 8, 2021

The doc says that all the clap method can be used as attribute. Structopt is "just" syntactic sugar above clap after all.

And, as you noted, structopt can't really do better without clap support.

@TeXitoi
Copy link
Owner

TeXitoi commented Jun 8, 2021

For default, I propose you write a getter on your struct. Then, to change the default, you just have to change the getter. Lots of person forget that a structopt is a struct, and you can impl on it!

@TeXitoi
Copy link
Owner

TeXitoi commented Aug 30, 2021

Closing this because "will only be in clap v3".

@TeXitoi TeXitoi closed this as completed Aug 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants