From 409480787103742d35d5cf5148639d84b307ea1d Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 23 Sep 2022 15:18:14 -0500 Subject: [PATCH] WIP --- src/builder/app_settings.rs | 4 ++++ src/builder/command.rs | 22 ++++++++++++++++++++++ src/parser/arg_matcher.rs | 4 ++-- src/parser/parser.rs | 27 ++++++++++++++++++++++++--- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/builder/app_settings.rs b/src/builder/app_settings.rs index 8fcad37e7e9b..7a9ff8c69c50 100644 --- a/src/builder/app_settings.rs +++ b/src/builder/app_settings.rs @@ -31,6 +31,7 @@ pub(crate) enum AppSettings { IgnoreErrors, AllowHyphenValues, AllowNegativeNumbers, + AllArgsOverrideSelf, AllowMissingPositional, TrailingVarArg, DontDelimitTrailingValues, @@ -93,6 +94,7 @@ bitflags! { const VALID_ARG_FOUND = 1 << 35; const INFER_SUBCOMMANDS = 1 << 36; const CONTAINS_LAST = 1 << 37; + const ARGS_OVERRIDE_SELF = 1 << 38; const HELP_REQUIRED = 1 << 39; const SUBCOMMAND_PRECEDENCE_OVER_ARG = 1 << 40; const DISABLE_HELP_FLAG = 1 << 41; @@ -163,6 +165,8 @@ impl_settings! { AppSettings, AppFlags, => Flags::BIN_NAME_BUILT, InferSubcommands => Flags::INFER_SUBCOMMANDS, + AllArgsOverrideSelf + => Flags::ARGS_OVERRIDE_SELF, InferLongArgs => Flags::INFER_LONG_ARGS } diff --git a/src/builder/command.rs b/src/builder/command.rs index c0c115abec99..d685295fb5ee 100644 --- a/src/builder/command.rs +++ b/src/builder/command.rs @@ -978,6 +978,23 @@ impl Command { } } + /// Specifies that all arguments override themselves. + /// + /// This is the equivalent to saying the `foo` arg using [`Arg::overrides_with("foo")`] for all + /// defined arguments. + /// + /// **NOTE:** This choice is propagated to all child subcommands. + /// + /// [`Arg::overrides_with("foo")`]: crate::Arg::overrides_with() + #[inline] + pub fn args_override_self(self, yes: bool) -> Self { + if yes { + self.global_setting(AppSettings::AllArgsOverrideSelf) + } else { + self.unset_global_setting(AppSettings::AllArgsOverrideSelf) + } + } + /// Disables the automatic delimiting of values after `--` or when [`Command::trailing_var_arg`] /// was used. /// @@ -3671,6 +3688,11 @@ impl Command { self.is_set(AppSettings::ArgsNegateSubcommands) } + #[doc(hidden)] + pub fn is_args_override_self(&self) -> bool { + self.is_set(AppSettings::AllArgsOverrideSelf) + } + /// Report whether [`Command::subcommand_precedence_over_arg`] is set pub fn is_subcommand_precedence_over_arg_set(&self) -> bool { self.is_set(AppSettings::SubcommandPrecedenceOverArg) diff --git a/src/parser/arg_matcher.rs b/src/parser/arg_matcher.rs index 071e3b272db9..3eac897fc0fa 100644 --- a/src/parser/arg_matcher.rs +++ b/src/parser/arg_matcher.rs @@ -101,8 +101,8 @@ impl ArgMatcher { self.matches.args.get_mut(arg) } - pub(crate) fn remove(&mut self, arg: &Id) { - self.matches.args.remove(arg); + pub(crate) fn remove(&mut self, arg: &Id) -> bool { + self.matches.args.remove(arg).is_some() } pub(crate) fn contains(&self, arg: &Id) -> bool { diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 1db8495eff68..190a1b54f4fc 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -1179,7 +1179,14 @@ impl<'cmd> Parser<'cmd> { self.cur_idx.set(self.cur_idx.get() + 1); debug!("Parser::react: cur_idx:={}", self.cur_idx.get()); } - matcher.remove(&arg.id); + if matcher.remove(&arg.id) && !self.cmd.is_args_override_self() { + return Err(ClapError::argument_conflict( + self.cmd, + arg.to_string(), + vec![arg.to_string()], + Usage::new(self.cmd).create_usage_with_title(&[]), + )); + } self.start_custom_arg(matcher, arg, source); self.push_arg_values(arg, raw_vals, matcher)?; if cfg!(debug_assertions) && matcher.needs_more_vals(arg) { @@ -1213,7 +1220,14 @@ impl<'cmd> Parser<'cmd> { raw_vals }; - matcher.remove(&arg.id); + if matcher.remove(&arg.id) && !self.cmd.is_args_override_self() { + return Err(ClapError::argument_conflict( + self.cmd, + arg.to_string(), + vec![arg.to_string()], + Usage::new(self.cmd).create_usage_with_title(&[]), + )); + } self.start_custom_arg(matcher, arg, source); self.push_arg_values(arg, raw_vals, matcher)?; Ok(ParseResult::ValuesDone) @@ -1225,7 +1239,14 @@ impl<'cmd> Parser<'cmd> { raw_vals }; - matcher.remove(&arg.id); + if matcher.remove(&arg.id) && self.cmd.is_args_conflicts_with_self() { + return Err(ClapError::argument_conflict( + self.cmd, + arg.to_string(), + vec![arg.to_string()], + Usage::new(self.cmd).create_usage_with_title(&[]), + )); + } self.start_custom_arg(matcher, arg, source); self.push_arg_values(arg, raw_vals, matcher)?; Ok(ParseResult::ValuesDone)