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

Support for using ArgGroup as Enum with derive #192

Open
2 tasks done
epage opened this issue Dec 6, 2021 · 6 comments
Open
2 tasks done

Support for using ArgGroup as Enum with derive #192

epage opened this issue Dec 6, 2021 · 6 comments

Comments

@epage
Copy link
Owner

epage commented Dec 6, 2021

Issue by ModProg
Sunday Jul 25, 2021 at 20:41 GMT
Originally opened as clap-rs/clap#2621


Please complete the following tasks

  • I have searched the discussions
  • I have searched the existing issues

Clap Version

3.0.0-beta.2

Describe your use case

I have multiple filters of witch only one can be set (--running, --exited, --restarting,...).

Describe the solution you'd like

I would like something with this usage:

#[derive(Clap)]
pub struct App{
    #[clap(arggroup)]
    pub state_filter: Option<StateFilter>,
}

#[derive(ArgGroup)]
pub enum StateFilter {
    /// Only running servers are returned
    #[clap(long)]
    Running,
    /// Only exited servers are returned
    #[clap(long)]
    Exited,
    /// Only restarting servers are returned
    #[clap(long)]
    Restarting,
}

Resulting in:

OPTIONS:
    --exited
           Only exited servers are returned
    --restarting
           Only restarting servers are returned
    --running
           Only running servers are returned

Alternatives, if applicable

I could use an arggroup for this currently, but I would still need to check each boolean seperatly and could not just easily (and readable) match it.

Additional Context

No response

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by epage
Monday Jul 26, 2021 at 14:40 GMT


When I was implementing the Args trait, I was thinking of this case. I was assuming we could do

#[derive(Clap)]
pub struct App{
    #[clap(flatten)]
    pub state_filter: Option<StateFilter>,
}

#[derive(Args)]
pub enum StateFilter {
    /// Only running servers are returned
    #[clap(long)]
    Running,
    /// Only exited servers are returned
    #[clap(long)]
    Exited,
    /// Only restarting servers are returned
    #[clap(long)]
    Restarting,
}

(with an attribute on the enum to override the group name)

Though I hadn't considered

  • Option in the caller, I like it!
  • Enum variants as flags, which I also like!

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by Skirmisher
Saturday Oct 30, 2021 at 21:17 GMT


This would be lovely for my use case (an archive utility, where the operation modes are exclusive but otherwise share the same options, similar to tar). I find clap's subcommand system to be a bit heavy-handed for what I need, but I'm lacking another way to concisely describe and match "exactly one of these options" like is described here.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by epage
Sunday Oct 31, 2021 at 00:45 GMT


You can workaround this by manually defining the arg group and adding the arguments to it. While its using structopt instead of clap-derive, the principle and calls are pretty much the same in this code of mine.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by 0x5c
Tuesday Nov 02, 2021 at 04:46 GMT


The problem with argument groups and the struct equivalent is that you can't ask clap what option was specified, all you can do is check each individual option of the group for presence in the arguments. We're back to to arguments not really being parsed into something useful.

With subcommands, clab directly talls you what subcommand was found in the arguments, as either an Enum or as the string ID of the subcommand. In both cases you can actually match on something instead of having an if-else chain or iteration simply to know which one it was

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by MTCoster
Tuesday Nov 02, 2021 at 16:22 GMT


I have a perfect use case for this right now: my app can accept a config file, or (perhaps if the config is very short) a string directly in the command line. For instance:

$ app --config 'foo=bar,baz=bat'
$ app --config-file ../longer-config.txt

The config string is not designed to be parsed by the app; it's passed directly through to the output. I have no desire to parse it.

Ideally, I'd write something like this:

#[derive(Parser)]
struct RootArgs {
    #[clap(flatten)]
    config: ConfigStringOrFile,
}

#[derive(Args)]
enum ConfigStringOrFile {
    #[clap(short = 'c', long = "config")]
    String(String),
    #[clap(short = 'C', long = "config-file")]
    File(PathBuf),
}

fn main() {
    let args = RootArgs::parse();

    let config = match args.config {
        ConfigStringOrFile::String(s) => s,
        ConfigStringOrFile::File(path) => { 
            // Read config from file...
        },
    };

    // ...
}

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by epage
Tuesday Nov 02, 2021 at 16:56 GMT


The problem with argument groups and the struct equivalent is that you can't ask clap what option was specified, all you can do is check each individual option of the group for presence in the arguments. We're back to to arguments not really being parsed into something useful.

Yes, its only a workaround to help keep people from being blocked and is not ideal. We are trying to focus on polishing up clap v3 before before working on new features. Once v3 is out (and maybe a little after as we do high priority work we postponed), we can look into this or mentoring someone who can look into this,

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