Skip to content
This repository has been archived by the owner on Jan 1, 2022. It is now read-only.

Allow positional arguments from ArgGroup take value separately #145

Open
epage opened this issue Dec 6, 2021 · 5 comments
Open

Allow positional arguments from ArgGroup take value separately #145

epage opened this issue Dec 6, 2021 · 5 comments

Comments

@epage
Copy link
Owner

epage commented Dec 6, 2021

Issue by EverlastingBugstopper
Wednesday Mar 25, 2020 at 17:37 GMT
Originally opened as clap-rs/clap#1761


What are you trying to do?

I'm trying to create positional command line arguments that are exclusive, you can either set one or the other. I'd like to be able to use clap_derive with this so that they are boiled down to a single expiration: std::time::Duration field in an opt struct.

set expiration to 60 seconds

$ app set key value EX 60

set expiration to 6000 milliseconds

$ app set key value PX 6000

What have you tried already?

I haven't been sure what to try or if this is even supported :)

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by pksunkara
Wednesday Mar 25, 2020 at 21:10 GMT


You can use conflicts function.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by CreepySkeleton
Thursday Mar 26, 2020 at 07:48 GMT


I'm under impression that conflicts is not what he was asking about.

This is pretty interesting question. What he's asking for (or so I get it) is:

  • Allow one of the given set of options: PX, EX. Only one of them can be present at a time.

    These two conditions can be implemented via ArgGroup.

  • Each of them takes value. This cannot be implemented via ArgGroup.

    use clap::{App, ArgGroup, Arg};
    
    fn main() {
        let m = App::new("app")
            .arg(Arg::with_name("PX").takes_value(true))
            .arg(Arg::with_name("EX").takes_value(true))
            .group(ArgGroup::with_name("expiration").args(&["PX", "EX"]))
            .get_matches();
    
        println!("{:?}", m.value_of("EX"));
    }
    $ cargo run -- EX 666
       Compiling probe v0.2.0 (D:\workspace\probe)
        Finished dev [unoptimized + debuginfo] target(s) in 10.46s
         Running `target\debug\probe.exe EX 666`
    error: The argument '<EX>' cannot be used with one or more of the other specified arguments
    
    USAGE:
        probe.exe <PX|EX>
    
    For more information try --help
    error: process didn't exit successfully: `target\debug\probe.exe EX 666` (exit code: 1)
    

    This could be implemented if EX and PX were non-positional options:

    use clap::{App, ArgGroup, Arg};
    
    fn main() {
        let m = App::new("app")
            .arg(Arg::with_name("PX").takes_value(true).long("PX"))
            .arg(Arg::with_name("EX").takes_value(true).long("EX"))
            .group(ArgGroup::with_name("expiration").args(&["PX", "EX"]))
            .get_matches();
    
        println!("{:?}", m.value_of("EX"));
    }
    $ cargo run -- --EX 600
        Finished dev [unoptimized + debuginfo] target(s) in 0.10s
         Running `target\debug\probe.exe --EX 600`
    Some("600")
    

But non-positional options must start with -.

I'll take liberty to rename this issue, transforming it into feature request.

Until the, @EverlastingBugstopper , you can make use of subcommands:

use clap::{App, Arg, SubCommand};

fn main() {
    let m = App::new("app")
        .subcommand(SubCommand::with_name("PX")
          .arg(Arg::with_name("value").takes_value(true).required(true)))
        .subcommand(SubCommand::with_name("EX")
          .arg(Arg::with_name("value").takes_value(true).required(true)))
        .get_matches();

    println!("{:#?}", m);
}
$ cargo run -- EX 600
   Compiling probe v0.2.0 (D:\workspace\probe)
    Finished dev [unoptimized + debuginfo] target(s) in 1.77s
     Running `target\debug\probe.exe EX 600`
ArgMatches {
    args: {},
    subcommand: Some(
        SubCommand {
            name: "EX",
            matches: ArgMatches {
                args: {
                    "value": MatchedArg {
                        occurs: 1,
                        indices: [
                            1,
                        ],
                        vals: [
                            "600",
                        ],
                    },
                },
                subcommand: None,
                usage: Some(
                    "USAGE:\n    probe.exe EX <value>",
                ),
            },
        },
    ),
    usage: Some(
        "USAGE:\n    probe.exe [SUBCOMMAND]",
    ),
}

The only thing is that the error message might not appear what you want:

$ cargo run -- --help
    Finished dev [unoptimized + debuginfo] target(s) in 0.06s
     Running `target\debug\probe.exe --help`
app

USAGE:
    probe.exe [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    EX
    PX
    help    Prints this message or the help of the given subcommand(s)

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by EverlastingBugstopper
Thursday Mar 26, 2020 at 15:06 GMT


Hey @CreepySkeleton - thanks for the thoughtful response!

When y'all implement new features like this is it automatically provided in clap_derive or does that require extra work as well? My mental model of how clap_derive actually works is a bit shaky, it seems like most things are supported but the patterns aren't always obvious to me (how would I go about creating an ArgGroup in clap_derive?

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by CreepySkeleton
Thursday Mar 26, 2020 at 17:06 GMT


(how would I go about creating an ArgGroup in clap_derive?

Example

When y'all implement new features like this is it automatically provided in clap_derive or does that require extra work as well?

Most things are immediately available through #[clap(method = value)] attributes. Some things, like subcommands, require dedicated features.

I am inclined to remind you that clap_derive is still in alpha stage and API may change. You can play with it, but expect sudden breakages. For production, use structopt.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by EverlastingBugstopper
Thursday Mar 26, 2020 at 18:37 GMT


Awesome! Yeah - this is something I'm working on the side, not released or intended to be released soon so it's ok that it's still in alpha. Thanks for the help :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant