From 5bfbe2b3bbd46acce60c30502a8116110b980bad Mon Sep 17 00:00:00 2001 From: Fabian Freyer Date: Mon, 15 May 2023 20:26:44 +0200 Subject: [PATCH] fix(help): Render partially optional values with [] Fixes: #4847 --- clap_builder/src/builder/arg.rs | 15 +++++++++++++-- tests/builder/help.rs | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/clap_builder/src/builder/arg.rs b/clap_builder/src/builder/arg.rs index ddd4418499b..ed6ee2c236e 100644 --- a/clap_builder/src/builder/arg.rs +++ b/clap_builder/src/builder/arg.rs @@ -4363,8 +4363,19 @@ impl Arg { } debug_assert!(self.is_takes_value_set()); + for (n, val_name) in val_names.iter().enumerate() { - let arg_name = if self.is_positional() && (num_vals.min_values() == 0 || !required) { + let value_is_required = if self.is_positional() { + required && (num_vals.min_values() != 0) + } else { + // 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()) + }; + + let arg_name = if !value_is_required { format!("[{val_name}]") } else { format!("<{val_name}>") @@ -4646,7 +4657,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); +}