Add support for automatic negation flags
Add a way to automatically generate flags that override (or negate) other flags. This can be done manually already, but doing so for an entire CLI can be tedious, painful, and error prone. Manually doing so will also pollute the --help output.
This proposal offers a way to automatically have these negation flags generated on a case by case basis, or across all flags in the command. This proposal also offers a way to have these negation flags listed in the --help message or hidden.
Design
A negation flag would simply take the long version of the regular flag and pre-pend no; for exmaple --follow would get a --no-follow. If a flag only specifies a short version, the no would be prepended to the short such as -L gets --no-L.
When parsing occurs, if a negation flag is found, and the negated argument was used, it functions exactly like a override that is already supported.
Functionally the following two examples are equivilant:
app.arg(Arg::with_name("regular")
.long("follow-links")
.help("follows symlinks")
.overrides_with("override"))
.arg(Arg::with_name("override)
.long("no-follow-links")
.help("does not follow symlinks"))New proposal:
app.arg(Arg::with_name("regular")
.long("follow-links")
.help("follows symlinks")
.overridable(true))Concerns
There are two primary concerns with this approach.
Flags that already contian "no"
A flag which already starts with no such as --no-ignore would end up getting a double no in the form of --no-no-ignore. This actually makes sense and is consistent, but looks strange at first glance. An alternative would be to check if a flag starts with no and simply remove the no, i.e. --no-ignore becomes --ignore but this has the downside of additional processing at runtime, becomes slightly more confusing, and has a higher chance of a conflict.
Conflicting names
If a user has selected to auto-generate a negation flag, and the negating flag long conflicts with a flag already in use, a panic! will occur. Example, --ignore and --no-ignore is already defined elsewhere, and the user has selected to automaticlly generate negation flags, this will cause --ignore to generate a --no-ignore flag which already exists causing a panic!. The fix is to either not use a sweeping setting that applies ot all flags indescriminantly, or to change/remove the already defined --no-ignore flag.
Progress
- Add
AppSettings::GenerateNegationFlagswhich does the above, but automatically for all flags.- docs
- tests
- Add
AppSettings:GenerateHiddenNegationFlagswhich hides all these negation flags.- docs
- tests
See the discussion in burntsushi/ripgrep#196
Relates to #748
Edit: Removed Arg::overridable(bool) because this can already be done manually by making another flag.
Source: clap-rs/clap