diff --git a/clap_builder/src/builder/arg.rs b/clap_builder/src/builder/arg.rs index ddd4418499b..6014c3132be 100644 --- a/clap_builder/src/builder/arg.rs +++ b/clap_builder/src/builder/arg.rs @@ -4363,8 +4363,20 @@ impl Arg { } debug_assert!(self.is_takes_value_set()); + + let is_required = |n| match self.is_positional() { + true => required && (num_vals.min_values() != 0), + false => { + // If all values are optional, the [] get rendered by the caller: + // --foo[=] + // In this case, treat as required. + let required = self.get_min_vals() == 0; + required || (n < num_vals.min_values()) + } + }; + for (n, val_name) in val_names.iter().enumerate() { - let arg_name = if self.is_positional() && (num_vals.min_values() == 0 || !required) { + let arg_name = if !is_required(n) { format!("[{val_name}]") } else { format!("<{val_name}>") @@ -4646,7 +4658,7 @@ mod test { .value_names(["file", "name"]); o._build(); - assert_eq!(o.to_string(), "-o ..."); + assert_eq!(o.to_string(), "-o [name]..."); } #[test] diff --git a/tests/builder/help.rs b/tests/builder/help.rs index 526bc0c6e4d..84eaf977864 100644 --- a/tests/builder/help.rs +++ b/tests/builder/help.rs @@ -2845,3 +2845,24 @@ fn display_name_subcommand_explicit() { Some("child.display") ); } + +#[test] +fn issue_4847_usage() { + static USAGE_WITH_GROUP: &str = "\ +Usage: deno [OPTIONS] + +Options: + --example [OPTIONAL] issue 4847 + -h, --help Print help +"; + + let cmd = clap::Command::new("hello").bin_name("deno").arg( + Arg::new("example") + .long("example") + .num_args(1..=2) + .help("issue 4847") + .value_names(&["REQUIRED", "OPTIONAL"]), + ); + + utils::assert_output(cmd, "deno --help", USAGE_WITH_GROUP, false); +}