Repository: clap-rs/clap
Pull request #4020 (2022-08-03 15:36:18)

fix!: Replace multiple_values with number_of_values 
This reduces ambiguity in how the different "multiple" parts of the API
interact and lowrs the amount of API surface area users have to dig
through to use clap.

For now, this is only a matter of cleaning up the public API.  Cleaning
up the implementation is the next step.

This is part of #2688


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b247fd1c..f9ade3d6 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 c22c279e..bd9583f4 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 <minvals> ... "Tests 2 min vals").number_of_values(2..).multiple_values(true).required(false),
-                arg!(--maxvals3 <maxvals> ... "Tests 3 max vals").number_of_values(1..=3).multiple_values(true).required(false),
+                ).required(false).value_names(&["one", "two"]),
+                arg!(--minvals2 <minvals> ... "Tests 2 min vals").number_of_values(2..).required(false),
+                arg!(--maxvals3 <maxvals> ... "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 513c3437..cbc5d36c 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 3fd83b51..519471aa 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 127c69f0..96196411 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 5dd5b3f9..e5062227 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_derive/src/derives/args.rs b/clap_derive/src/derives/args.rs
index 81de7a01..689a2418 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/examples/escaped-positional.rs b/examples/escaped-positional.rs
index 02420010..e0505b9d 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 6f02c30e..f532bc68 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 7425368f..da037358 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::<String>("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=<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::<String>("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::<String>("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::<String>("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::<String>("file").unwrap().collect();
-    /// assert_eq!(files, ["file1", "file2", "file3"]);
-    /// assert_eq!(m.get_one::<String>("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::<String>("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<ValuesRange>) -> 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 <opt>...");
@@ -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 <file> <name>");
+        assert_eq!(o.to_string(), "-o <file> <name>...");
     }
 
     #[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(), "<pos>...");
diff --git a/src/builder/command.rs b/src/builder/command.rs
index 9d25a79f..2187d727 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::<String>("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 552000d9..ae4bbf74 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 7c35d1eb..5097f1af 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 426189e6..ca13ffa6 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 a2599ea2..436e9914 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 c2b6f2e8..c4ce0e98 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 4f64215c..173c325e 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!(


Test patch:
diff --git a/clap_complete/tests/common.rs b/clap_complete/tests/common.rs
index 13af2fcc..f1d03238 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 2a5b11c7..0aa37b4c 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 <SUBCOMMAND>..."
+            opts="-c [<SUBCOMMAND>...]"
             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 98918ca4..af529269 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="<SUBCOMMAND>..."
+            opts="[<SUBCOMMAND>...]"
             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 ead2b13b..a4ae43a2 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="<SUBCOMMAND>..."
+            opts="[<SUBCOMMAND>...]"
             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 33f99ad0..bb603b5b 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="<SUBCOMMAND>..."
+            opts="[<SUBCOMMAND>...]"
             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 85729508..c96561de 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="<SUBCOMMAND>..."
+            opts="[<SUBCOMMAND>...]"
             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="<SUBCOMMAND>..."
+            opts="[<SUBCOMMAND>...]"
             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 13af2fcc..f1d03238 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_mangen/tests/common.rs b/clap_mangen/tests/common.rs
index 55c5c5fc..025ffef9 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/tests/builder/app_settings.rs b/tests/builder/app_settings.rs
index 23bf93eb..46e49d81 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 <val> ... "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 78f416bf..91c296e5 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 71184d92..ffc09f1f 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 0b53597d..04fbe56e 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 d740a2ff..56646630 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 c009ab09..5b193c9c 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 <color> "some option").multiple_values(true))
+        .arg(arg!(-c --color <color> "some option").number_of_values(1..))
         .arg(arg!(-h --hostname <name> "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 45d5f158..73a6e878 100644
--- a/tests/builder/help.rs
+++ b/tests/builder/help.rs
@@ -67,7 +67,7 @@ fn help_multi_subcommand_error() {
                         -o --option <scoption>    "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 <scoption>    "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 5b5f0369..b670ab63 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 ae520001..9c3d939d 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 5b11141f..2e764315 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 0c6ba9f0..92916731 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 <opt> "some opt").multiple_values(true))
+        .arg(arg!(o: -o <opt> "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 <opt> "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 <opt> "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 <opt> "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 <opt> "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 7490a238..41e24d15 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 a65f75a1..a0e17a7c 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 879d92cb..cb7d7bb8 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 55ab1ebe..9cf31c1a 100644
--- a/tests/builder/utils.rs
+++ b/tests/builder/utils.rs
@@ -49,7 +49,7 @@ pub fn complex_app() -> Command<'static> {
                 -o --option <opt> "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 <scoption> "tests options")
                         .required(false)
-                        .multiple_values(true),
+                        .number_of_values(1..),
                 )
                 .arg(arg!(-s --subcmdarg <subcmdarg> "tests other args").required(false))
                 .arg(arg!([scpositional] "tests positionals")),
diff --git a/tests/derive/options.rs b/tests/derive/options.rs
index 1ebbf6d7..d41dab2d 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<i32>,
     }
     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<Vec<i32>>,
     }
     assert_eq!(