clap
clap copied to clipboard
Support multiple arguments writing to the same destination
Please complete the following tasks
- [X] I have searched the discussions
- [X] I have searched the existing issues
Clap Version
3.0.0-rc.0
Describe your use case
Related issues
- #1820
- #815
Describe the solution you'd like
In Python's argparse
, you can assign the dest
(for us, name
) for an argument in the Namespace
(for us, ArgMatches
). This gives a lot of power. One example is #1820 with migrating flags. The thing I used this most frequently for was negations (#815).
The code would look something like
parser.add_argument("--flag", dest="flag", action="store_true")
parser.add_argument("--no-flag", dest="flag", action="store_false")
... some line about setting the default
This makes it easy to define and handle and gives good semantics (last writer wins)
For now, I'm doing stuff like
fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
match (yes, no) {
(true, false) => Some(true),
(false, true) => Some(false),
(false, false) => None,
(_, _) => unreachable!("StructOpt should make this impossible"),
}
}
https://github.com/epage/git-stack/blob/main/src/bin/git-stack/args.rs#L105
and haven't played with overrides_with
to see what a last-writer-wins would look like with clap.
Alternatives, if applicable
No response
Additional Context
See #1820 which has several concerns over doing this. I especially expect problems with
- Interaction with
global(true)
- Validation rules (they have to be aware of and operate on the dest)
- Derives reading the right dest
- Derives dealing with multiple "arguments" pointing to the same dest
See #3119 for more use cases
Is there a good workaround for this? I have a lot of options that are negatable (mostly using no-
prefixed options), and it would be really nice to avoid having duplicate boolean fields for all of them that I have to check both of.
@tmccombs would a workaround like this work for your use case?
Maybe. In my case I only want these options for a few of the options, and in some cases I the man option starts with --no-
and the negating option doesn't have the prefix (or in other words, the option without the --no
prefix is the default).
I'm also not really sure what the best way to do that when using the derive api would be.
@tmccombs if your interest is in negation flags, be sure to watch the more specific #815. In it, I do bring up a more unusual solution using ArgAction so there is room for solutions outside of this issue.
Some other use cases for this:
- having an option that is a shortcut for passing a specific value to another option. For example
-1
as an alias for--max-results=1
- Allowing an argument to be passed either as a positional argument or an option
- Options that take the same value, but with different meanings. for example
--include
and--exclude
might feed into a single list of filters, where relative order matters, and the difference is just which variant of an enum is used (or maybe one type is prefixed with some delimiter like "!").
and haven't played with overrides_with to see what a last-writer-wins would look like with clap.
https://docs.rs/bpaf/0.5.6/bpaf/batteries/fn.toggle_flag.html - looks like this in bpaf
, values can be the same or different. As long as types align you just compose them as alternatives, consume all and get the last value construct!([a, b, c, d]).many().map(|xs| xs.into_iter().last())
.