Repository: clap-rs/clap
Pull request #4003 (2022-07-29 14:58:55)

fix(help): Show when a flag 'ArgAction::Count's
<!--
Thanks for helping out!

Please link the appropriate issue from your PR.

If you don't have an issue, we'd recommend starting with one first so the PR can focus on the
implementation (unless its an obvious bug or documentation fix that will have
little conversation).
-->



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8257bd88..4b6e7ead 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -52,6 +52,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 - *(assert)* Ensure no self-`overrides_with` now that Actions replace it
 - *(assert)* Ensure subcommand names are not duplicated
 - *(help)* Use `Command::display_name` in the help title rather than `Command::bin_name`
+- *(help)* Show when a flag is `ArgAction::Count` by adding an `...`
 - *(version)* Use `Command::display_name` rather than `Command::bin_name`
 - *(parser)* Assert on unknown args when using external subcommands (#3703)
 - *(parser)* Always fill in `""` argument for external subcommands (#3263)
diff --git a/examples/tutorial_builder/01_quick.md b/examples/tutorial_builder/01_quick.md
index 89180af5..a110e8f9 100644
--- a/examples/tutorial_builder/01_quick.md
+++ b/examples/tutorial_builder/01_quick.md
@@ -11,7 +11,7 @@ ARGS:
 
 OPTIONS:
     -c, --config <FILE>    Sets a custom config file
-    -d, --debug            Turn debugging information on
+    -d, --debug...         Turn debugging information on
     -h, --help             Print help information
     -V, --version          Print version information
 
diff --git a/examples/tutorial_builder/03_01_flag_count.md b/examples/tutorial_builder/03_01_flag_count.md
index afc13e56..34be02f1 100644
--- a/examples/tutorial_builder/03_01_flag_count.md
+++ b/examples/tutorial_builder/03_01_flag_count.md
@@ -7,9 +7,9 @@ USAGE:
     03_01_flag_count[EXE] [OPTIONS]
 
 OPTIONS:
-    -v, --verbose    
-    -h, --help       Print help information
-    -V, --version    Print version information
+    -v, --verbose...    
+    -h, --help          Print help information
+    -V, --version       Print version information
 
 $ 03_01_flag_count
 verbose: 0
diff --git a/examples/tutorial_derive/01_quick.md b/examples/tutorial_derive/01_quick.md
index 89180af5..a110e8f9 100644
--- a/examples/tutorial_derive/01_quick.md
+++ b/examples/tutorial_derive/01_quick.md
@@ -11,7 +11,7 @@ ARGS:
 
 OPTIONS:
     -c, --config <FILE>    Sets a custom config file
-    -d, --debug            Turn debugging information on
+    -d, --debug...         Turn debugging information on
     -h, --help             Print help information
     -V, --version          Print version information
 
diff --git a/examples/tutorial_derive/03_01_flag_count.md b/examples/tutorial_derive/03_01_flag_count.md
index afc13e56..34be02f1 100644
--- a/examples/tutorial_derive/03_01_flag_count.md
+++ b/examples/tutorial_derive/03_01_flag_count.md
@@ -7,9 +7,9 @@ USAGE:
     03_01_flag_count[EXE] [OPTIONS]
 
 OPTIONS:
-    -v, --verbose    
-    -h, --help       Print help information
-    -V, --version    Print version information
+    -v, --verbose...    
+    -h, --help          Print help information
+    -V, --version       Print version information
 
 $ 03_01_flag_count
 verbose: 0
diff --git a/src/builder/arg.rs b/src/builder/arg.rs
index 0df3489e..6950deff 100644
--- a/src/builder/arg.rs
+++ b/src/builder/arg.rs
@@ -4448,6 +4448,8 @@ impl<'help> Display for Arg<'help> {
         if self.is_takes_value_set() || self.is_positional() {
             let arg_val = render_arg_val(self);
             f.write_str(&arg_val)?;
+        } else if matches!(*self.get_action(), ArgAction::Count) {
+            f.write_str("...")?;
         }
         if need_closing_bracket {
             f.write_str("]")?;
@@ -4566,14 +4568,8 @@ pub(crate) fn render_arg_val(arg: &Arg) -> String {
         }
         extra_values |= val_names.len() < num_vals.max_values();
     }
-    if arg.is_positional() {
-        if matches!(*arg.get_action(), ArgAction::Append) {
-            extra_values = true;
-        }
-    } else {
-        if matches!(*arg.get_action(), ArgAction::Count) {
-            extra_values = true;
-        }
+    if arg.is_positional() && matches!(*arg.get_action(), ArgAction::Append) {
+        extra_values = true;
     }
 
     if extra_values {
@@ -4590,18 +4586,29 @@ mod test {
     use super::ArgAction;
 
     #[test]
-    fn flag_display() {
+    fn flag_display_long() {
         let mut f = Arg::new("flg").long("flag").action(ArgAction::SetTrue);
         f._build();
 
         assert_eq!(f.to_string(), "--flag");
+    }
 
+    #[test]
+    fn flag_display_short() {
         let mut f2 = Arg::new("flg").short('f').action(ArgAction::SetTrue);
         f2._build();
 
         assert_eq!(f2.to_string(), "-f");
     }
 
+    #[test]
+    fn flag_display_count() {
+        let mut f2 = Arg::new("flg").long("flag").action(ArgAction::Count);
+        f2._build();
+
+        assert_eq!(f2.to_string(), "--flag...");
+    }
+
     #[test]
     fn flag_display_single_alias() {
         let mut f = Arg::new("flg")
diff --git a/src/output/help.rs b/src/output/help.rs
index f3228831..09a3013c 100644
--- a/src/output/help.rs
+++ b/src/output/help.rs
@@ -8,6 +8,7 @@ use std::usize;
 // Internal
 use crate::builder::{render_arg_val, Arg, Command};
 use crate::output::{fmt::Colorizer, Usage};
+use crate::ArgAction;
 use crate::PossibleValue;
 
 // Third party
@@ -316,8 +317,9 @@ impl<'help, 'cmd, 'writer> Help<'help, 'cmd, 'writer> {
         if arg.is_takes_value_set() || arg.is_positional() {
             let arg_val = render_arg_val(arg);
             self.good(arg_val)?;
+        } else if matches!(*arg.get_action(), ArgAction::Count) {
+            self.good("...")?;
         }
-
         if need_closing_bracket {
             self.none("]")?;
         }


Test patch:
diff --git a/tests/builder/conflicts.rs b/tests/builder/conflicts.rs
index a205bbb1..ee08b159 100644
--- a/tests/builder/conflicts.rs
+++ b/tests/builder/conflicts.rs
@@ -2,32 +2,6 @@ use super::utils;
 
 use clap::{arg, error::ErrorKind, Arg, ArgAction, ArgGroup, Command};
 
-static CONFLICT_ERR: &str = "error: The argument '--flag' cannot be used with '-F'
-
-USAGE:
-    clap-test --flag --long-option-2 <option2> <positional> <positional2>
-
-For more information try --help
-";
-
-static CONFLICT_ERR_REV: &str = "error: The argument '-F' cannot be used with '--flag'
-
-USAGE:
-    clap-test -F --long-option-2 <option2> <positional> <positional2>
-
-For more information try --help
-";
-
-static CONFLICT_ERR_THREE: &str = "error: The argument '--one' cannot be used with:
-    --two
-    --three
-
-USAGE:
-    three_conflicting_arguments --one
-
-For more information try --help
-";
-
 #[test]
 fn flag_conflict() {
     let result = Command::new("flag_conflict")
@@ -316,6 +290,14 @@ fn get_arg_conflicts_with_group() {
 
 #[test]
 fn conflict_output() {
+    static CONFLICT_ERR: &str = "error: The argument '--flag...' cannot be used with '-F'
+
+USAGE:
+    clap-test --flag... --long-option-2 <option2> <positional> <positional2>
+
+For more information try --help
+";
+
     utils::assert_output(
         utils::complex_app(),
         "clap-test val1 fa --flag --long-option-2 val2 -F",
@@ -326,6 +308,14 @@ fn conflict_output() {
 
 #[test]
 fn conflict_output_rev() {
+    static CONFLICT_ERR_REV: &str = "error: The argument '-F' cannot be used with '--flag...'
+
+USAGE:
+    clap-test -F --long-option-2 <option2> <positional> <positional2>
+
+For more information try --help
+";
+
     utils::assert_output(
         utils::complex_app(),
         "clap-test val1 fa -F --long-option-2 val2 --flag",
@@ -336,6 +326,14 @@ fn conflict_output_rev() {
 
 #[test]
 fn conflict_output_with_required() {
+    static CONFLICT_ERR: &str = "error: The argument '--flag...' cannot be used with '-F'
+
+USAGE:
+    clap-test --flag... --long-option-2 <option2> <positional> <positional2>
+
+For more information try --help
+";
+
     utils::assert_output(
         utils::complex_app(),
         "clap-test val1 --flag --long-option-2 val2 -F",
@@ -346,6 +344,14 @@ fn conflict_output_with_required() {
 
 #[test]
 fn conflict_output_rev_with_required() {
+    static CONFLICT_ERR_REV: &str = "error: The argument '-F' cannot be used with '--flag...'
+
+USAGE:
+    clap-test -F --long-option-2 <option2> <positional> <positional2>
+
+For more information try --help
+";
+
     utils::assert_output(
         utils::complex_app(),
         "clap-test val1 -F --long-option-2 val2 --flag",
@@ -356,6 +362,16 @@ fn conflict_output_rev_with_required() {
 
 #[test]
 fn conflict_output_three_conflicting() {
+    static CONFLICT_ERR_THREE: &str = "error: The argument '--one' cannot be used with:
+    --two
+    --three
+
+USAGE:
+    three_conflicting_arguments --one
+
+For more information try --help
+";
+
     let cmd = Command::new("three_conflicting_arguments")
         .arg(
             Arg::new("one")
diff --git a/tests/builder/help.rs b/tests/builder/help.rs
index 126fc9b8..c6e3a452 100644
--- a/tests/builder/help.rs
+++ b/tests/builder/help.rs
@@ -219,7 +219,7 @@ ARGS:
 
 OPTIONS:
     -o, --option <opt>...                    tests options
-    -f, --flag                               tests flags
+    -f, --flag...                            tests flags
     -F                                       tests flags with exclusions
         --long-option-2 <option2>            tests long options with exclusions
     -O, --option3 <option3>                  specific vals [possible values: fast, slow]
@@ -550,7 +550,7 @@ ARGS:
 
 OPTIONS:
     -o, --option <scoption>...     tests options
-    -f, --flag                     tests flags
+    -f, --flag...                  tests flags
     -s, --subcmdarg <subcmdarg>    tests other args
     -h, --help                     Print help information
     -V, --version                  Print version information
diff --git a/tests/builder/template_help.rs b/tests/builder/template_help.rs
index f74c4aea..5d5784a6 100644
--- a/tests/builder/template_help.rs
+++ b/tests/builder/template_help.rs
@@ -34,7 +34,7 @@ USAGE:
 
 OPTIONS:
     -c, --config <FILE>    Sets a custom config file
-    -d                     Turn debugging information on
+    -d...                  Turn debugging information on
     -h, --help             Print help information
     -V, --version          Print version information
 ARGS:
@@ -56,7 +56,7 @@ ARGS:
 
 OPTIONS:
     -c, --config <FILE>    Sets a custom config file
-    -d                     Turn debugging information on
+    -d...                  Turn debugging information on
     -h, --help             Print help information
     -V, --version          Print version information