Repository: clap-rs/clap
Pull request #2346 (2021-02-13 16:56:47)

Fix part of the non_fmt_panic warnings, bump version-sync to 0.9.2
Remove recent nightly test warnings, some of the warnings originates from version-sync.

Related: https://github.com/mgeisler/version-sync/issues/103, https://github.com/rust-lang/rust/pull/81645


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e69b014..e0660b25 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,9 +10,6 @@ TODO: `cargo`, `std` features
 
 #### BREAKING CHANGES
 
-* **Removed Methods**
-  * **Arg**
-    * `Arg::settings` in favor of `Arg::setting(Setting1 | Setting2)`
 * **Renamed Settings**
   * `AppSettings::DisableHelpFlags` => `AppSettings::DisableHelpFlag`
   * `AppSettings::DisableVersion` => `AppSettings::DisableVersionFlag`
@@ -199,7 +196,6 @@ TODO: `cargo`, `std` features
     * `Arg::multiple_values`
     * `Arg::multiple_occurrences`
     * `Arg::help_heading`
-    * `Arg::settings`
 * **Added Settings**
   * `AppSettings::HelpRequired`
   * `AppSettings::NoAutoHelp`
diff --git a/benches/03_complex.rs b/benches/03_complex.rs
index 4e152dd3..04979b42 100644
--- a/benches/03_complex.rs
+++ b/benches/03_complex.rs
@@ -67,7 +67,7 @@ pub fn build_from_builder(c: &mut Criterion) {
                         .about("tests flags")
                         .long("flag")
                         .global(true)
-                        .setting(ArgSettings::MultipleOccurrences),
+                        .settings(&[ArgSettings::MultipleOccurrences]),
                 )
                 .arg(
                     Arg::new("flag2")
diff --git a/benches/04_new_help.rs b/benches/04_new_help.rs
index 3b2f7149..f245111e 100644
--- a/benches/04_new_help.rs
+++ b/benches/04_new_help.rs
@@ -112,9 +112,11 @@ fn app_example7<'c>() -> App<'c> {
         .arg(
             Arg::new("input")
                 .about("the input file to use")
-                .setting(ArgSettings::MultipleValues)
-                .setting(ArgSettings::MultipleOccurrences)
-                .setting(ArgSettings::Required)
+                .settings(&[
+                    ArgSettings::MultipleValues,
+                    ArgSettings::MultipleOccurrences,
+                    ArgSettings::Required,
+                ])
                 .short('i')
                 .long("input")
                 .requires("config")
@@ -129,9 +131,11 @@ fn app_example8<'c>() -> App<'c> {
         .arg(
             Arg::new("input")
                 .about("the input file to use")
-                .setting(ArgSettings::MultipleValues)
-                .setting(ArgSettings::MultipleOccurrences)
-                .setting(ArgSettings::Required)
+                .settings(&[
+                    ArgSettings::MultipleValues,
+                    ArgSettings::MultipleOccurrences,
+                    ArgSettings::Required,
+                ])
                 .short('i')
                 .long("input")
                 .requires("config")
diff --git a/benches/05_ripgrep.rs b/benches/05_ripgrep.rs
index 866e8e95..ebde55e2 100644
--- a/benches/05_ripgrep.rs
+++ b/benches/05_ripgrep.rs
@@ -332,9 +332,11 @@ where
         .arg(
             flag("regexp")
                 .short('e')
-                .setting(ArgSettings::AllowHyphenValues)
-                .setting(ArgSettings::MultipleOccurrences)
-                .setting(ArgSettings::TakesValue)
+                .settings(&[
+                    ArgSettings::AllowHyphenValues,
+                    ArgSettings::MultipleOccurrences,
+                    ArgSettings::TakesValue,
+                ])
                 .value_name("pattern"),
         )
         .arg(
@@ -356,15 +358,13 @@ where
         .arg(
             flag("colors")
                 .value_name("SPEC")
-                .setting(ArgSettings::MultipleOccurrences)
-                .setting(ArgSettings::TakesValue),
+                .settings(&[ArgSettings::MultipleOccurrences, ArgSettings::TakesValue]),
         )
         .arg(flag("fixed-strings").short('F'))
         .arg(
             flag("glob")
                 .short('g')
-                .setting(ArgSettings::MultipleOccurrences)
-                .setting(ArgSettings::TakesValue)
+                .settings(&[ArgSettings::MultipleOccurrences, ArgSettings::TakesValue])
                 .value_name("GLOB"),
         )
         .arg(flag("ignore-case").short('i'))
@@ -374,15 +374,13 @@ where
         .arg(
             flag("type")
                 .short('t')
-                .setting(ArgSettings::MultipleOccurrences)
-                .setting(ArgSettings::TakesValue)
+                .settings(&[ArgSettings::MultipleOccurrences, ArgSettings::TakesValue])
                 .value_name("TYPE"),
         )
         .arg(
             flag("type-not")
                 .short('T')
-                .setting(ArgSettings::MultipleOccurrences)
-                .setting(ArgSettings::TakesValue)
+                .settings(&[ArgSettings::MultipleOccurrences, ArgSettings::TakesValue])
                 .value_name("TYPE"),
         )
         .arg(
diff --git a/benches/06_rustup.rs b/benches/06_rustup.rs
index e056aa26..907ad702 100644
--- a/benches/06_rustup.rs
+++ b/benches/06_rustup.rs
@@ -262,12 +262,11 @@ fn build_cli() -> App<'static> {
                 .after_help(RUN_HELP)
                 .setting(AppSettings::TrailingVarArg)
                 .arg(Arg::new("toolchain").setting(ArgSettings::Required))
-                .arg(
-                    Arg::new("command")
-                        .setting(ArgSettings::Required)
-                        .setting(ArgSettings::MultipleValues)
-                        .setting(ArgSettings::MultipleOccurrences),
-                ),
+                .arg(Arg::new("command").settings(&[
+                    ArgSettings::Required,
+                    ArgSettings::MultipleValues,
+                    ArgSettings::MultipleOccurrences,
+                ])),
         )
         .subcommand(
             App::new("which")
diff --git a/clap.schema.json b/clap.schema.json
index 80997e25..4fa922bd 100644
--- a/clap.schema.json
+++ b/clap.schema.json
@@ -51,6 +51,7 @@
   "definitions": {
     "arg": {
       "type": "object",
+
       "properties": {
         "about": {
           "type": "string"
@@ -314,6 +315,7 @@
       "type": "string"
     }
   },
+
   "type": "object",
   "TODO:": "set 'name' as required",
   "properties": {
diff --git a/clap_generate/Cargo.toml b/clap_generate/Cargo.toml
index 49ab533e..8497ab5c 100644
--- a/clap_generate/Cargo.toml
+++ b/clap_generate/Cargo.toml
@@ -39,7 +39,7 @@ clap = { path = "../", version = "3.0.0-beta.2" }
 
 [dev-dependencies]
 pretty_assertions = "0.6"
-version-sync = "0.8"
+version-sync = "0.9"
 
 [features]
 default = []
diff --git a/examples/16_app_settings.rs b/examples/16_app_settings.rs
index 11e3c5f0..68c06f32 100644
--- a/examples/16_app_settings.rs
+++ b/examples/16_app_settings.rs
@@ -2,8 +2,9 @@ use clap::{App, AppSettings};
 
 fn main() {
     // You can use AppSettings to change the application level behavior of clap. .setting() function
-    // of App struct takes AppSettings enum as argument. You can learn more about AppSettings in the
-    // documentation, which also has examples on each setting.
+    // of App struct takes AppSettings enum as argument. There is also .settings() function which
+    // takes slice of AppSettings enum.  You can learn more about AppSettings in the documentation,
+    // which also has examples on each setting.
     //
     // This example will only show usage of one AppSettings setting. See documentation for more
     // information.
diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs
index 6b2c93bf..c38dfcfc 100644
--- a/src/build/app/mod.rs
+++ b/src/build/app/mod.rs
@@ -918,6 +918,7 @@ impl<'help> App<'help> {
     /// # ;
     /// ```
     /// [`AppSettings`]: ./enum.AppSettings.html
+    /// [global]: ./struct.App.html#method.global_setting
     #[inline]
     pub fn unset_setting(mut self, setting: AppSettings) -> Self {
         self.settings.unset(setting);
@@ -2317,11 +2318,11 @@ impl<'help> App<'help> {
                 .collect();
 
             if !args_missing_help.is_empty() {
-                panic!(format!(
+                panic!(
                     "AppSettings::HelpRequired is enabled for the App {}, but at least one of its arguments does not have either `help` or `long_help` set. List of such arguments: {}",
                     self.name,
                     args_missing_help.join(", ")
-                ));
+                );
             }
         }
 
diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs
index 3d0f70ad..43df7466 100644
--- a/src/build/arg/mod.rs
+++ b/src/build/arg/mod.rs
@@ -3058,11 +3058,10 @@ impl<'help> Arg<'help> {
     /// # use clap::{App, Arg, ArgSettings};
     /// let res = App::new("prog")
     ///     .arg(Arg::new("cfg")
-    ///         .setting(ArgSettings::Required)
-    ///         .setting(ArgSettings::TakesValue)
+    ///         .settings(&[ArgSettings::Required, ArgSettings::TakesValue])
     ///         .long("config"))
     ///     .try_get_matches_from(vec![
-    ///         "prog", "--config", "file.conf",
+    ///         "prog", "--config", "file.conf"
     ///     ]);
     ///
     /// assert!(res.is_ok());
@@ -3074,8 +3073,7 @@ impl<'help> Arg<'help> {
     /// # use clap::{App, Arg, ArgSettings, ErrorKind};
     /// let res = App::new("prog")
     ///     .arg(Arg::new("cfg")
-    ///         .setting(ArgSettings::Required)
-    ///         .setting(ArgSettings::TakesValue)
+    ///         .settings(&[ArgSettings::Required, ArgSettings::TakesValue])
     ///         .long("config"))
     ///     .try_get_matches_from(vec![
     ///         "prog"
@@ -3342,8 +3340,7 @@ impl<'help> Arg<'help> {
     /// let delims = App::new("prog")
     ///     .arg(Arg::new("opt")
     ///         .short('o')
-    ///         .setting(ArgSettings::RequireDelimiter)
-    ///         .setting(ArgSettings::MultipleValues))
+    ///         .settings(&[ArgSettings::RequireDelimiter, ArgSettings::MultipleValues]))
     ///     .get_matches_from(vec![
     ///         "prog", "-o", "val1,val2,val3",
     ///     ]);
@@ -3548,8 +3545,7 @@ impl<'help> Arg<'help> {
     ///     .arg(Arg::new("option")
     ///         .short('o')
     ///         .long("--option")
-    ///         .setting(ArgSettings::IgnoreCase)
-    ///         .setting(ArgSettings::MultipleValues)
+    ///         .settings(&[ArgSettings::IgnoreCase, ArgSettings::MultipleValues])
     ///         .possible_value("test123")
     ///         .possible_value("test321"))
     ///     .get_matches_from(vec![
@@ -3717,8 +3713,7 @@ impl<'help> Arg<'help> {
     ///     .arg(Arg::new("opt")
     ///         .long("long-option-flag")
     ///         .short('o')
-    ///         .setting(ArgSettings::TakesValue)
-    ///         .setting(ArgSettings::NextLineHelp)
+    ///         .settings(&[ArgSettings::TakesValue, ArgSettings::NextLineHelp])
     ///         .value_names(&["value1", "value2"])
     ///         .about("Some really long help and complex\n\
     ///                help that makes more sense to be\n\
@@ -3893,8 +3888,7 @@ impl<'help> Arg<'help> {
     /// # use clap::{App, Arg, ArgSettings};
     /// let m = App::new("prog")
     ///     .arg(Arg::new("file")
-    ///         .setting(ArgSettings::MultipleOccurrences)
-    ///         .setting(ArgSettings::TakesValue)
+    ///         .settings(&[ArgSettings::MultipleOccurrences, ArgSettings::TakesValue])
     ///         .short('F'))
     ///     .arg(Arg::new("word")
     ///         .index(1))
@@ -3914,8 +3908,7 @@ impl<'help> Arg<'help> {
     /// # use clap::{App, Arg, ErrorKind, ArgSettings};
     /// let res = App::new("prog")
     ///     .arg(Arg::new("file")
-    ///         .setting(ArgSettings::MultipleOccurrences)
-    ///         .setting(ArgSettings::TakesValue)
+    ///         .settings(&[ArgSettings::MultipleOccurrences, ArgSettings::TakesValue])
     ///         .short('F'))
     ///     .arg(Arg::new("word")
     ///         .index(1))
@@ -4039,8 +4032,7 @@ impl<'help> Arg<'help> {
     /// # use clap::{App, Arg, ArgSettings};
     /// let m = App::new("prog")
     ///     .arg(Arg::new("file")
-    ///         .setting(ArgSettings::MultipleOccurrences)
-    ///         .setting(ArgSettings::TakesValue)
+    ///         .settings(&[ArgSettings::MultipleOccurrences, ArgSettings::TakesValue])
     ///         .short('F'))
     ///     .get_matches_from(vec![
     ///         "prog", "-F", "file1", "-F", "file2", "-F", "file3"
@@ -4260,42 +4252,32 @@ impl<'help> Arg<'help> {
         self.settings.is_set(s)
     }
 
-    /// Enables a single setting for the current (this `Arg` instance) argument.
-    ///
-    /// See [`ArgSettings`] for a full list of possibilities and examples.
-    ///
-    /// # Examples
+    /// Sets one of the [`ArgSettings`] settings for the argument
     ///
-    /// ```no_run
-    /// # use clap::{Arg, ArgSettings};
-    /// Arg::new("config")
-    ///     .setting(ArgSettings::Required)
-    ///     .setting(ArgSettings::TakesValue)
-    /// # ;
-    /// ```
     /// [`ArgSettings`]: ./enum.ArgSettings.html
     #[inline]
-    pub fn setting(mut self, setting: ArgSettings) -> Self {
-        self.settings.set(setting);
+    pub fn setting(mut self, s: ArgSettings) -> Self {
+        self.set_mut(s);
         self
     }
 
-    /// Disables a single setting for the current (this `Arg` instance) argument.
-    ///
-    /// See [`ArgSettings`] for a full list of possibilities and examples.
+    // @TODO @docs @v3-beta: write better docs as ArgSettings is now critical
+    /// Sets multiple [`ArgSettings`] for the argument
     ///
-    /// # Examples
+    /// [`ArgSettings`]: ./enum.ArgSettings.html
+    pub fn settings(mut self, settings: &[ArgSettings]) -> Self {
+        for s in settings {
+            self.settings.set(*s);
+        }
+        self
+    }
+
+    /// Unsets one of the [`ArgSettings`] for the argument
     ///
-    /// ```no_run
-    /// # use clap::{Arg, ArgSettings};
-    /// Arg::new("config")
-    ///     .unset_setting(ArgSettings::Required)
-    /// # ;
-    /// ```
     /// [`ArgSettings`]: ./enum.ArgSettings.html
     #[inline]
-    pub fn unset_setting(mut self, setting: ArgSettings) -> Self {
-        self.settings.unset(setting);
+    pub fn unset_setting(mut self, s: ArgSettings) -> Self {
+        self.unset_mut(s);
         self
     }
 
@@ -4333,7 +4315,7 @@ impl<'help> Arg<'help> {
     /// # ;
     /// ```
     pub fn value_hint(mut self, value_hint: ValueHint) -> Self {
-        self.settings.set(ArgSettings::TakesValue);
+        self.set_mut(ArgSettings::TakesValue);
         self.value_hint = value_hint;
         self
     }
@@ -4352,14 +4334,22 @@ impl<'help> Arg<'help> {
                 || self.min_vals.is_some()
                 || (self.num_vals.is_some() && self.num_vals.unwrap() > 1)
             {
-                self.settings.set(ArgSettings::MultipleValues);
-                self.settings.set(ArgSettings::MultipleOccurrences);
+                self.set_mut(ArgSettings::MultipleValues);
+                self.set_mut(ArgSettings::MultipleOccurrences);
             }
         } else if self.is_set(ArgSettings::TakesValue) && self.val_names.len() > 1 {
             self.num_vals = Some(self.val_names.len() as u64);
         }
     }
 
+    pub(crate) fn set_mut(&mut self, s: ArgSettings) {
+        self.settings.set(s);
+    }
+
+    pub(crate) fn unset_mut(&mut self, s: ArgSettings) {
+        self.settings.unset(s);
+    }
+
     pub(crate) fn has_switch(&self) -> bool {
         self.short.is_some() || self.long.is_some()
     }
@@ -4534,7 +4524,7 @@ impl<'help> From<&'help Yaml> for Arg<'help> {
                 "required_unless_present_any" => yaml_vec!(a, v, required_unless_present_any),
                 "required_unless_present_all" => {
                     a = yaml_vec!(a, v, required_unless_present_all);
-                    a.settings.set(ArgSettings::RequiredUnlessAll);
+                    a.set_mut(ArgSettings::RequiredUnlessAll);
                     a
                 }
                 "visible_alias" => yaml_to_str!(a, v, visible_alias),
@@ -4880,16 +4870,16 @@ mod test {
 
     #[test]
     fn positiona_display_mult() {
-        let p = Arg::new("pos")
-            .index(1)
-            .setting(ArgSettings::MultipleValues);
+        let mut p = Arg::new("pos").index(1);
+        p.set_mut(ArgSettings::MultipleValues);
 
         assert_eq!(&*format!("{}", p), "<pos>...");
     }
 
     #[test]
     fn positional_display_required() {
-        let p2 = Arg::new("pos").index(1).setting(ArgSettings::Required);
+        let mut p2 = Arg::new("pos").index(1);
+        p2.settings.set(ArgSettings::Required);
 
         assert_eq!(&*format!("{}", p2), "<pos>");
     }
@@ -4907,7 +4897,8 @@ mod test {
 
     #[test]
     fn positional_display_val_names_req() {
-        let mut p2 = Arg::new("pos").index(1).setting(ArgSettings::Required);
+        let mut p2 = Arg::new("pos").index(1);
+        p2.settings.set(ArgSettings::Required);
         let mut vm = VecMap::new();
         vm.insert(0, "file1");
         vm.insert(1, "file2");
diff --git a/src/build/usage_parser.rs b/src/build/usage_parser.rs
index 102abb5a..e5f07540 100644
--- a/src/build/usage_parser.rs
+++ b/src/build/usage_parser.rs
@@ -71,7 +71,7 @@ impl<'help> UsageParser<'help> {
         };
         if !arg.has_switch() && arg.is_set(ArgSettings::MultipleOccurrences) {
             // We had a positional and need to set mult vals too
-            arg.settings.set(ArgSettings::MultipleValues);
+            arg.set_mut(ArgSettings::MultipleValues);
         }
         debug!("UsageParser::parse: vals...{:?}", arg.val_names);
         arg
@@ -87,7 +87,7 @@ impl<'help> UsageParser<'help> {
             == b'<'
             && !self.explicit_name_set
         {
-            arg.settings.set(ArgSettings::Required);
+            arg.set_mut(ArgSettings::Required);
         }
         self.pos += 1;
         self.stop_at(name_end);
@@ -104,7 +104,7 @@ impl<'help> UsageParser<'help> {
         } else {
             debug!("UsageParser::name: setting val name...{}", name);
             if arg.val_names.is_empty() {
-                arg.settings.set(ArgSettings::TakesValue);
+                arg.set_mut(ArgSettings::TakesValue);
             }
             let len = arg.val_names.len();
             arg.val_names.insert(len, name);
@@ -183,9 +183,9 @@ impl<'help> UsageParser<'help> {
             if dot_counter == 3 {
                 debug!("UsageParser::multiple: setting multiple");
                 if arg.is_set(ArgSettings::TakesValue) {
-                    arg.settings.set(ArgSettings::MultipleValues);
+                    arg.set_mut(ArgSettings::MultipleValues);
                 }
-                arg.settings.set(ArgSettings::MultipleOccurrences);
+                arg.set_mut(ArgSettings::MultipleOccurrences);
                 self.prev = UsageToken::Multiple;
                 self.pos += 1;
                 break;
@@ -218,7 +218,7 @@ impl<'help> UsageParser<'help> {
             "UsageParser::default: setting default...\"{}\"",
             &self.usage[self.start..self.pos]
         );
-        arg.settings.set(ArgSettings::TakesValue);
+        arg.set_mut(ArgSettings::TakesValue);
         arg.default_vals = vec![std::ffi::OsStr::new(&self.usage[self.start..self.pos])];
         self.prev = UsageToken::Default;
     }
diff --git a/src/parse/validator.rs b/src/parse/validator.rs
index 1e89cc9f..5aefa02f 100644
--- a/src/parse/validator.rs
+++ b/src/parse/validator.rs
@@ -242,7 +242,7 @@ impl<'help, 'app, 'parser> Validator<'help, 'app, 'parser> {
             ));
         }
 
-        panic!(INTERNAL_ERROR_MSG);
+        panic!("{}", INTERNAL_ERROR_MSG);
     }
 
     fn validate_conflicts(&mut self, matcher: &mut ArgMatcher) -> ClapResult<()> {


Test patch:
diff --git a/clap_derive/tests/custom-string-parsers.rs b/clap_derive/tests/custom-string-parsers.rs
index 32ebf70a..fccd0083 100644
--- a/clap_derive/tests/custom-string-parsers.rs
+++ b/clap_derive/tests/custom-string-parsers.rs
@@ -83,6 +83,7 @@ fn test_parse_hex() {
     let err = HexOpt::try_parse_from(&["test", "-n", "gg"]).unwrap_err();
     assert!(
         err.to_string().contains("invalid digit found in string"),
+        "{}",
         err
     );
 }
diff --git a/clap_derive/tests/non_literal_attributes.rs b/clap_derive/tests/non_literal_attributes.rs
index 83f42f0b..72e8b865 100644
--- a/clap_derive/tests/non_literal_attributes.rs
+++ b/clap_derive/tests/non_literal_attributes.rs
@@ -149,6 +149,7 @@ fn test_parse_hex_function_path() {
     let err = HexOpt::try_parse_from(&["test", "-n", "gg"]).unwrap_err();
     assert!(
         err.to_string().contains("invalid digit found in string"),
+        "{}",
         err
     );
 }
diff --git a/tests/help.rs b/tests/help.rs
index 81827773..ec596a21 100644
--- a/tests/help.rs
+++ b/tests/help.rs
@@ -740,9 +740,11 @@ fn args_with_last_usage() {
         .arg(
             Arg::new("pass through args")
                 .about("Any arguments you wish to pass to the being profiled.")
-                .setting(ArgSettings::MultipleValues)
-                .setting(ArgSettings::MultipleOccurrences)
-                .setting(ArgSettings::Last)
+                .settings(&[
+                    ArgSettings::MultipleValues,
+                    ArgSettings::MultipleOccurrences,
+                    ArgSettings::Last,
+                ])
                 .value_name("ARGS"),
         );
     assert!(utils::compare_output(