Skip to content

Commit

Permalink
fix(parser): Allow one-off self-overrides
Browse files Browse the repository at this point in the history
bat needed this.

See also clap-rs#4261
  • Loading branch information
epage committed Sep 28, 2022
1 parent 2d78749 commit 3683e2c
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 11 deletions.
5 changes: 0 additions & 5 deletions src/builder/debug_asserts.rs
Expand Up @@ -686,11 +686,6 @@ fn assert_arg(arg: &Arg) {
"Argument '{}' cannot conflict with itself",
arg.get_id(),
);
assert!(
!arg.overrides.iter().any(|x| *x == arg.id),
"Argument '{}' cannot override itself, its the default",
arg.get_id(),
);

assert_eq!(
arg.get_action().takes_values(),
Expand Down
12 changes: 9 additions & 3 deletions src/parser/parser.rs
Expand Up @@ -1180,7 +1180,9 @@ impl<'cmd> Parser<'cmd> {
self.cur_idx.set(self.cur_idx.get() + 1);
debug!("Parser::react: cur_idx:={}", self.cur_idx.get());
}
if matcher.remove(&arg.id) && !self.cmd.is_args_override_self() {
if matcher.remove(&arg.id)
&& !(self.cmd.is_args_override_self() || arg.overrides.contains(arg.get_id()))
{
return Err(ClapError::argument_conflict(
self.cmd,
arg.to_string(),
Expand Down Expand Up @@ -1221,7 +1223,9 @@ impl<'cmd> Parser<'cmd> {
raw_vals
};

if matcher.remove(&arg.id) && !self.cmd.is_args_override_self() {
if matcher.remove(&arg.id)
&& !(self.cmd.is_args_override_self() || arg.overrides.contains(arg.get_id()))
{
return Err(ClapError::argument_conflict(
self.cmd,
arg.to_string(),
Expand All @@ -1240,7 +1244,9 @@ impl<'cmd> Parser<'cmd> {
raw_vals
};

if matcher.remove(&arg.id) && !self.cmd.is_args_override_self() {
if matcher.remove(&arg.id)
&& !(self.cmd.is_args_override_self() || arg.overrides.contains(arg.get_id()))
{
return Err(ClapError::argument_conflict(
self.cmd,
arg.to_string(),
Expand Down
26 changes: 23 additions & 3 deletions tests/builder/posix_compatible.rs
@@ -1,16 +1,36 @@
use clap::{arg, error::ErrorKind, Arg, ArgAction, Command};

#[test]
#[should_panic = "Argument 'flag' cannot override itself"]
fn flag_overrides_itself() {
Command::new("posix")
let res = Command::new("posix")
.arg(
arg!(--flag "some flag"
)
.action(ArgAction::SetTrue)
.overrides_with("flag"),
)
.build();
.try_get_matches_from(vec!["", "--flag", "--flag"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert!(*m.get_one::<bool>("flag").expect("defaulted by clap"));
}

#[test]
fn option_overrides_itself() {
let res = Command::new("posix")
.arg(
arg!(--opt <val> "some option")
.required(false)
.overrides_with("opt"),
)
.try_get_matches_from(vec!["", "--opt=some", "--opt=other"]);
assert!(res.is_ok(), "{}", res.unwrap_err());
let m = res.unwrap();
assert!(m.contains_id("opt"));
assert_eq!(
m.get_one::<String>("opt").map(|v| v.as_str()),
Some("other")
);
}

#[test]
Expand Down

0 comments on commit 3683e2c

Please sign in to comment.