mirror of
https://github.com/clap-rs/clap
synced 2024-11-11 07:14:15 +00:00
Merge pull request #3225 from epage/override
fix: Remove overriden occurrences as we go
This commit is contained in:
commit
a58c1640a2
7 changed files with 75 additions and 129 deletions
|
@ -2601,6 +2601,7 @@ impl<'help> App<'help> {
|
||||||
self._derive_display_order();
|
self._derive_display_order();
|
||||||
|
|
||||||
let mut pos_counter = 1;
|
let mut pos_counter = 1;
|
||||||
|
let self_override = self.is_set(AppSettings::AllArgsOverrideSelf);
|
||||||
for a in self.args.args_mut() {
|
for a in self.args.args_mut() {
|
||||||
// Fill in the groups
|
// Fill in the groups
|
||||||
for g in &a.groups {
|
for g in &a.groups {
|
||||||
|
@ -2619,6 +2620,10 @@ impl<'help> App<'help> {
|
||||||
// in the usage string don't get confused or left out.
|
// in the usage string don't get confused or left out.
|
||||||
self.settings.set(AppSettings::DontCollapseArgsInUsage);
|
self.settings.set(AppSettings::DontCollapseArgsInUsage);
|
||||||
}
|
}
|
||||||
|
if self_override {
|
||||||
|
let self_id = a.id.clone();
|
||||||
|
a.overrides.push(self_id);
|
||||||
|
}
|
||||||
a._build();
|
a._build();
|
||||||
if a.is_positional() && a.index.is_none() {
|
if a.is_positional() && a.index.is_none() {
|
||||||
a.index = Some(pos_counter);
|
a.index = Some(pos_counter);
|
||||||
|
|
|
@ -4808,6 +4808,16 @@ impl<'help> Arg<'help> {
|
||||||
self.num_vals = Some(val_names_len);
|
self.num_vals = Some(val_names_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let self_id = self.id.clone();
|
||||||
|
if self.is_positional() || self.is_set(ArgSettings::MultipleOccurrences) {
|
||||||
|
// Remove self-overrides where they don't make sense.
|
||||||
|
//
|
||||||
|
// We can evaluate switching this to a debug assert at a later time (though it will
|
||||||
|
// require changing propagation of `AllArgsOverrideSelf`). Being conservative for now
|
||||||
|
// due to where we are at in the release.
|
||||||
|
self.overrides.retain(|e| *e != self_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn generated(mut self) -> Self {
|
pub(crate) fn generated(mut self) -> Self {
|
||||||
|
|
|
@ -176,8 +176,11 @@ impl ArgMatcher {
|
||||||
ma.push_index(idx);
|
ma.push_index(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn arg_have_val(&mut self, arg: &Id) -> bool {
|
pub(crate) fn has_val_groups(&mut self, arg: &Id) -> bool {
|
||||||
matches!(self.entry(arg), Entry::Occupied(_))
|
match self.entry(arg) {
|
||||||
|
Entry::Occupied(e) => e.get().has_val_groups(),
|
||||||
|
Entry::Vacant(_) => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
|
pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
|
||||||
|
|
|
@ -77,10 +77,14 @@ impl MatchedArg {
|
||||||
self.vals.last().map(|x| x.len()).unwrap_or(0)
|
self.vals.last().map(|x| x.len()).unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_vals_empty(&self) -> bool {
|
pub(crate) fn all_val_groups_empty(&self) -> bool {
|
||||||
self.vals.iter().flatten().count() == 0
|
self.vals.iter().flatten().count() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn has_val_groups(&self) -> bool {
|
||||||
|
!self.vals.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
// Will be used later
|
// Will be used later
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn remove_vals(&mut self, len: usize) {
|
pub(crate) fn remove_vals(&mut self, len: usize) {
|
||||||
|
@ -104,13 +108,6 @@ impl MatchedArg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn override_vals(&mut self) {
|
|
||||||
let len = self.vals.len();
|
|
||||||
if len > 1 {
|
|
||||||
self.vals.drain(0..len - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn contains_val(&self, val: &str) -> bool {
|
pub(crate) fn contains_val(&self, val: &str) -> bool {
|
||||||
self.vals_flatten().any(|v| {
|
self.vals_flatten().any(|v| {
|
||||||
if self.ignore_case {
|
if self.ignore_case {
|
||||||
|
@ -158,47 +155,6 @@ pub(crate) enum ValueType {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_vals_override() {
|
|
||||||
let mut m = MatchedArg::new();
|
|
||||||
m.push_val("aaa".into());
|
|
||||||
m.new_val_group();
|
|
||||||
m.append_val("bbb".into());
|
|
||||||
m.append_val("ccc".into());
|
|
||||||
m.new_val_group();
|
|
||||||
m.append_val("ddd".into());
|
|
||||||
m.push_val("eee".into());
|
|
||||||
m.new_val_group();
|
|
||||||
m.append_val("fff".into());
|
|
||||||
m.append_val("ggg".into());
|
|
||||||
m.append_val("hhh".into());
|
|
||||||
m.append_val("iii".into());
|
|
||||||
|
|
||||||
m.override_vals();
|
|
||||||
let vals: Vec<&Vec<OsString>> = m.vals().collect();
|
|
||||||
assert_eq!(
|
|
||||||
vals,
|
|
||||||
vec![&vec![
|
|
||||||
OsString::from("fff"),
|
|
||||||
OsString::from("ggg"),
|
|
||||||
OsString::from("hhh"),
|
|
||||||
OsString::from("iii"),
|
|
||||||
]]
|
|
||||||
);
|
|
||||||
m.override_vals();
|
|
||||||
|
|
||||||
let vals: Vec<&Vec<OsString>> = m.vals().collect();
|
|
||||||
assert_eq!(
|
|
||||||
vals,
|
|
||||||
vec![&vec![
|
|
||||||
OsString::from("fff"),
|
|
||||||
OsString::from("ggg"),
|
|
||||||
OsString::from("hhh"),
|
|
||||||
OsString::from("iii"),
|
|
||||||
]]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_grouped_vals_first() {
|
fn test_grouped_vals_first() {
|
||||||
let mut m = MatchedArg::new();
|
let mut m = MatchedArg::new();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Std
|
// Std
|
||||||
use std::{
|
use std::{
|
||||||
cell::Cell,
|
cell::{Cell, RefCell},
|
||||||
ffi::{OsStr, OsString},
|
ffi::{OsStr, OsString},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ use crate::{
|
||||||
pub(crate) struct Parser<'help, 'app> {
|
pub(crate) struct Parser<'help, 'app> {
|
||||||
pub(crate) app: &'app mut App<'help>,
|
pub(crate) app: &'app mut App<'help>,
|
||||||
pub(crate) required: ChildGraph<Id>,
|
pub(crate) required: ChildGraph<Id>,
|
||||||
pub(crate) overridden: Vec<Id>,
|
pub(crate) overridden: RefCell<Vec<Id>>,
|
||||||
pub(crate) seen: Vec<Id>,
|
pub(crate) seen: Vec<Id>,
|
||||||
pub(crate) cur_idx: Cell<usize>,
|
pub(crate) cur_idx: Cell<usize>,
|
||||||
/// Index of the previous flag subcommand in a group of flags.
|
/// Index of the previous flag subcommand in a group of flags.
|
||||||
|
@ -51,7 +51,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
Parser {
|
Parser {
|
||||||
app,
|
app,
|
||||||
required: reqs,
|
required: reqs,
|
||||||
overridden: Vec::new(),
|
overridden: Default::default(),
|
||||||
seen: Vec::new(),
|
seen: Vec::new(),
|
||||||
cur_idx: Cell::new(0),
|
cur_idx: Cell::new(0),
|
||||||
flag_subcmd_at: None,
|
flag_subcmd_at: None,
|
||||||
|
@ -591,10 +591,14 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.seen.push(p.id.clone());
|
self.seen.push(p.id.clone());
|
||||||
|
// Increase occurrence no matter if we are appending, occurrences
|
||||||
|
// of positional argument equals to number of values rather than
|
||||||
|
// the number of value groups.
|
||||||
|
self.inc_occurrence_of_arg(matcher, p);
|
||||||
// Creating new value group rather than appending when the arg
|
// Creating new value group rather than appending when the arg
|
||||||
// doesn't have any value. This behaviour is right because
|
// doesn't have any value. This behaviour is right because
|
||||||
// positional arguments are always present continuously.
|
// positional arguments are always present continuously.
|
||||||
let append = self.arg_have_val(matcher, p);
|
let append = self.has_val_groups(matcher, p);
|
||||||
self.add_val_to_arg(
|
self.add_val_to_arg(
|
||||||
p,
|
p,
|
||||||
&arg_os,
|
&arg_os,
|
||||||
|
@ -604,11 +608,6 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
trailing_values,
|
trailing_values,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Increase occurrence no matter if we are appending, occurrences
|
|
||||||
// of positional argument equals to number of values rather than
|
|
||||||
// the number of value groups.
|
|
||||||
self.inc_occurrence_of_arg(matcher, p);
|
|
||||||
|
|
||||||
// Only increment the positional counter if it doesn't allow multiples
|
// Only increment the positional counter if it doesn't allow multiples
|
||||||
if !p.is_multiple() {
|
if !p.is_multiple() {
|
||||||
pos_counter += 1;
|
pos_counter += 1;
|
||||||
|
@ -658,8 +657,6 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
matches: sc_m.into_inner(),
|
matches: sc_m.into_inner(),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.remove_overrides(matcher);
|
|
||||||
|
|
||||||
return Validator::new(self).validate(
|
return Validator::new(self).validate(
|
||||||
parse_state,
|
parse_state,
|
||||||
subcmd_name.is_some(),
|
subcmd_name.is_some(),
|
||||||
|
@ -697,8 +694,6 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.remove_overrides(matcher);
|
|
||||||
|
|
||||||
Validator::new(self).validate(parse_state, subcmd_name.is_some(), matcher, trailing_values)
|
Validator::new(self).validate(parse_state, subcmd_name.is_some(), matcher, trailing_values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1302,6 +1297,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
if opt.is_set(ArgSettings::RequireEquals) && !has_eq {
|
if opt.is_set(ArgSettings::RequireEquals) && !has_eq {
|
||||||
if opt.min_vals == Some(0) {
|
if opt.min_vals == Some(0) {
|
||||||
debug!("Requires equals, but min_vals == 0");
|
debug!("Requires equals, but min_vals == 0");
|
||||||
|
self.inc_occurrence_of_arg(matcher, opt);
|
||||||
// We assume this case is valid: require equals, but min_vals == 0.
|
// We assume this case is valid: require equals, but min_vals == 0.
|
||||||
if !opt.default_missing_vals.is_empty() {
|
if !opt.default_missing_vals.is_empty() {
|
||||||
debug!("Parser::parse_opt: has default_missing_vals");
|
debug!("Parser::parse_opt: has default_missing_vals");
|
||||||
|
@ -1313,7 +1309,6 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
self.inc_occurrence_of_arg(matcher, opt);
|
|
||||||
if attached_value.is_some() {
|
if attached_value.is_some() {
|
||||||
ParseResult::AttachedValueNotConsumed
|
ParseResult::AttachedValueNotConsumed
|
||||||
} else {
|
} else {
|
||||||
|
@ -1333,6 +1328,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
fv,
|
fv,
|
||||||
fv.starts_with("=")
|
fv.starts_with("=")
|
||||||
);
|
);
|
||||||
|
self.inc_occurrence_of_arg(matcher, opt);
|
||||||
self.add_val_to_arg(
|
self.add_val_to_arg(
|
||||||
opt,
|
opt,
|
||||||
v,
|
v,
|
||||||
|
@ -1341,7 +1337,6 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
false,
|
false,
|
||||||
trailing_values,
|
trailing_values,
|
||||||
);
|
);
|
||||||
self.inc_occurrence_of_arg(matcher, opt);
|
|
||||||
ParseResult::ValuesDone
|
ParseResult::ValuesDone
|
||||||
} else {
|
} else {
|
||||||
debug!("Parser::parse_opt: More arg vals required...");
|
debug!("Parser::parse_opt: More arg vals required...");
|
||||||
|
@ -1463,78 +1458,40 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
matcher.add_index_to(&arg.id, self.cur_idx.get(), ty);
|
matcher.add_index_to(&arg.id, self.cur_idx.get(), ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arg_have_val(&self, matcher: &mut ArgMatcher, arg: &Arg<'help>) -> bool {
|
fn has_val_groups(&self, matcher: &mut ArgMatcher, arg: &Arg<'help>) -> bool {
|
||||||
matcher.arg_have_val(&arg.id)
|
matcher.has_val_groups(&arg.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_flag(&self, flag: &Arg<'help>, matcher: &mut ArgMatcher) -> ParseResult {
|
fn parse_flag(&self, flag: &Arg<'help>, matcher: &mut ArgMatcher) -> ParseResult {
|
||||||
debug!("Parser::parse_flag");
|
debug!("Parser::parse_flag");
|
||||||
|
|
||||||
matcher.add_index_to(&flag.id, self.cur_idx.get(), ValueType::CommandLine);
|
|
||||||
self.inc_occurrence_of_arg(matcher, flag);
|
self.inc_occurrence_of_arg(matcher, flag);
|
||||||
|
matcher.add_index_to(&flag.id, self.cur_idx.get(), ValueType::CommandLine);
|
||||||
|
|
||||||
ParseResult::ValuesDone
|
ParseResult::ValuesDone
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_overrides(&mut self, matcher: &mut ArgMatcher) {
|
fn remove_overrides(&self, arg: &Arg<'help>, matcher: &mut ArgMatcher) {
|
||||||
debug!("Parser::remove_overrides");
|
debug!("Parser::remove_overrides: id={:?}", arg.id);
|
||||||
let mut to_rem: Vec<Id> = Vec::new();
|
for override_id in &arg.overrides {
|
||||||
let mut self_override: Vec<Id> = Vec::new();
|
debug!("Parser::remove_overrides:iter:{:?}: removing", override_id);
|
||||||
let mut arg_overrides = Vec::new();
|
matcher.remove(override_id);
|
||||||
for name in matcher.arg_names() {
|
self.overridden.borrow_mut().push(override_id.clone());
|
||||||
debug!("Parser::remove_overrides:iter:{:?}", name);
|
}
|
||||||
if let Some(overrider) = self.app.find(name) {
|
|
||||||
let mut override_self = false;
|
// Override anything that can override us
|
||||||
for overridee in &overrider.overrides {
|
let mut transitive = Vec::new();
|
||||||
debug!(
|
for arg_id in matcher.arg_names() {
|
||||||
"Parser::remove_overrides:iter:{:?} => {:?}",
|
if let Some(overrider) = self.app.find(arg_id) {
|
||||||
name, overrider
|
if overrider.overrides.contains(&arg.id) {
|
||||||
);
|
transitive.push(&overrider.id);
|
||||||
if *overridee == overrider.id {
|
|
||||||
override_self = true;
|
|
||||||
} else {
|
|
||||||
arg_overrides.push((overrider.id.clone(), overridee));
|
|
||||||
arg_overrides.push((overridee.clone(), &overrider.id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Only do self override for argument that is not positional
|
|
||||||
// argument or flag with MultipleOccurrences setting enabled.
|
|
||||||
if (self.is_set(AS::AllArgsOverrideSelf) || override_self)
|
|
||||||
&& !overrider.is_set(ArgSettings::MultipleOccurrences)
|
|
||||||
&& !overrider.is_positional()
|
|
||||||
{
|
|
||||||
debug!(
|
|
||||||
"Parser::remove_overrides:iter:{:?}:iter:{:?}: self override",
|
|
||||||
name, overrider
|
|
||||||
);
|
|
||||||
self_override.push(overrider.id.clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for overrider_id in transitive {
|
||||||
// remove future overrides in reverse seen order
|
debug!("Parser::remove_overrides:iter:{:?}: removing", overrider_id);
|
||||||
for arg in self.seen.iter().rev() {
|
matcher.remove(overrider_id);
|
||||||
for (a, overr) in arg_overrides.iter().filter(|(a, _)| a == arg) {
|
self.overridden.borrow_mut().push(overrider_id.clone());
|
||||||
if !to_rem.contains(a) {
|
|
||||||
to_rem.push((*overr).clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do self overrides
|
|
||||||
for name in &self_override {
|
|
||||||
debug!("Parser::remove_overrides:iter:self:{:?}: resetting", name);
|
|
||||||
if let Some(ma) = matcher.get_mut(name) {
|
|
||||||
ma.occurs = 1;
|
|
||||||
ma.override_vals();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally remove conflicts
|
|
||||||
for name in &to_rem {
|
|
||||||
debug!("Parser::remove_overrides:iter:{:?}: removing", name);
|
|
||||||
matcher.remove(name);
|
|
||||||
self.overridden.push(name.clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1638,7 +1595,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
arg.name
|
arg.name
|
||||||
);
|
);
|
||||||
match matcher.get(&arg.id) {
|
match matcher.get(&arg.id) {
|
||||||
Some(ma) if ma.is_vals_empty() => {
|
Some(ma) if ma.all_val_groups_empty() => {
|
||||||
debug!(
|
debug!(
|
||||||
"Parser::add_value:iter:{}: has no user defined vals",
|
"Parser::add_value:iter:{}: has no user defined vals",
|
||||||
arg.name
|
arg.name
|
||||||
|
@ -1732,6 +1689,9 @@ impl<'help, 'app> Parser<'help, 'app> {
|
||||||
|
|
||||||
/// Increase occurrence of specific argument and the grouped arg it's in.
|
/// Increase occurrence of specific argument and the grouped arg it's in.
|
||||||
fn inc_occurrence_of_arg(&self, matcher: &mut ArgMatcher, arg: &Arg<'help>) {
|
fn inc_occurrence_of_arg(&self, matcher: &mut ArgMatcher, arg: &Arg<'help>) {
|
||||||
|
// With each new occurrence, remove overrides from prior occurrences
|
||||||
|
self.remove_overrides(arg, matcher);
|
||||||
|
|
||||||
matcher.inc_occurrence_of_arg(arg);
|
matcher.inc_occurrence_of_arg(arg);
|
||||||
// Increment or create the group "args"
|
// Increment or create the group "args"
|
||||||
for group in self.app.groups_for_arg(&arg.id) {
|
for group in self.app.groups_for_arg(&arg.id) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> {
|
||||||
let o = &self.p.app[&a];
|
let o = &self.p.app[&a];
|
||||||
reqs_validated = true;
|
reqs_validated = true;
|
||||||
let should_err = if let Some(v) = matcher.0.args.get(&o.id) {
|
let should_err = if let Some(v) = matcher.0.args.get(&o.id) {
|
||||||
v.is_vals_empty() && !(o.min_vals.is_some() && o.min_vals.unwrap() == 0)
|
v.all_val_groups_empty() && !(o.min_vals.is_some() && o.min_vals.unwrap() == 0)
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
@ -396,7 +396,7 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> {
|
||||||
};
|
};
|
||||||
// Issue 665 (https://github.com/clap-rs/clap/issues/665)
|
// Issue 665 (https://github.com/clap-rs/clap/issues/665)
|
||||||
// Issue 1105 (https://github.com/clap-rs/clap/issues/1105)
|
// Issue 1105 (https://github.com/clap-rs/clap/issues/1105)
|
||||||
if a.is_set(ArgSettings::TakesValue) && !min_vals_zero && ma.is_vals_empty() {
|
if a.is_set(ArgSettings::TakesValue) && !min_vals_zero && ma.all_val_groups_empty() {
|
||||||
return Err(Error::empty_value(
|
return Err(Error::empty_value(
|
||||||
self.p.app,
|
self.p.app,
|
||||||
a,
|
a,
|
||||||
|
@ -457,7 +457,7 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> {
|
||||||
|
|
||||||
fn is_missing_required_ok(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool {
|
fn is_missing_required_ok(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool {
|
||||||
debug!("Validator::is_missing_required_ok: {}", a.name);
|
debug!("Validator::is_missing_required_ok: {}", a.name);
|
||||||
self.validate_arg_conflicts(a, matcher) || self.p.overridden.contains(&a.id)
|
self.validate_arg_conflicts(a, matcher) || self.p.overridden.borrow().contains(&a.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_arg_conflicts(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool {
|
fn validate_arg_conflicts(&self, a: &Arg<'help>, matcher: &ArgMatcher) -> bool {
|
||||||
|
|
|
@ -387,3 +387,15 @@ fn issue_1374_overrides_self_with_multiple_values() {
|
||||||
&["c", "d"]
|
&["c", "d"]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn incremental_override() {
|
||||||
|
let mut app = App::new("test")
|
||||||
|
.arg(arg!(--name <NAME>).multiple_occurrences(true))
|
||||||
|
.arg(arg!(--"no-name").overrides_with("name"));
|
||||||
|
let m = app
|
||||||
|
.try_get_matches_from_mut(&["test", "--name=ahmed", "--no-name", "--name=ali"])
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(m.values_of("name").unwrap().collect::<Vec<_>>(), &["ali"]);
|
||||||
|
assert!(!m.is_present("no-name"));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue