diff --git a/CHANGELOG.md b/CHANGELOG.md index b247fd1cb32..f9ade3d6a89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `number_of_values(1)` no longer implies `multiple_values(true)` - Remove `Arg::min_values` (across all occurrences) with `Arg::number_of_values(N..)` (per occurrence) - Remove `Arg::max_values` (across all occurrences) with `Arg::number_of_values(1..=M)` (per occurrence) +- Remove `Arg::multiple_values(true)` with `Arg::number_of_values(1..)` and `Arg::multiple_values(false)` with `Arg::number_of_values(0)` - `ArgAction::SetTrue` and `ArgAction::SetFalse` now prioritize `Arg::default_missing_value` over their standard behavior - *(help)* Make `DeriveDisplayOrder` the default and removed the setting. To sort help, set `next_display_order(None)` (#2808) - *(help)* Subcommand display order respects `Command::next_display_order` instead of `DeriveDisplayOrder` and using its own initial display order value (#2808) diff --git a/clap_bench/benches/03_complex.rs b/clap_bench/benches/03_complex.rs index c22c279e957..bd9583f45a0 100644 --- a/clap_bench/benches/03_complex.rs +++ b/clap_bench/benches/03_complex.rs @@ -30,9 +30,9 @@ macro_rules! create_app { arg!(--multvals "Tests multiple values not mult occs").required(false).value_names(&["one", "two"]), arg!( --multvalsmo "Tests multiple values, not mult occs" - ).multiple_values(true).required(false).value_names(&["one", "two"]), - arg!(--minvals2 ... "Tests 2 min vals").number_of_values(2..).multiple_values(true).required(false), - arg!(--maxvals3 ... "Tests 3 max vals").number_of_values(1..=3).multiple_values(true).required(false), + ).required(false).value_names(&["one", "two"]), + arg!(--minvals2 ... "Tests 2 min vals").number_of_values(2..).required(false), + arg!(--maxvals3 ... "Tests 3 max vals").number_of_values(1..=3).required(false), ]) .subcommand( Command::new("subcmd") @@ -57,7 +57,7 @@ pub fn build_from_builder(c: &mut Criterion) { .help("tests options") .short('o') .long("option") - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ) .arg(Arg::new("positional").help("tests positionals").index(1)) @@ -99,7 +99,7 @@ pub fn build_from_builder(c: &mut Criterion) { ) .arg( Arg::new("positional3") - .multiple_values(true) + .number_of_values(1..) .help("tests positionals with specific values") .index(4) .value_parser(POS3_VALS), @@ -113,7 +113,6 @@ pub fn build_from_builder(c: &mut Criterion) { .arg( Arg::new("multvalsmo") .long("multvalsmo") - .multiple_values(true) .action(ArgAction::Append) .help("Tests multiple values, not mult occs") .value_names(&["one", "two"]), @@ -121,7 +120,6 @@ pub fn build_from_builder(c: &mut Criterion) { .arg( Arg::new("minvals") .long("minvals2") - .multiple_values(true) .action(ArgAction::Append) .help("Tests 2 min vals") .number_of_values(2..), @@ -129,7 +127,6 @@ pub fn build_from_builder(c: &mut Criterion) { .arg( Arg::new("maxvals") .long("maxvals3") - .multiple_values(true) .action(ArgAction::Append) .help("Tests 3 max vals") .number_of_values(1..=3), @@ -143,7 +140,7 @@ pub fn build_from_builder(c: &mut Criterion) { Arg::new("scoption") .short('o') .long("option") - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append) .help("tests options"), ) diff --git a/clap_bench/benches/04_new_help.rs b/clap_bench/benches/04_new_help.rs index 513c34374ec..cbc5d36cf31 100644 --- a/clap_bench/benches/04_new_help.rs +++ b/clap_bench/benches/04_new_help.rs @@ -118,7 +118,7 @@ fn app_example7<'c>() -> Command<'c> { .arg( Arg::new("input") .help("the input file to use") - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append) .required(true) .short('i') @@ -135,7 +135,7 @@ fn app_example8<'c>() -> Command<'c> { .arg( Arg::new("input") .help("the input file to use") - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append) .required(true) .short('i') diff --git a/clap_bench/benches/05_ripgrep.rs b/clap_bench/benches/05_ripgrep.rs index 3fd83b514e8..519471aa02a 100644 --- a/clap_bench/benches/05_ripgrep.rs +++ b/clap_bench/benches/05_ripgrep.rs @@ -323,7 +323,7 @@ where "type-list", "version", ])) - .arg(arg("path").multiple_values(true)) + .arg(arg("path").number_of_values(1..)) .arg( flag("regexp") .short('e') diff --git a/clap_bench/benches/06_rustup.rs b/clap_bench/benches/06_rustup.rs index 127c69f0151..96196411bd3 100644 --- a/clap_bench/benches/06_rustup.rs +++ b/clap_bench/benches/06_rustup.rs @@ -236,7 +236,7 @@ fn build_cli() -> Command<'static> { .after_help(RUN_HELP) .trailing_var_arg(true) .arg(Arg::new("toolchain").required(true)) - .arg(Arg::new("command").required(true).multiple_values(true)), + .arg(Arg::new("command").required(true).number_of_values(1..)), ) .subcommand( Command::new("which") diff --git a/clap_complete/examples/completion.rs b/clap_complete/examples/completion.rs index 5dd5b3f9361..e506222736e 100644 --- a/clap_complete/examples/completion.rs +++ b/clap_complete/examples/completion.rs @@ -68,7 +68,7 @@ fn build_cli() -> Command<'static> { ) .arg( Arg::new("command_with_args") - .multiple_values(true) + .number_of_values(1..) .value_hint(ValueHint::CommandWithArguments), ) .arg( diff --git a/clap_complete/tests/common.rs b/clap_complete/tests/common.rs index 13af2fcc55d..f1d0323883a 100644 --- a/clap_complete/tests/common.rs +++ b/clap_complete/tests/common.rs @@ -64,7 +64,7 @@ pub fn special_commands_command(name: &'static str) -> clap::Command<'static> { .require_equals(true) .help("the other case to test"), ) - .arg(clap::Arg::new("path").multiple_values(true)), + .arg(clap::Arg::new("path").number_of_values(1..)), ) .subcommand(clap::Command::new("some-cmd-with-hyphens").alias("hyphen")) .subcommand(clap::Command::new("some-hidden-cmd").hide(true)) @@ -220,7 +220,7 @@ pub fn value_hint_command(name: &'static str) -> clap::Command<'static> { .arg( clap::Arg::new("command_with_args") .action(clap::ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .value_hint(clap::ValueHint::CommandWithArguments), ) .arg( diff --git a/clap_complete/tests/snapshots/basic.bash b/clap_complete/tests/snapshots/basic.bash index 2a5b11c7069..0aa37b4cfd8 100644 --- a/clap_complete/tests/snapshots/basic.bash +++ b/clap_complete/tests/snapshots/basic.bash @@ -39,7 +39,7 @@ _my-app() { return 0 ;; my__app__help) - opts="-c ..." + opts="-c [...]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/clap_complete/tests/snapshots/feature_sample.bash b/clap_complete/tests/snapshots/feature_sample.bash index 98918ca47f3..af529269b62 100644 --- a/clap_complete/tests/snapshots/feature_sample.bash +++ b/clap_complete/tests/snapshots/feature_sample.bash @@ -39,7 +39,7 @@ _my-app() { return 0 ;; my__app__help) - opts="..." + opts="[...]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/clap_complete/tests/snapshots/quoting.bash b/clap_complete/tests/snapshots/quoting.bash index ead2b13b8bb..a4ae43a2009 100644 --- a/clap_complete/tests/snapshots/quoting.bash +++ b/clap_complete/tests/snapshots/quoting.bash @@ -138,7 +138,7 @@ _my-app() { return 0 ;; my__app__help) - opts="..." + opts="[...]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/clap_complete/tests/snapshots/special_commands.bash b/clap_complete/tests/snapshots/special_commands.bash index 33f99ad04a3..bb603b5b11b 100644 --- a/clap_complete/tests/snapshots/special_commands.bash +++ b/clap_complete/tests/snapshots/special_commands.bash @@ -48,7 +48,7 @@ _my-app() { return 0 ;; my__app__help) - opts="..." + opts="[...]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/clap_complete/tests/snapshots/sub_subcommands.bash b/clap_complete/tests/snapshots/sub_subcommands.bash index 85729508196..c96561de46d 100644 --- a/clap_complete/tests/snapshots/sub_subcommands.bash +++ b/clap_complete/tests/snapshots/sub_subcommands.bash @@ -45,7 +45,7 @@ _my-app() { return 0 ;; my__app__help) - opts="..." + opts="[...]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -73,7 +73,7 @@ _my-app() { return 0 ;; my__app__some_cmd__help) - opts="..." + opts="[...]" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/clap_complete_fig/tests/common.rs b/clap_complete_fig/tests/common.rs index 13af2fcc55d..f1d0323883a 100644 --- a/clap_complete_fig/tests/common.rs +++ b/clap_complete_fig/tests/common.rs @@ -64,7 +64,7 @@ pub fn special_commands_command(name: &'static str) -> clap::Command<'static> { .require_equals(true) .help("the other case to test"), ) - .arg(clap::Arg::new("path").multiple_values(true)), + .arg(clap::Arg::new("path").number_of_values(1..)), ) .subcommand(clap::Command::new("some-cmd-with-hyphens").alias("hyphen")) .subcommand(clap::Command::new("some-hidden-cmd").hide(true)) @@ -220,7 +220,7 @@ pub fn value_hint_command(name: &'static str) -> clap::Command<'static> { .arg( clap::Arg::new("command_with_args") .action(clap::ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .value_hint(clap::ValueHint::CommandWithArguments), ) .arg( diff --git a/clap_derive/src/derives/args.rs b/clap_derive/src/derives/args.rs index 81de7a01764..689a2418ee5 100644 --- a/clap_derive/src/derives/args.rs +++ b/clap_derive/src/derives/args.rs @@ -267,7 +267,7 @@ pub fn gen_augment( if attrs.is_positional() { quote_spanned! { ty.span()=> .value_name(#value_name) - .multiple_values(true) // action won't be sufficient for getting multiple + .number_of_values(1..) // action won't be sufficient for getting multiple #value_parser #action } @@ -284,7 +284,7 @@ pub fn gen_augment( if attrs.is_positional() { quote_spanned! { ty.span()=> .value_name(#value_name) - .multiple_values(true) // action won't be sufficient for getting multiple + .number_of_values(1..) // action won't be sufficient for getting multiple #value_parser #action } diff --git a/clap_mangen/tests/common.rs b/clap_mangen/tests/common.rs index 55c5c5fcd6b..025ffef923e 100644 --- a/clap_mangen/tests/common.rs +++ b/clap_mangen/tests/common.rs @@ -216,7 +216,7 @@ pub fn value_hint_command(name: &'static str) -> clap::Command<'static> { .arg( clap::Arg::new("command_with_args") .action(clap::ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .value_hint(clap::ValueHint::CommandWithArguments), ) .arg( diff --git a/examples/escaped-positional.rs b/examples/escaped-positional.rs index 02420010022..e0505b9d339 100644 --- a/examples/escaped-positional.rs +++ b/examples/escaped-positional.rs @@ -11,7 +11,7 @@ fn main() { .arg( // Indicates that `slop` is only accessible after `--`. arg!(slop: [SLOP]) - .multiple_values(true) + .number_of_values(1..) .last(true) .value_parser(value_parser!(String)), ) diff --git a/examples/pacman.rs b/examples/pacman.rs index 6f02c30e0c8..f532bc68cce 100644 --- a/examples/pacman.rs +++ b/examples/pacman.rs @@ -22,7 +22,7 @@ fn main() { .help("search locally installed packages for matching strings") .conflicts_with("info") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .arg( Arg::new("info") @@ -31,7 +31,7 @@ fn main() { .conflicts_with("search") .help("view package information") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ), ) // Sync subcommand @@ -48,7 +48,7 @@ fn main() { .long("search") .conflicts_with("info") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .help("search remote repositories for matching strings"), ) .arg( @@ -64,7 +64,7 @@ fn main() { .help("packages") .required_unless_present("search") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ), ) .get_matches(); diff --git a/src/builder/arg.rs b/src/builder/arg.rs index 7425368fcec..da037358d71 100644 --- a/src/builder/arg.rs +++ b/src/builder/arg.rs @@ -411,8 +411,8 @@ impl<'help> Arg<'help> { /// **NOTE:** This is only meant to be used for positional arguments and shouldn't to be used /// with [`Arg::short`] or [`Arg::long`]. /// - /// **NOTE:** When utilized with [`Arg::multiple_values(true)`], only the **last** positional argument - /// may be defined as multiple (i.e. with the highest index) + /// **NOTE:** When utilized with [`Arg::number_of_values(1..)`], only the **last** positional argument + /// may be defined as having a variable number of arguments (i.e. with the highest index) /// /// # Panics /// @@ -447,7 +447,7 @@ impl<'help> Arg<'help> { /// ``` /// [`Arg::short`]: Arg::short() /// [`Arg::long`]: Arg::long() - /// [`Arg::multiple_values(true)`]: Arg::multiple_values() + /// [`Arg::number_of_values(true)`]: Arg::number_of_values() /// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html /// [`Command`]: crate::Command #[inline] @@ -808,7 +808,7 @@ impl<'help> Arg<'help> { /// assert_eq!(m.get_one::("mode").unwrap(), "fast"); /// ``` /// [`Arg::value_delimiter(char)`]: Arg::value_delimiter() - /// [multiple values]: Arg::multiple_values + /// [multiple values]: Arg::number_of_values #[inline] #[must_use] pub fn takes_value(self, yes: bool) -> Self { @@ -905,170 +905,9 @@ impl<'help> Arg<'help> { self } - /// Specifies that the argument may have an unknown number of values - /// - /// Without any other settings, this argument may appear only *once*. - /// - /// For example, `--opt val1 val2` is allowed, but `--opt val1 val2 --opt val3` is not. - /// - /// **NOTE:** Setting this requires [`Arg::takes_value`]. - /// - /// **WARNING:** - /// - /// Setting `multiple_values` for an argument that takes a value, but with no other details can - /// be dangerous in some circumstances. Because multiple values are allowed, - /// `--option val1 val2 val3` is perfectly valid. Be careful when designing a CLI where - /// positional arguments are *also* expected as `clap` will continue parsing *values* until one - /// of the following happens: - /// - /// - It reaches the [maximum number of values] - /// - It reaches a [specific number of values] - /// - It finds another flag or option (i.e. something that starts with a `-`) - /// - It reaches a [value terminator][Arg::value_terminator] - /// - /// Alternatively, [require a delimiter between values][Arg::require_value_delimiter]. - /// - /// **WARNING:** - /// - /// When using args with `multiple_values` and [`subcommands`], one needs to consider the - /// possibility of an argument value being the same as a valid subcommand. By default `clap` will - /// parse the argument in question as a value *only if* a value is possible at that moment. - /// Otherwise it will be parsed as a subcommand. In effect, this means using `multiple_values` with no - /// additional parameters and a value that coincides with a subcommand name, the subcommand - /// cannot be called unless another argument is passed between them. - /// - /// As an example, consider a CLI with an option `--ui-paths=...` and subcommand `signer` - /// - /// The following would be parsed as values to `--ui-paths`. - /// - /// ```text - /// $ program --ui-paths path1 path2 signer - /// ``` - /// - /// This is because `--ui-paths` accepts multiple values. `clap` will continue parsing values - /// until another argument is reached and it knows `--ui-paths` is done parsing. - /// - /// By adding additional parameters to `--ui-paths` we can solve this issue. Consider adding - /// [`Arg::number_of_values(1)`] or using *only* [`ArgAction::Append`]. The following are all - /// valid, and `signer` is parsed as a subcommand in the first case, but a value in the second - /// case. - /// - /// ```text - /// $ program --ui-paths path1 signer - /// $ program --ui-paths path1 --ui-paths signer signer - /// ``` - /// - /// # Examples - /// - /// An example with options - /// - /// ```rust - /// # use clap::{Command, Arg, ArgAction}; - /// let m = Command::new("prog") - /// .arg(Arg::new("file") - /// .action(ArgAction::Set) - /// .multiple_values(true) - /// .short('F')) - /// .get_matches_from(vec![ - /// "prog", "-F", "file1", "file2", "file3" - /// ]); - /// - /// assert!(m.contains_id("file")); - /// let files: Vec<_> = m.get_many::("file").unwrap().collect(); - /// assert_eq!(files, ["file1", "file2", "file3"]); - /// ``` - /// - /// Although `multiple_values` has been specified, the last argument still wins - /// - /// ```rust - /// # use clap::{Command, Arg, error::ErrorKind, ArgAction}; - /// let m = Command::new("prog") - /// .arg(Arg::new("file") - /// .action(ArgAction::Set) - /// .multiple_values(true) - /// .short('F')) - /// .get_matches_from(vec![ - /// "prog", "-F", "file1", "-F", "file2", "-F", "file3" - /// ]); - /// - /// assert!(m.contains_id("file")); - /// let files: Vec<_> = m.get_many::("file").unwrap().collect(); - /// assert_eq!(files, ["file3"]); - /// ``` - /// - /// A common mistake is to define an option which allows multiple values, and a positional - /// argument. - /// - /// ```rust - /// # use clap::{Command, Arg, ArgAction}; - /// let m = Command::new("prog") - /// .arg(Arg::new("file") - /// .action(ArgAction::Set) - /// .multiple_values(true) - /// .short('F')) - /// .arg(Arg::new("word")) - /// .get_matches_from(vec![ - /// "prog", "-F", "file1", "file2", "file3", "word" - /// ]); - /// - /// assert!(m.contains_id("file")); - /// let files: Vec<_> = m.get_many::("file").unwrap().collect(); - /// assert_eq!(files, ["file1", "file2", "file3", "word"]); // wait...what?! - /// assert!(!m.contains_id("word")); // but we clearly used word! - /// ``` - /// - /// The problem is `clap` doesn't know when to stop parsing values for "files". This is further - /// compounded by if we'd said `word -F file1 file2` it would have worked fine, so it would - /// appear to only fail sometimes...not good! - /// - /// A solution for the example above is to limit how many values with a [maximum], or [specific] - /// number, or to say [`ArgAction::Append`] is ok, but multiple values is not. - /// - /// ```rust - /// # use clap::{Command, Arg, ArgAction}; - /// let m = Command::new("prog") - /// .arg(Arg::new("file") - /// .action(ArgAction::Set) - /// .action(ArgAction::Append) - /// .short('F')) - /// .arg(Arg::new("word")) - /// .get_matches_from(vec![ - /// "prog", "-F", "file1", "-F", "file2", "-F", "file3", "word" - /// ]); - /// - /// assert!(m.contains_id("file")); - /// let files: Vec<_> = m.get_many::("file").unwrap().collect(); - /// assert_eq!(files, ["file1", "file2", "file3"]); - /// assert_eq!(m.get_one::("word").unwrap(), "word"); - /// ``` - /// - /// As a final example, let's fix the above error and get a pretty message to the user :) - /// - /// ```rust - /// # use clap::{Command, Arg, error::ErrorKind, ArgAction}; - /// let res = Command::new("prog") - /// .arg(Arg::new("file") - /// .action(ArgAction::Set) - /// .action(ArgAction::Append) - /// .short('F')) - /// .arg(Arg::new("word")) - /// .try_get_matches_from(vec![ - /// "prog", "-F", "file1", "file2", "file3", "word" - /// ]); - /// - /// assert!(res.is_err()); - /// assert_eq!(res.unwrap_err().kind(), ErrorKind::UnknownArgument); - /// ``` - /// - /// [`subcommands`]: crate::Command::subcommand() - /// [`Arg::number_of_values(1)`]: Arg::number_of_values() - /// [maximum number of values]: Arg::number_of_values() - /// [specific number of values]: Arg::number_of_values() - /// [maximum]: Arg::number_of_values() - /// [specific]: Arg::number_of_values() #[inline] #[must_use] - pub fn multiple_values(self, yes: bool) -> Self { + fn multiple_values(self, yes: bool) -> Self { if yes { self.setting(ArgSettings::MultipleValues) } else { @@ -1222,7 +1061,6 @@ impl<'help> Arg<'help> { /// assert_eq!(m.get_one::("word").unwrap(), "word"); /// ``` /// [`Arg::value_delimiter(char)`]: Arg::value_delimiter() - /// [multiple values]: Arg::multiple_values #[inline] #[must_use] pub fn number_of_values(mut self, qty: impl Into) -> Self { @@ -1298,7 +1136,7 @@ impl<'help> Arg<'help> { /// **Pro Tip:** It may help to use [`Arg::next_line_help(true)`] if there are long, or /// multiple value names in order to not throw off the help text alignment of all options. /// - /// **NOTE:** implicitly sets [`Arg::action(ArgAction::Set)`] and [`Arg::multiple_values(true)`]. + /// **NOTE:** implicitly sets [`Arg::action(ArgAction::Set)`] and [`Arg::number_of_values(1..)`]. /// /// # Examples /// @@ -1336,7 +1174,7 @@ impl<'help> Arg<'help> { /// [`Arg::next_line_help(true)`]: Arg::next_line_help() /// [`Arg::number_of_values`]: Arg::number_of_values() /// [`Arg::action(ArgAction::Set)`]: Arg::takes_value() - /// [`Arg::multiple_values(true)`]: Arg::multiple_values() + /// [`Arg::number_of_values(1..)`]: Arg::number_of_values() #[must_use] pub fn value_names(mut self, names: &[&'help str]) -> Self { self.val_names = names.to_vec(); @@ -1368,7 +1206,7 @@ impl<'help> Arg<'help> { /// .arg( /// Arg::new("command") /// .action(ArgAction::Set) - /// .multiple_values(true) + /// .number_of_values(1..) /// .value_hint(ValueHint::CommandWithArguments) /// ); /// ``` @@ -1417,7 +1255,7 @@ impl<'help> Arg<'help> { /// .long("option") /// .action(ArgAction::Set) /// .ignore_case(true) - /// .multiple_values(true) + /// .number_of_values(1..) /// .value_parser(["test123", "test321"])) /// .get_matches_from(vec![ /// "pv", "--option", "TeSt123", "teST123", "tESt321" @@ -1441,7 +1279,7 @@ impl<'help> Arg<'help> { /// **NOTE:** Setting this requires [`Arg::takes_value`] /// /// **WARNING**: Take caution when using this setting combined with - /// [`Arg::multiple_values`], as this becomes ambiguous `$ prog --arg -- -- val`. All + /// [`Arg::number_of_values`], as this becomes ambiguous `$ prog --arg -- -- val`. All /// three `--, --, val` will be values when the user may have thought the second `--` would /// constitute the normal, "Only positional args follow" idiom. /// @@ -1666,7 +1504,7 @@ impl<'help> Arg<'help> { /// .action(ArgAction::Set) /// .use_value_delimiter(true) /// .require_value_delimiter(true) - /// .multiple_values(true)) + /// .number_of_values(1..)) /// .get_matches_from(vec![ /// "prog", "-o", "val1,val2,val3", /// ]); @@ -1707,7 +1545,7 @@ impl<'help> Arg<'help> { /// .arg(Arg::new("opt") /// .short('o') /// .action(ArgAction::Set) - /// .multiple_values(true)) + /// .number_of_values(1..)) /// .get_matches_from(vec![ /// "prog", "-o", "val1", "val2", "val3", /// ]); @@ -1728,7 +1566,7 @@ impl<'help> Arg<'help> { /// Sentinel to **stop** parsing multiple values of a given argument. /// /// By default when - /// one sets [`multiple_values(true)`] on an argument, clap will continue parsing values for that + /// one sets [`number_of_values(1..)`] on an argument, clap will continue parsing values for that /// argument until it reaches another valid argument, or one of the other more specific settings /// for multiple values is used (such as [`number_of_values`]). /// @@ -1743,7 +1581,7 @@ impl<'help> Arg<'help> { /// # use clap::{Command, Arg, ArgAction}; /// Arg::new("vals") /// .action(ArgAction::Set) - /// .multiple_values(true) + /// .number_of_values(1..) /// .value_terminator(";") /// # ; /// ``` @@ -1756,7 +1594,7 @@ impl<'help> Arg<'help> { /// let m = Command::new("prog") /// .arg(Arg::new("cmds") /// .action(ArgAction::Set) - /// .multiple_values(true) + /// .number_of_values(1..) /// .allow_hyphen_values(true) /// .value_terminator(";")) /// .arg(Arg::new("location")) @@ -1769,7 +1607,7 @@ impl<'help> Arg<'help> { /// ``` /// [options]: Arg::takes_value() /// [positional arguments]: Arg::index() - /// [`multiple_values(true)`]: Arg::multiple_values() + /// [`number_of_values(1..)`]: Arg::number_of_values() /// [`number_of_values`]: Arg::number_of_values() #[inline] #[must_use] @@ -1793,11 +1631,11 @@ impl<'help> Arg<'help> { /// may not be exactly what you are expecting and using [`crate::Command::trailing_var_arg`] /// may be more appropriate. /// - /// **NOTE:** Implicitly sets [`Arg::action(ArgAction::Set)`] [`Arg::multiple_values(true)`], + /// **NOTE:** Implicitly sets [`Arg::action(ArgAction::Set)`] [`Arg::number_of_values(1..)`], /// [`Arg::allow_hyphen_values(true)`], and [`Arg::last(true)`] when set to `true`. /// /// [`Arg::action(ArgAction::Set)`]: Arg::takes_value() - /// [`Arg::multiple_values(true)`]: Arg::multiple_values() + /// [`Arg::number_of_values(1..)`]: Arg::number_of_values() /// [`Arg::allow_hyphen_values(true)`]: Arg::allow_hyphen_values() /// [`Arg::last(true)`]: Arg::last() #[inline] @@ -2170,7 +2008,7 @@ impl<'help> Arg<'help> { /// .long("flag") /// .env("MY_FLAG_MULTI") /// .action(ArgAction::Set) - /// .multiple_values(true) + /// .number_of_values(1..) /// .use_value_delimiter(true)) /// .get_matches_from(vec![ /// "prog" @@ -4131,7 +3969,7 @@ impl<'help> Arg<'help> { self.is_set(ArgSettings::Required) } - /// Report whether [`Arg::multiple_values`] is set + /// Report whether [`Arg::number_of_values`] allows multiple values pub fn is_multiple_values_set(&self) -> bool { self.is_set(ArgSettings::MultipleValues) } @@ -4531,7 +4369,7 @@ pub(crate) fn render_arg_val(arg: &Arg) -> String { let mut extra_values = false; debug_assert!(arg.is_takes_value_set()); - let num_vals = arg.num_vals.unwrap_or_else(|| { + let num_vals = arg.get_num_vals().unwrap_or_else(|| { if arg.is_multiple_values_set() { (1..).into() } else { @@ -4547,7 +4385,7 @@ pub(crate) fn render_arg_val(arg: &Arg) -> String { } rendered.push_str(&arg_name); } - extra_values |= arg.num_vals.is_none() && arg.is_multiple_values_set(); + extra_values |= arg.get_num_vals().is_none() && arg.is_multiple_values_set(); extra_values |= min < num_vals.max_values(); } else { debug_assert!(1 < val_names.len()); @@ -4659,7 +4497,7 @@ mod test { let mut o = Arg::new("opt") .long("option") .action(ArgAction::Set) - .multiple_values(true); + .number_of_values(1..); o._build(); assert_eq!(o.to_string(), "--option ..."); @@ -4737,12 +4575,12 @@ mod test { fn option_display3() { let mut o = Arg::new("opt") .short('o') - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Set) .value_names(&["file", "name"]); o._build(); - assert_eq!(o.to_string(), "-o "); + assert_eq!(o.to_string(), "-o ..."); } #[test] @@ -4795,7 +4633,7 @@ mod test { #[test] fn positional_display_multiple_values() { - let mut p = Arg::new("pos").index(1).multiple_values(true); + let mut p = Arg::new("pos").index(1).number_of_values(1..); p._build(); assert_eq!(p.to_string(), "..."); diff --git a/src/builder/command.rs b/src/builder/command.rs index 9d25a79ff7f..2187d727086 100644 --- a/src/builder/command.rs +++ b/src/builder/command.rs @@ -2016,8 +2016,7 @@ impl<'help> Command<'help> { /// /// The values of the trailing positional argument will contain all args from itself on. /// - /// **NOTE:** The final positional argument **must** have [`Arg::multiple_values(true)`] or the usage - /// string equivalent. + /// **NOTE:** The final positional argument **must** have [`Arg::number_of_values(..)`]. /// /// # Examples /// @@ -2031,7 +2030,7 @@ impl<'help> Command<'help> { /// let trail: Vec<_> = m.get_many::("cmd").unwrap().collect(); /// assert_eq!(trail, ["arg1", "-r", "val1"]); /// ``` - /// [`Arg::multiple_values(true)`]: crate::Arg::multiple_values() + /// [`Arg::number_of_values(true)`]: crate::Arg::number_of_values() pub fn trailing_var_arg(self, yes: bool) -> Self { if yes { self.setting(AppSettings::TrailingVarArg) @@ -2117,7 +2116,7 @@ impl<'help> Command<'help> { /// .allow_missing_positional(true) /// .arg(Arg::new("foo")) /// .arg(Arg::new("bar")) - /// .arg(Arg::new("baz").action(ArgAction::Set).multiple_values(true)) + /// .arg(Arg::new("baz").action(ArgAction::Set).number_of_values(1..)) /// .get_matches_from(vec![ /// "prog", "foo", "bar", "baz1", "baz2", "baz3" /// ]); @@ -2136,7 +2135,7 @@ impl<'help> Command<'help> { /// .allow_missing_positional(true) /// .arg(Arg::new("foo")) /// .arg(Arg::new("bar")) - /// .arg(Arg::new("baz").action(ArgAction::Set).multiple_values(true)) + /// .arg(Arg::new("baz").action(ArgAction::Set).number_of_values(1..)) /// .get_matches_from(vec![ /// "prog", "--", "baz1", "baz2", "baz3" /// ]); @@ -2832,7 +2831,7 @@ impl<'help> Command<'help> { /// let cmd = Command::new("cmd").subcommand(Command::new("sub")).arg( /// Arg::new("arg") /// .long("arg") - /// .multiple_values(true) + /// .number_of_values(1..) /// .action(ArgAction::Set), /// ); /// @@ -4255,7 +4254,7 @@ To change `help`s short, call `cmd.arg(Arg::new(\"help\")...)`.", Arg::new("subcommand") .index(1) .action(ArgAction::Append) - .multiple_values(true) + .number_of_values(..) .value_name("SUBCOMMAND") .help("The subcommand whose help message to display"), ); diff --git a/src/builder/debug_asserts.rs b/src/builder/debug_asserts.rs index 552000d93ab..ae4bbf74b82 100644 --- a/src/builder/debug_asserts.rs +++ b/src/builder/debug_asserts.rs @@ -131,7 +131,7 @@ pub(crate) fn assert_app(cmd: &Command) { panic!( "Command {}: Argument '{}' has the same index as '{}' \ and they are both positional arguments\n\n\t \ - Use Arg::multiple_values(true) to allow one \ + Use Arg::number_of_values(1..) to allow one \ positional argument to take multiple values", cmd.get_name(), first.name, @@ -517,7 +517,7 @@ fn _verify_positionals(cmd: &Command) -> bool { || last.is_last_set(); assert!( ok, - "When using a positional argument with .multiple_values(true) that is *not the \ + "When using a positional argument with .number_of_values(1..) that is *not the \ last* positional argument, the last positional argument (i.e. the one \ with the highest index) *must* have .required(true) or .last(true) set." ); @@ -527,13 +527,15 @@ fn _verify_positionals(cmd: &Command) -> bool { assert!( ok, "Only the last positional argument, or second to last positional \ - argument may be set to .multiple_values(true)" + argument may be set to .number_of_values(1..)" ); // Next we check how many have both Multiple and not a specific number of values set let count = cmd .get_positionals() - .filter(|p| p.is_multiple_values_set() && p.num_vals.is_none()) + .filter(|p| { + p.is_multiple_values_set() && !p.num_vals.map(|r| r.is_fixed()).unwrap_or(false) + }) .count(); let ok = count <= 1 || (last.is_last_set() @@ -542,7 +544,7 @@ fn _verify_positionals(cmd: &Command) -> bool { && count == 2); assert!( ok, - "Only one positional argument with .multiple_values(true) set is allowed per \ + "Only one positional argument with .number_of_values(1..) set is allowed per \ command, unless the second one also has .last(true) set" ); } diff --git a/src/builder/value_hint.rs b/src/builder/value_hint.rs index 7c35d1eb3e5..5097f1aff1b 100644 --- a/src/builder/value_hint.rs +++ b/src/builder/value_hint.rs @@ -48,12 +48,12 @@ pub enum ValueHint { /// common when writing shell wrappers that execute anther command, for example `sudo` or `env`. /// /// This hint is special, the argument must be a positional argument and have - /// [`.multiple_values(true)`] and Command must use [`Command::trailing_var_arg(true)`]. The result is that the + /// [`.number_of_values(1..)`] and Command must use [`Command::trailing_var_arg(true)`]. The result is that the /// command line `my_app ls -la /` will be parsed as `["ls", "-la", "/"]` and clap won't try to /// parse the `-la` argument itself. /// /// [`Command::trailing_var_arg(true)`]: crate::Command::trailing_var_arg - /// [`.multiple_values(true)`]: crate::Arg::multiple_values() + /// [`.number_of_values(1..)`]: crate::Arg::number_of_values() CommandWithArguments, /// Name of a local operating system user. Username, diff --git a/src/macros.rs b/src/macros.rs index 426189e6199..ca13ffa60d6 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -412,7 +412,7 @@ macro_rules! arg_impl { @arg ({ if $arg.get_long().is_none() && $arg.get_short().is_none() { - $arg.multiple_values(true) + $arg.number_of_values(1..) // Allow collecting arguments interleaved with flags .action($crate::ArgAction::Append) } else if $arg.is_takes_value_set() { diff --git a/src/parser/arg_matcher.rs b/src/parser/arg_matcher.rs index a2599ea2e4a..436e9914301 100644 --- a/src/parser/arg_matcher.rs +++ b/src/parser/arg_matcher.rs @@ -197,20 +197,16 @@ impl ArgMatcher { } pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool { - let num_resolved = self.get(&o.id).map(|ma| ma.num_vals()).unwrap_or(0); let num_pending = self .pending .as_ref() .and_then(|p| (p.id == o.id).then(|| p.raw_vals.len())) .unwrap_or(0); - let current_num = num_resolved + num_pending; debug!( - "ArgMatcher::needs_more_vals: o={}, resolved={}, pending={}", - o.name, num_resolved, num_pending + "ArgMatcher::needs_more_vals: o={}, pending={}", + o.name, num_pending ); - if current_num == 0 { - true - } else if let Some(expected) = o.num_vals { + if let Some(expected) = o.get_num_vals() { debug!( "ArgMatcher::needs_more_vals: expected={}, actual={}", expected, num_pending diff --git a/src/parser/matches/arg_matches.rs b/src/parser/matches/arg_matches.rs index c2b6f2e8135..c4ce0e9838b 100644 --- a/src/parser/matches/arg_matches.rs +++ b/src/parser/matches/arg_matches.rs @@ -263,9 +263,8 @@ impl ArgMatches { /// let mut m = Command::new("myprog") /// .arg(Arg::new("file") /// .action(ArgAction::Append) - /// .multiple_values(true) - /// .required(true) - /// .action(ArgAction::Set)) + /// .number_of_values(1..) + /// .required(true)) /// .get_matches_from(vec![ /// "myprog", "file1.txt", "file2.txt", "file3.txt", "file4.txt", /// ]); @@ -545,7 +544,7 @@ impl ArgMatches { /// .arg(Arg::new("option") /// .short('o') /// .use_value_delimiter(true) - /// .multiple_values(true)) + /// .number_of_values(1..)) /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); /// // ARGV indices: ^0 ^1 /// // clap indices: ^2 ^3 ^4 @@ -586,8 +585,7 @@ impl ArgMatches { /// let m = Command::new("myapp") /// .arg(Arg::new("option") /// .short('o') - /// .use_value_delimiter(true) - /// .multiple_values(true)) + /// .use_value_delimiter(true)) /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); /// // ARGV indices: ^0 ^1 /// // clap indices: ^2 ^3 ^4 @@ -628,7 +626,7 @@ impl ArgMatches { /// .arg(Arg::new("option") /// .short('o') /// .action(ArgAction::Set) - /// .multiple_values(true)) + /// .number_of_values(1..)) /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); /// // ARGV indices: ^0 ^1 /// // clap indices: ^2 @@ -1328,7 +1326,7 @@ impl<'a> Default for GroupedValues<'a> { /// let m = Command::new("myapp") /// .arg(Arg::new("output") /// .short('o') -/// .multiple_values(true) +/// .number_of_values(1..) /// .action(ArgAction::Set)) /// .get_matches_from(vec!["myapp", "-o", "val1", "val2"]); /// @@ -1424,7 +1422,7 @@ mod tests { .arg( crate::Arg::new("POTATO") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .required(true), ) .try_get_matches_from(["test", "one"]) @@ -1441,7 +1439,7 @@ mod tests { .arg( crate::Arg::new("POTATO") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .value_parser(crate::builder::ValueParser::os_string()) .required(true), ) @@ -1459,7 +1457,7 @@ mod tests { .arg( crate::Arg::new("POTATO") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .required(true), ) .try_get_matches_from(["test", "one"]) diff --git a/src/parser/validator.rs b/src/parser/validator.rs index 4f64215c58a..173c325e450 100644 --- a/src/parser/validator.rs +++ b/src/parser/validator.rs @@ -270,7 +270,7 @@ impl<'help, 'cmd> Validator<'help, 'cmd> { )); } - if let Some(expected) = a.num_vals { + if let Some(expected) = a.get_num_vals() { if let Some(expected) = expected.num_values() { if expected != actual { debug!( diff --git a/tests/builder/app_settings.rs b/tests/builder/app_settings.rs index 23bf93eb9ae..46e49d81433 100644 --- a/tests/builder/app_settings.rs +++ b/tests/builder/app_settings.rs @@ -1173,7 +1173,7 @@ fn aaos_opts_mult() { let res = Command::new("posix") .arg( arg!(--opt ... "some option") - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ) .try_get_matches_from(vec![ diff --git a/tests/builder/delimiters.rs b/tests/builder/delimiters.rs index 78f416bfc2d..91c296e52d5 100644 --- a/tests/builder/delimiters.rs +++ b/tests/builder/delimiters.rs @@ -87,7 +87,7 @@ fn opt_s_no_space_mult_no_delim() { Arg::new("option") .short('o') .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec!["", "-o", "val1,val2,val3"]); @@ -108,7 +108,7 @@ fn opt_eq_mult_def_delim() { Arg::new("option") .long("opt") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .use_value_delimiter(true), ) .try_get_matches_from(vec!["", "--opt=val1,val2,val3"]); diff --git a/tests/builder/env.rs b/tests/builder/env.rs index 71184d9259b..ffc09f1fa90 100644 --- a/tests/builder/env.rs +++ b/tests/builder/env.rs @@ -230,7 +230,7 @@ fn multiple_one() { .env("CLP_TEST_ENV_MO") .action(ArgAction::Set) .use_value_delimiter(true) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec![""]); @@ -256,7 +256,7 @@ fn multiple_three() { .env("CLP_TEST_ENV_MULTI1") .action(ArgAction::Set) .use_value_delimiter(true) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec![""]); @@ -281,7 +281,7 @@ fn multiple_no_delimiter() { arg!([arg] "some opt") .env("CLP_TEST_ENV_MULTI2") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec![""]); diff --git a/tests/builder/flag_subcommands.rs b/tests/builder/flag_subcommands.rs index 0b53597dd84..04fbe56e727 100644 --- a/tests/builder/flag_subcommands.rs +++ b/tests/builder/flag_subcommands.rs @@ -526,7 +526,7 @@ fn flag_subcommand_long_short_normal_usage_string() { .help("search locally installed packages for matching strings") .conflicts_with("info") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .arg( Arg::new("info") @@ -535,7 +535,7 @@ fn flag_subcommand_long_short_normal_usage_string() { .conflicts_with("search") .help("view package information") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ), ); utils::assert_output(cmd, "pacman -Qh", FLAG_SUBCOMMAND_HELP, false); @@ -574,7 +574,7 @@ fn flag_subcommand_long_normal_usage_string() { .help("search locally installed packages for matching strings") .conflicts_with("info") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .arg( Arg::new("info") @@ -583,7 +583,7 @@ fn flag_subcommand_long_normal_usage_string() { .conflicts_with("search") .help("view package information") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ), ); utils::assert_output( @@ -627,7 +627,7 @@ fn flag_subcommand_short_normal_usage_string() { .help("search locally installed packages for matching strings") .conflicts_with("info") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .arg( Arg::new("info") @@ -636,7 +636,7 @@ fn flag_subcommand_short_normal_usage_string() { .conflicts_with("search") .help("view package information") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ), ); utils::assert_output( diff --git a/tests/builder/grouped_values.rs b/tests/builder/grouped_values.rs index d740a2ff6bc..56646630119 100644 --- a/tests/builder/grouped_values.rs +++ b/tests/builder/grouped_values.rs @@ -9,7 +9,7 @@ fn grouped_value_works() { Arg::new("option") .long("option") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ) .try_get_matches_from(&[ @@ -41,7 +41,7 @@ fn issue_1026() { Arg::new("target") .long("target") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ) .try_get_matches_from(&[ @@ -69,7 +69,7 @@ fn grouped_value_long_flag_delimiter() { .long("option") .action(ArgAction::Set) .use_value_delimiter(true) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ) .try_get_matches_from(vec![ @@ -99,7 +99,7 @@ fn grouped_value_short_flag_delimiter() { .short('o') .action(ArgAction::Set) .use_value_delimiter(true) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ) .try_get_matches_from(vec!["myapp", "-o=foo", "-o=val1,val2,val3", "-o=bar"]) @@ -118,7 +118,7 @@ fn grouped_value_positional_arg() { Arg::new("pos") .help("multiple positionals") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec![ "myprog", "val1", "val2", "val3", "val4", "val5", "val6", @@ -139,7 +139,7 @@ fn grouped_value_multiple_positional_arg() { Arg::new("pos2") .help("multiple positionals") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec![ "myprog", "val1", "val2", "val3", "val4", "val5", "val6", @@ -160,7 +160,7 @@ fn grouped_value_multiple_positional_arg_last_multiple() { Arg::new("pos2") .help("multiple positionals") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .last(true), ) .try_get_matches_from(vec![ @@ -177,7 +177,7 @@ fn grouped_value_multiple_positional_arg_last_multiple() { #[test] fn grouped_interleaved_positional_values() { let cmd = clap::Command::new("foo") - .arg(clap::Arg::new("pos").multiple_values(true)) + .arg(clap::Arg::new("pos").number_of_values(1..)) .arg( clap::Arg::new("flag") .short('f') @@ -200,7 +200,7 @@ fn grouped_interleaved_positional_values() { #[test] fn grouped_interleaved_positional_occurrences() { let cmd = clap::Command::new("foo") - .arg(clap::Arg::new("pos").multiple_values(true)) + .arg(clap::Arg::new("pos").number_of_values(1..)) .arg( clap::Arg::new("flag") .short('f') diff --git a/tests/builder/groups.rs b/tests/builder/groups.rs index c009ab09056..5b193c9c609 100644 --- a/tests/builder/groups.rs +++ b/tests/builder/groups.rs @@ -133,7 +133,7 @@ fn group_required_flags_empty() { #[test] fn group_multi_value_single_arg() { let res = Command::new("group") - .arg(arg!(-c --color "some option").multiple_values(true)) + .arg(arg!(-c --color "some option").number_of_values(1..)) .arg(arg!(-h --hostname "another option").required(false)) .group(ArgGroup::new("grp").args(&["hostname", "color"])) .try_get_matches_from(vec!["", "-c", "blue", "red", "green"]); diff --git a/tests/builder/help.rs b/tests/builder/help.rs index 45d5f158d02..73a6e87899d 100644 --- a/tests/builder/help.rs +++ b/tests/builder/help.rs @@ -67,7 +67,7 @@ fn help_multi_subcommand_error() { -o --option "tests options" ) .required(false) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ), ), @@ -107,13 +107,13 @@ OPTIONS: .arg( Arg::new("FIRST") .help("First") - .multiple_values(true) + .number_of_values(1..) .required(true), ) .arg( Arg::new("SECOND") .help("Second") - .multiple_values(true) + .number_of_values(1..) .required(true) .last(true), ); @@ -172,7 +172,7 @@ OPTIONS: Arg::new("pass through args") .help("Any arguments you wish to pass to the being profiled.") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .last(true) .value_name("ARGS"), ); @@ -342,7 +342,7 @@ fn multi_level_sc_help() { -o --option "tests options" ) .required(false) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ), ), @@ -981,7 +981,7 @@ OPTIONS: .arg( Arg::new("arg2") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .help("some option"), ) .arg( @@ -1003,7 +1003,7 @@ OPTIONS: .help("a label") .short('l') .long("label") - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Set), ); utils::assert_output(cmd, "myapp --help", ISSUE_702, false); @@ -1043,23 +1043,6 @@ OPTIONS: utils::assert_output(cmd, "myapp --help", LONG_ABOUT, false); } -#[test] -#[should_panic = "Argument option: mismatch between `number_of_values` (1) and `multiple_values`"] -fn number_of_values_conflicts_with_multiple_values() { - Command::new("ctest") - .version("0.1") - .arg( - Arg::new("option") - .help("tests options") - .short('o') - .long("option") - .action(ArgAction::Set) - .number_of_values(1) - .multiple_values(true), - ) - .build(); -} - static RIPGREP_USAGE: &str = "ripgrep 0.5 USAGE: @@ -1359,7 +1342,7 @@ OPTIONS: .arg( Arg::new("ARGS") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .last(true) .help("some"), ); @@ -1390,7 +1373,7 @@ OPTIONS: .arg( Arg::new("ARGS") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .last(true) .required(true) .help("some"), @@ -1428,7 +1411,7 @@ SUBCOMMANDS: .arg( Arg::new("ARGS") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .last(true) .required(true) .help("some"), @@ -1467,7 +1450,7 @@ SUBCOMMANDS: .arg( Arg::new("ARGS") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .last(true) .help("some"), ) @@ -1882,7 +1865,7 @@ OPTIONS: Arg::new("files") .value_name("FILES") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ); utils::assert_output(cmd, "demo -h", ISSUE_1364, false); @@ -2411,7 +2394,7 @@ fn missing_positional_final_multiple() { .allow_missing_positional(true) .arg(Arg::new("foo")) .arg(Arg::new("bar")) - .arg(Arg::new("baz").action(ArgAction::Set).multiple_values(true)); + .arg(Arg::new("baz").action(ArgAction::Set).number_of_values(1..)); utils::assert_output( cmd, "test --help", @@ -2438,7 +2421,7 @@ fn positional_multiple_values_is_dotted() { Arg::new("foo") .required(true) .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ); utils::assert_output( cmd, @@ -2462,7 +2445,7 @@ OPTIONS: .required(true) .action(ArgAction::Set) .value_name("BAR") - .multiple_values(true), + .number_of_values(1..), ); utils::assert_output( cmd, @@ -2488,7 +2471,7 @@ fn positional_multiple_occurrences_is_dotted() { Arg::new("foo") .required(true) .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ); utils::assert_output( @@ -2513,7 +2496,7 @@ OPTIONS: .required(true) .action(ArgAction::Set) .value_name("BAR") - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ); utils::assert_output( diff --git a/tests/builder/indices.rs b/tests/builder/indices.rs index 5b5f0369648..b670ab63d05 100644 --- a/tests/builder/indices.rs +++ b/tests/builder/indices.rs @@ -7,14 +7,14 @@ fn indices_mult_opts() { Arg::new("exclude") .short('e') .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ) .arg( Arg::new("include") .short('i') .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec!["ind", "-e", "A", "B", "-i", "B", "C", "-e", "C"]) .unwrap(); @@ -36,14 +36,14 @@ fn index_mult_opts() { Arg::new("exclude") .short('e') .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ) .arg( Arg::new("include") .short('i') .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec!["ind", "-e", "A", "B", "-i", "B", "C", "-e", "C"]) .unwrap(); @@ -136,7 +136,7 @@ fn indices_mult_opt_value_delim_eq() { .short('o') .action(ArgAction::Set) .use_value_delimiter(true) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec!["myapp", "-o=val1,val2,val3"]) .unwrap(); @@ -153,7 +153,7 @@ fn indices_mult_opt_value_no_delim_eq() { Arg::new("option") .short('o') .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec!["myapp", "-o=val1,val2,val3"]) .unwrap(); diff --git a/tests/builder/multiple_occurrences.rs b/tests/builder/multiple_occurrences.rs index ae520001fbd..9c3d939d801 100644 --- a/tests/builder/multiple_occurrences.rs +++ b/tests/builder/multiple_occurrences.rs @@ -30,7 +30,7 @@ fn multiple_occurrences_of_flags_short() { fn multiple_occurrences_of_positional() { let cmd = Command::new("test").arg( Arg::new("multi") - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ); diff --git a/tests/builder/multiple_values.rs b/tests/builder/multiple_values.rs index 5b11141f9cc..2e764315e7a 100644 --- a/tests/builder/multiple_values.rs +++ b/tests/builder/multiple_values.rs @@ -8,7 +8,7 @@ fn option_long() { .long("option") .help("multiple options") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ) .try_get_matches_from(vec![ @@ -36,7 +36,7 @@ fn option_short() { .short('o') .help("multiple options") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ) .try_get_matches_from(vec!["", "-o", "val1", "-o", "val2", "-o", "val3"]); @@ -63,7 +63,7 @@ fn option_mixed() { .short('o') .help("multiple options") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ) .try_get_matches_from(vec![ @@ -448,7 +448,7 @@ fn positional() { Arg::new("pos") .help("multiple positionals") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec!["myprog", "val1", "val2", "val3"]); @@ -875,14 +875,14 @@ fn req_delimiter_long() { .arg( Arg::new("option") .long("option") - .multiple_values(true) + .number_of_values(1..) .use_value_delimiter(true) .require_value_delimiter(true), ) .arg( Arg::new("args") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .index(1), ) .try_get_matches_from(vec!["", "--option", "val1", "val2", "val3"]); @@ -913,14 +913,14 @@ fn req_delimiter_long_with_equal() { .arg( Arg::new("option") .long("option") - .multiple_values(true) + .number_of_values(1..) .use_value_delimiter(true) .require_value_delimiter(true), ) .arg( Arg::new("args") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .index(1), ) .try_get_matches_from(vec!["", "--option=val1", "val2", "val3"]); @@ -951,14 +951,14 @@ fn req_delimiter_short_with_space() { .arg( Arg::new("option") .short('o') - .multiple_values(true) + .number_of_values(1..) .use_value_delimiter(true) .require_value_delimiter(true), ) .arg( Arg::new("args") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .index(1), ) .try_get_matches_from(vec!["", "-o", "val1", "val2", "val3"]); @@ -989,14 +989,14 @@ fn req_delimiter_short_with_no_space() { .arg( Arg::new("option") .short('o') - .multiple_values(true) + .number_of_values(1..) .use_value_delimiter(true) .require_value_delimiter(true), ) .arg( Arg::new("args") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .index(1), ) .try_get_matches_from(vec!["", "-oval1", "val2", "val3"]); @@ -1027,14 +1027,14 @@ fn req_delimiter_short_with_equal() { .arg( Arg::new("option") .short('o') - .multiple_values(true) + .number_of_values(1..) .use_value_delimiter(true) .require_value_delimiter(true), ) .arg( Arg::new("args") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .index(1), ) .try_get_matches_from(vec!["", "-o=val1", "val2", "val3"]); @@ -1066,12 +1066,12 @@ fn req_delimiter_complex() { Arg::new("option") .long("option") .short('o') - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append) .use_value_delimiter(true) .require_value_delimiter(true), ) - .arg(Arg::new("args").multiple_values(true).index(1)) + .arg(Arg::new("args").number_of_values(1..).index(1)) .try_get_matches_from(vec![ "", "val1", @@ -1131,7 +1131,7 @@ fn req_delimiter_complex() { #[cfg(debug_assertions)] #[test] #[should_panic = "When using a positional argument with \ -.multiple_values(true) that is *not the last* positional argument, the last \ +.number_of_values(1..) that is *not the last* positional argument, the last \ positional argument (i.e. the one with the highest index) *must* have \ .required(true) or .last(true) set."] fn low_index_positional_not_required() { @@ -1141,7 +1141,7 @@ fn low_index_positional_not_required() { .index(1) .action(ArgAction::Set) .required(true) - .multiple_values(true), + .number_of_values(1..), ) .arg(Arg::new("target").index(2)) .try_get_matches_from(vec![""]); @@ -1150,7 +1150,7 @@ fn low_index_positional_not_required() { // This tests a programmer error and will only succeed with debug_assertions #[cfg(debug_assertions)] #[test] -#[should_panic = "Only one positional argument with .multiple_values(true) \ +#[should_panic = "Only one positional argument with .number_of_values(1..) \ set is allowed per command, unless the second one also has .last(true) set"] fn low_index_positional_last_multiple_too() { let _ = Command::new("lip") @@ -1159,14 +1159,14 @@ fn low_index_positional_last_multiple_too() { .index(1) .action(ArgAction::Set) .required(true) - .multiple_values(true), + .number_of_values(1..), ) .arg( Arg::new("target") .index(2) .action(ArgAction::Set) .required(true) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec![""]); } @@ -1175,7 +1175,7 @@ fn low_index_positional_last_multiple_too() { #[cfg(debug_assertions)] #[test] #[should_panic = "Only the last positional argument, or second to \ -last positional argument may be set to .multiple_values(true)"] +last positional argument may be set to .number_of_values(1..)"] fn low_index_positional_too_far_back() { let _ = Command::new("lip") .arg( @@ -1183,7 +1183,7 @@ fn low_index_positional_too_far_back() { .index(1) .action(ArgAction::Set) .required(true) - .multiple_values(true), + .number_of_values(1..), ) .arg(Arg::new("target").required(true).index(2)) .arg(Arg::new("target2").required(true).index(3)) @@ -1198,7 +1198,7 @@ fn low_index_positional() { .index(1) .action(ArgAction::Set) .required(true) - .multiple_values(true), + .number_of_values(1..), ) .arg(Arg::new("target").index(2).required(true)) .try_get_matches_from(vec!["lip", "file1", "file2", "file3", "target"]); @@ -1231,7 +1231,7 @@ fn low_index_positional_in_subcmd() { .index(1) .action(ArgAction::Set) .required(true) - .multiple_values(true), + .number_of_values(1..), ) .arg(Arg::new("target").index(2).required(true)), ) @@ -1264,7 +1264,7 @@ fn low_index_positional_with_option() { .required(true) .index(1) .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .arg(Arg::new("target").index(2).required(true)) .arg(Arg::new("opt").long("option").action(ArgAction::Set)) @@ -1302,7 +1302,7 @@ fn low_index_positional_with_flag() { .index(1) .action(ArgAction::Set) .required(true) - .multiple_values(true), + .number_of_values(1..), ) .arg(Arg::new("target").index(2).required(true)) .arg(Arg::new("flg").long("flag").action(ArgAction::SetTrue)) @@ -1333,7 +1333,7 @@ fn low_index_positional_with_extra_flags() { .arg(Arg::new("yes").long("yes").action(ArgAction::SetTrue)) .arg(Arg::new("one").long("one").action(ArgAction::Set)) .arg(Arg::new("two").long("two").action(ArgAction::Set)) - .arg(Arg::new("input").multiple_values(true).required(true)) + .arg(Arg::new("input").number_of_values(1..).required(true)) .arg(Arg::new("output").required(true)); let m = cmd.try_get_matches_from([ "test", "--one", "1", "--two", "2", "3", "4", "5", "6", "7", "8", @@ -1370,7 +1370,7 @@ fn multiple_value_terminator_option() { .short('f') .value_terminator(";") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .arg(Arg::new("other")) .try_get_matches_from(vec!["lip", "-f", "val1", "val2", ";", "otherval"]); @@ -1401,7 +1401,7 @@ fn multiple_value_terminator_option_other_arg() { .short('f') .value_terminator(";") .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ) .arg(Arg::new("other")) .arg(Arg::new("flag").short('F').action(ArgAction::SetTrue)) @@ -1432,7 +1432,7 @@ fn multiple_vals_with_hyphen() { .arg( Arg::new("cmds") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .allow_hyphen_values(true) .value_terminator(";"), ) diff --git a/tests/builder/opts.rs b/tests/builder/opts.rs index 0c6ba9f0708..92916731c99 100644 --- a/tests/builder/opts.rs +++ b/tests/builder/opts.rs @@ -177,7 +177,7 @@ fn opts_using_short() { #[test] fn lots_o_vals() { let r = Command::new("opts") - .arg(arg!(o: -o "some opt").multiple_values(true)) + .arg(arg!(o: -o "some opt").number_of_values(1..)) .try_get_matches_from(vec![ "", "-o", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", "some", @@ -338,7 +338,7 @@ fn multiple_vals_pos_arg_delim() { let r = Command::new("mvae") .arg( arg!(o: -o "some opt") - .multiple_values(true) + .number_of_values(1..) .use_value_delimiter(true), ) .arg(arg!([file] "some file")) @@ -380,7 +380,7 @@ fn require_delims() { let r = Command::new("mvae") .arg( arg!(o: -o "some opt") - .multiple_values(true) + .number_of_values(1..) .use_value_delimiter(true) .require_value_delimiter(true), ) @@ -408,7 +408,7 @@ fn leading_hyphen_pass() { let r = Command::new("mvae") .arg( arg!(o: -o "some opt") - .multiple_values(true) + .number_of_values(1..) .allow_hyphen_values(true), ) .try_get_matches_from(vec!["", "-o", "-2", "3"]); @@ -439,7 +439,7 @@ fn leading_hyphen_with_flag_after() { let r = Command::new("mvae") .arg( arg!(o: -o "some opt") - .multiple_values(true) + .number_of_values(1..) .allow_hyphen_values(true), ) .arg(arg!(f: -f "some flag").action(ArgAction::SetTrue)) diff --git a/tests/builder/positionals.rs b/tests/builder/positionals.rs index 7490a238b7d..41e24d15ed7 100644 --- a/tests/builder/positionals.rs +++ b/tests/builder/positionals.rs @@ -121,7 +121,7 @@ fn positional_multiple() { Arg::new("positional") .index(1) .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ]) .try_get_matches_from(vec!["", "-f", "test1", "test2", "test3"]); assert!(r.is_ok(), "{:#?}", r); @@ -145,7 +145,7 @@ fn positional_multiple_3() { Arg::new("positional") .index(1) .action(ArgAction::Set) - .multiple_values(true), + .number_of_values(1..), ]) .try_get_matches_from(vec!["", "test1", "test2", "test3", "--flag"]); assert!(r.is_ok(), "{:#?}", r); @@ -330,7 +330,7 @@ fn ignore_hyphen_values_on_last() { let cmd = clap::Command::new("foo") .arg( clap::Arg::new("cmd") - .multiple_values(true) + .number_of_values(1..) .last(true) .allow_hyphen_values(true), ) diff --git a/tests/builder/possible_values.rs b/tests/builder/possible_values.rs index a65f75a1d7a..a0e17a7ce0d 100644 --- a/tests/builder/possible_values.rs +++ b/tests/builder/possible_values.rs @@ -90,7 +90,7 @@ fn possible_values_of_positional_multiple() { .index(1) .action(ArgAction::Set) .value_parser(["test123", "test321"]) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec!["myprog", "test123", "test321"]); @@ -115,7 +115,7 @@ fn possible_values_of_positional_multiple_fail() { .index(1) .action(ArgAction::Set) .value_parser(["test123", "test321"]) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec!["myprog", "test123", "notest"]); @@ -394,7 +394,7 @@ fn ignore_case_multiple() { .long("option") .action(ArgAction::Set) .value_parser(["test123", "test321"]) - .multiple_values(true) + .number_of_values(1..) .ignore_case(true), ) .try_get_matches_from(vec!["pv", "--option", "TeSt123", "teST123", "tESt321"]); @@ -419,7 +419,7 @@ fn ignore_case_multiple_fail() { .long("option") .action(ArgAction::Set) .value_parser(["test123", "test321"]) - .multiple_values(true), + .number_of_values(1..), ) .try_get_matches_from(vec!["pv", "--option", "test123", "teST123", "test321"]); diff --git a/tests/builder/subcommands.rs b/tests/builder/subcommands.rs index 879d92cb79f..cb7d7bb873f 100644 --- a/tests/builder/subcommands.rs +++ b/tests/builder/subcommands.rs @@ -304,7 +304,7 @@ fn issue_1161_multiple_hyphen_hyphen() { .arg( Arg::new("slop") .action(ArgAction::Set) - .multiple_values(true) + .number_of_values(1..) .last(true), ) .try_get_matches_from(vec![ diff --git a/tests/builder/utils.rs b/tests/builder/utils.rs index 55ab1ebe774..9cf31c1a304 100644 --- a/tests/builder/utils.rs +++ b/tests/builder/utils.rs @@ -49,7 +49,7 @@ pub fn complex_app() -> Command<'static> { -o --option "tests options" ) .required(false) - .multiple_values(true) + .number_of_values(1..) .action(ArgAction::Append), ) .arg(arg!([positional] "tests positionals")) @@ -100,7 +100,7 @@ pub fn complex_app() -> Command<'static> { .arg( arg!(-o --option "tests options") .required(false) - .multiple_values(true), + .number_of_values(1..), ) .arg(arg!(-s --subcmdarg "tests other args").required(false)) .arg(arg!([scpositional] "tests positionals")), diff --git a/tests/derive/options.rs b/tests/derive/options.rs index 1ebbf6d7a97..d41dab2dc33 100644 --- a/tests/derive/options.rs +++ b/tests/derive/options.rs @@ -369,7 +369,7 @@ fn vec_type_with_required() { fn vec_type_with_multiple_values_only() { #[derive(Parser, PartialEq, Debug)] struct Opt { - #[clap(short, long, multiple_values(true))] + #[clap(short, long, number_of_values(1..))] arg: Vec, } assert_eq!( @@ -429,7 +429,7 @@ fn option_vec_type() { fn option_vec_type_structopt_behavior() { #[derive(Parser, PartialEq, Debug)] struct Opt { - #[clap(short, long, multiple_values(true), number_of_values(0..))] + #[clap(short, long, number_of_values(0..))] arg: Option>, } assert_eq!(