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

Support multiple positionals with fixed sizes #5464

Open
2 tasks done
superstator opened this issue Apr 18, 2024 · 1 comment
Open
2 tasks done

Support multiple positionals with fixed sizes #5464

superstator opened this issue Apr 18, 2024 · 1 comment
Labels
A-parsing Area: Parser's logic and needs it changed somehow. C-enhancement Category: Raise on the bar on expectations E-medium Call for participation: Experience needed to fix: Medium / intermediate

Comments

@superstator
Copy link

Please complete the following tasks

Clap Version

4.5.4

Describe your use case

I want to build a CLI in Rust, using clap, which can accept some number of positional arguments with a set number of values each, and a final argument accepting whatever positional values were left over. For example, ./app a b c with a positional argument accepting 2 values, and a positional argument accepting leftovers, would assign a b to the first arg, and c to the second. I'm able to do this with a positional argument that accepts a single value:

        let cmd = Command::new("main")
            .arg(Arg::new("ONE").action(ArgAction::Set).num_args(1))
            .arg(Arg::new("TWO").action(ArgAction::Append));

        let matches = cmd.get_matches_from(&["bin","a","b","c"]);

        assert_eq!(matches.get_many::<String>("ONE").unwrap().collect::<Vec<_>>(), &["a"]);
        assert_eq!(matches.get_many::<String>("TWO").unwrap().collect::<Vec<_>>(), &["b","c"]);

But if I try to have the first arg accept two values like this:

        let cmd = Command::new("main")
            .arg(Arg::new("ONE").action(ArgAction::Set).num_args(2))
            .arg(Arg::new("TWO").action(ArgAction::Append));

        let matches = cmd.get_matches_from(&["bin","a","b","c"]);

        assert_eq!(matches.get_many::<String>("ONE").unwrap().collect::<Vec<_>>(), &["a","b"]);
        assert_eq!(matches.get_many::<String>("TWO").unwrap().collect::<Vec<_>>(), &["c"]);

I get the error Positional argument [TWO]... *must* have required(true) or last(true) set because a prior positional argument ([ONE] [ONE]) has num_args(1..). If I make argument TWO required, I just get a different error, and if I make them both required the last argument is always attached to TWO, making it impossible to accept something like ./app a b or ./app a b c d and still have ONE capture the first two values.

Describe the solution you'd like

Allow for one or more positional arguments that capture a fixed number of items, plus a "final" positional that can capture 0.. items.

Alternatives, if applicable

No response

Additional Context

No response

@superstator superstator added the C-enhancement Category: Raise on the bar on expectations label Apr 18, 2024
@epage epage added A-parsing Area: Parser's logic and needs it changed somehow. E-medium Call for participation: Experience needed to fix: Medium / intermediate labels Apr 18, 2024
@epage
Copy link
Member

epage commented Apr 18, 2024

This was spun out of #5463.

If I dig into it a little would you be open to a PR?

Yes, we are

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-parsing Area: Parser's logic and needs it changed somehow. C-enhancement Category: Raise on the bar on expectations E-medium Call for participation: Experience needed to fix: Medium / intermediate
Projects
None yet
Development

No branches or pull requests

2 participants