Repository: clap-rs/clap (Rust)

Issue:
number_of_values should have improved help message
### Please complete the following tasks

- [x] I have searched the [discussions](https://github.com/clap-rs/clap/discussions)
- [X] I have searched the existing issues

### Rust Version

rustc 1.52.1 (9bc8c42bb 2021-05-09)

### Clap Version

3.0.0-beta.2

### Minimal reproducible code

```rust
use clap::{App, Arg};

fn main() {
    let my_app = App::new("my_app")
        .arg(Arg::new("some_arg").long("some_arg").number_of_values(2))
        .arg(
            Arg::new("some_arg_issue")
                .long("some_arg_issue")
                .number_of_values(2)
                .value_name("ARG"),
        )
        .get_matches();
}
```


### Steps to reproduce the bug with the above code

cargo run -- --help

### Actual Behaviour

The `some_arg` argument has 2 values in the help page.
The `some_arg_issue` argument has only one value in the help page.

Whenever you add a name to the value, the number of arguments required is not represented in the help page.

[![asciicast](https://asciinema.org/a/5pGWQPNM27rxKnnUYvvkP20Nv.svg)](https://asciinema.org/a/5pGWQPNM27rxKnnUYvvkP20Nv)

### Expected Behaviour

The number of arguments should be preserved in the help page even when the `value_name` is specified.

### Additional Context

When I use `multiple()` than the normal '...' is represented in the help page.

### Debug Output

[            clap::build::app] 	App::_do_parse
[            clap::build::app] 	App::_build
[            clap::build::app] 	App::_propagate:my_app
[            clap::build::app] 	App::_derive_display_order:my_app
[            clap::build::app] 	App::_create_help_and_version
[            clap::build::app] 	App::_create_help_and_version: Building --help
[            clap::build::app] 	App::_create_help_and_version: Building --version
[clap::build::app::debug_asserts] 	App::_debug_asserts
[            clap::build::arg] 	Arg::_debug_asserts:some_arg
[            clap::build::arg] 	Arg::_debug_asserts:some_arg_issue
[            clap::build::arg] 	Arg::_debug_asserts:help
[            clap::build::arg] 	Arg::_debug_asserts:version
[         clap::parse::parser] 	Parser::get_matches_with
[         clap::parse::parser] 	Parser::_build
[         clap::parse::parser] 	Parser::_verify_positionals
[         clap::parse::parser] 	Parser::get_matches_with: Begin parsing '"--help"' ([45, 45, 104, 101, 108, 112])
[         clap::parse::parser] 	Parser::is_new_arg: "--help":NotFound
[         clap::parse::parser] 	Parser::is_new_arg: arg_allows_tac=false
[         clap::parse::parser] 	Parser::is_new_arg: -- found
[         clap::parse::parser] 	Parser::is_new_arg: starts_new_arg=true
[         clap::parse::parser] 	Parser::possible_subcommand: arg="--help"
[         clap::parse::parser] 	Parser::get_matches_with: possible_sc=false, sc=None
[         clap::parse::parser] 	Parser::parse_long_arg
[         clap::parse::parser] 	Parser::parse_long_arg: Does it contain '='...
[         clap::parse::parser] 	No
[         clap::parse::parser] 	Parser::parse_long_arg: Found valid opt or flag '--help'
[         clap::parse::parser] 	Parser::check_for_help_and_version_str
[         clap::parse::parser] 	Parser::check_for_help_and_version_str: Checking if --"help" is help or version...
[         clap::parse::parser] 	Help
[         clap::parse::parser] 	[         clap::parse::parser] 	Parser::use_long_help
Parser::help_err: use_long=false
[         clap::parse::parser] 	Parser::use_long_help
[         clap::parse::parser] 	Parser::color_help
[          clap::output::help] 	Help::new
[          clap::output::help] 	Help::write_help
[          clap::output::help] 	Help::write_templated_help
[          clap::output::help] 	Help::write_bin_name
[         clap::output::usage] 	Usage::create_usage_no_title
[         clap::output::usage] 	Usage::create_help_usage; incl_reqs=true
[         clap::output::usage] 	Usage::get_required_usage_from: incls=[], matcher=false, incl_last=false
[         clap::output::usage] 	Usage::get_required_usage_from: unrolled_reqs=[]
[         clap::output::usage] 	Usage::get_required_usage_from: ret_val=[]
[         clap::output::usage] 	Usage::needs_flags_tag
[         clap::output::usage] 	Usage::needs_flags_tag:iter: f=help
[         clap::output::usage] 	Usage::needs_flags_tag:iter: f=version
[         clap::output::usage] 	Usage::needs_flags_tag: [FLAGS] not required
[         clap::output::usage] 	Usage::create_help_usage: usage=clap_issue [OPTIONS]
[          clap::output::help] 	Help::write_all_args
[          clap::output::help] 	should_show_arg: use_long=false, arg=some_arg
[          clap::output::help] 	should_show_arg: use_long=false, arg=some_arg_issue
[          clap::output::help] 	Help::write_args
[          clap::output::help] 	should_show_arg: use_long=false, arg=help
[          clap::output::help] 	Help::write_args: Current Longest...2
[          clap::output::help] 	Help::write_args: New Longest...6
[          clap::output::help] 	should_show_arg: use_long=false, arg=version
[          clap::output::help] 	Help::write_args: Current Longest...6
[          clap::output::help] 	Help::write_args: New Longest...9
[          clap::output::help] 	Help::write_arg
[          clap::output::help] 	Help::short
[          clap::output::help] 	Help::long
[          clap::output::help] 	Help::val: arg=help
[          clap::output::help] 	Help::spec_vals: a=--help
[          clap::output::help] 	Help::val: Has switch...
[          clap::output::help] 	Yes
[          clap::output::help] 	Help::val: force_next_line...false
[          clap::output::help] 	Help::val: nlh...false
[          clap::output::help] 	Help::val: taken...21
[          clap::output::help] 	val: help_width > (width - taken)...23 > (100 - 21)
[          clap::output::help] 	Help::val: longest...9
[          clap::output::help] 	Help::val: next_line...
[          clap::output::help] 	No
[          clap::output::help] 	Help::write_nspaces!: num=7
[          clap::output::help] 	Help::help
[          clap::output::help] 	Help::help: Next Line...false
[          clap::output::help] 	Help::help: Too long...
[          clap::output::help] 	No
[          clap::output::help] 	Help::write_arg
[          clap::output::help] 	Help::short
[          clap::output::help] 	Help::long
[          clap::output::help] 	Help::val: arg=version
[          clap::output::help] 	Help::spec_vals: a=--version
[          clap::output::help] 	Help::val: Has switch...
[          clap::output::help] 	Yes
[          clap::output::help] 	Help::val: force_next_line...false
[          clap::output::help] 	Help::val: nlh...false
[          clap::output::help] 	Help::val: taken...21
[          clap::output::help] 	val: help_width > (width - taken)...26 > (100 - 21)
[          clap::output::help] 	Help::val: longest...9
[          clap::output::help] 	Help::val: next_line...
[          clap::output::help] 	No
[          clap::output::help] 	Help::write_nspaces!: num=4
[          clap::output::help] 	Help::help
[          clap::output::help] 	Help::help: Next Line...false
[          clap::output::help] 	Help::help: Too long...
[          clap::output::help] 	No
[          clap::output::help] 	Help::write_args
[          clap::output::help] 	should_show_arg: use_long=false, arg=some_arg
[          clap::output::help] 	Help::write_args: Current Longest...2
[          clap::output::help] 	Help::write_args: New Longest...32
[          clap::output::help] 	should_show_arg: use_long=false, arg=some_arg_issue
[          clap::output::help] 	Help::write_args: Current Longest...32
[          clap::output::help] 	Help::write_args: New Longest...32
[          clap::output::help] 	Help::write_arg
[          clap::output::help] 	Help::short
[          clap::output::help] 	Help::long
[          clap::output::help] 	Help::val: arg=some_arg
[          clap::output::help] 	Help::spec_vals: a=--some_arg <some_arg> <some_arg>
[          clap::output::help] 	Help::val: Has switch...
[          clap::output::help] 	Yes
[          clap::output::help] 	Help::val: force_next_line...false
[          clap::output::help] 	Help::val: nlh...false
[          clap::output::help] 	Help::val: taken...44
[          clap::output::help] 	val: help_width > (width - taken)...0 > (100 - 44)
[          clap::output::help] 	Help::val: longest...32
[          clap::output::help] 	Help::val: next_line...
[          clap::output::help] 	No
[          clap::output::help] 	Help::write_nspaces!: num=4
[          clap::output::help] 	Help::help
[          clap::output::help] 	Help::help: Next Line...false
[          clap::output::help] 	Help::help: Too long...
[          clap::output::help] 	No
[          clap::output::help] 	Help::write_arg
[          clap::output::help] 	Help::short
[          clap::output::help] 	Help::long
[          clap::output::help] 	Help::val: arg=some_arg_issue
[          clap::output::help] 	Help::spec_vals: a=--some_arg_issue <ARG>
[          clap::output::help] 	Help::val: Has switch...
[          clap::output::help] 	Yes
[          clap::output::help] 	Help::val: force_next_line...false
[          clap::output::help] 	Help::val: nlh...false
[          clap::output::help] 	Help::val: taken...44
[          clap::output::help] 	val: help_width > (width - taken)...0 > (100 - 44)
[          clap::output::help] 	Help::val: longest...32
[          clap::output::help] 	Help::val: next_line...
[          clap::output::help] 	No
[          clap::output::help] 	Help::write_nspaces!: num=14
[          clap::output::help] 	Help::help
[          clap::output::help] 	Help::help: Next Line...false
[          clap::output::help] 	Help::help: Too long...
[          clap::output::help] 	No
[           clap::output::fmt] 	is_a_tty: stderr=false
my_app 

USAGE:
    clap_issue [OPTIONS]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
        --some_arg <some_arg> <some_arg>    
        --some_arg_issue <ARG>              



Discussion:
I am aware of `value_names` but this should probably also work.
Have you tried it with current master?
I have now. The output changed for `some_arg_issue` to `<ARG>...`. This is still not the desired outcome, which would be `<ARG> <ARG>`.



Patch:
diff --git a/src/output/help.rs b/src/output/help.rs
index 54a8a2cc12a..777bf3d733b 100644
--- a/src/output/help.rs
+++ b/src/output/help.rs
@@ -332,21 +332,39 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
                 ' '
             };
             if !arg.val_names.is_empty() {
-                let mut it = arg.val_names.iter().peekable();
-                while let Some((_, val)) = it.next() {
-                    self.good(&format!("<{}>", val))?;
-                    if it.peek().is_some() {
-                        self.none(&delim.to_string())?;
+                match (arg.val_names.len(), arg.num_vals) {
+                    (1, Some(num)) if num > 1 => {
+                        let arg_name = format!("<{}>", arg.val_names.get(0).unwrap());
+                        let mut it = (0..num).peekable();
+                        while it.next().is_some() {
+                            self.good(&arg_name)?;
+                            if it.peek().is_some() {
+                                self.none(&delim.to_string())?;
+                            }
+                        }
+                        if mult && num == 1 {
+                            self.good("...")?;
+                        }
+                    }
+                    _ => {
+                        let mut it = arg.val_names.iter().peekable();
+                        while let Some((_, val)) = it.next() {
+                            self.good(&format!("<{}>", val))?;
+                            if it.peek().is_some() {
+                                self.none(&delim.to_string())?;
+                            }
+                        }
+                        let num = arg.val_names.len();
+                        if mult && num == 1 {
+                            self.good("...")?;
+                        }
                     }
-                }
-                let num = arg.val_names.len();
-                if mult && num == 1 {
-                    self.good("...")?;
                 }
             } else if let Some(num) = arg.num_vals {
+                let arg_name = format!("<{}>", arg.name);
                 let mut it = (0..num).peekable();
-                while let Some(_) = it.next() {
-                    self.good(&format!("<{}>", arg.name))?;
+                while it.next().is_some() {
+                    self.good(&arg_name)?;
                     if it.peek().is_some() {
                         self.none(&delim.to_string())?;
                     }


Test patch:
diff --git a/tests/help.rs b/tests/help.rs
index f19f7408dc0..8dca6627c8e 100644
--- a/tests/help.rs
+++ b/tests/help.rs
@@ -2499,3 +2499,32 @@ fn only_custom_heading_pos_no_args() {
         false
     ));
 }
+
+#[test]
+fn issue_2508_number_of_values_with_single_value_name() {
+    let app = App::new("my_app")
+        .arg(Arg::new("some_arg").long("some_arg").number_of_values(2))
+        .arg(
+            Arg::new("some_arg_issue")
+                .long("some_arg_issue")
+                .number_of_values(2)
+                .value_name("ARG"),
+        );
+    assert!(utils::compare_output(
+        app,
+        "my_app --help",
+        "my_app 
+
+USAGE:
+    my_app [OPTIONS]
+
+FLAGS:
+    -h, --help       Prints help information
+    -V, --version    Prints version information
+
+OPTIONS:
+        --some_arg <some_arg> <some_arg>    
+        --some_arg_issue <ARG> <ARG>           ",
+        false
+    ));
+}