From 6f7174cc7c11239eb472ec2b9c4166f2e10de9df Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 8 Nov 2023 11:10:55 -0600 Subject: [PATCH 01/12] refactor(help): Pull out usage separator --- clap_builder/src/output/usage.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clap_builder/src/output/usage.rs b/clap_builder/src/output/usage.rs index 884a64df960..da396d67073 100644 --- a/clap_builder/src/output/usage.rs +++ b/clap_builder/src/output/usage.rs @@ -14,6 +14,7 @@ use crate::util::FlatSet; use crate::util::Id; static DEFAULT_SUB_VALUE_NAME: &str = "COMMAND"; +const USAGE_SEP: &str = "\n "; pub(crate) struct Usage<'cmd> { cmd: &'cmd Command, @@ -123,7 +124,7 @@ impl<'cmd> Usage<'cmd> { if self.cmd.is_subcommand_negates_reqs_set() || self.cmd.is_args_conflicts_with_subcommands_set() { - let _ = write!(styled, "\n "); + let _ = write!(styled, "{}", USAGE_SEP); if self.cmd.is_args_conflicts_with_subcommands_set() { // Short-circuit full usage creation since no args will be relevant let _ = write!( From f04f04111b68c2ff7bbd13784440b80417451ee1 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 8 Nov 2023 11:25:43 -0600 Subject: [PATCH 02/12] refactor(help): Switch usage creation to writing --- clap_builder/src/output/usage.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/clap_builder/src/output/usage.rs b/clap_builder/src/output/usage.rs index da396d67073..50161d58f32 100644 --- a/clap_builder/src/output/usage.rs +++ b/clap_builder/src/output/usage.rs @@ -62,11 +62,15 @@ impl<'cmd> Usage<'cmd> { } else { #[cfg(feature = "usage")] { + let mut styled = StyledStr::new(); if used.is_empty() { - Some(self.create_help_usage(true)) + self.write_help_usage(&mut styled, true); } else { - Some(self.create_smart_usage(used)) + self.write_smart_usage(&mut styled, used); } + styled.trim(); + debug!("Usage::create_usage_no_title: usage={styled}"); + Some(styled) } #[cfg(not(feature = "usage"))] @@ -80,12 +84,11 @@ impl<'cmd> Usage<'cmd> { #[cfg(feature = "usage")] impl<'cmd> Usage<'cmd> { // Creates a usage string for display in help messages (i.e. not for errors) - fn create_help_usage(&self, incl_reqs: bool) -> StyledStr { + fn write_help_usage(&self, styled: &mut StyledStr, incl_reqs: bool) { debug!("Usage::create_help_usage; incl_reqs={incl_reqs:?}"); use std::fmt::Write as _; let literal = &self.styles.get_literal(); let placeholder = &self.styles.get_placeholder(); - let mut styled = StyledStr::new(); let name = self .cmd @@ -111,7 +114,7 @@ impl<'cmd> Usage<'cmd> { ); } - self.write_args(&[], !incl_reqs, &mut styled); + self.write_args(&[], !incl_reqs, styled); // incl_reqs is only false when this function is called recursively if self.cmd.has_visible_subcommands() && incl_reqs @@ -134,7 +137,7 @@ impl<'cmd> Usage<'cmd> { literal.render_reset() ); } else { - styled.push_styled(&self.create_help_usage(false)); + self.write_help_usage(styled, false); } let _ = write!( styled, @@ -158,19 +161,15 @@ impl<'cmd> Usage<'cmd> { ); } } - styled.trim(); - debug!("Usage::create_help_usage: usage={styled}"); - styled } // Creates a context aware usage string, or "smart usage" from currently used // args, and requirements - fn create_smart_usage(&self, used: &[Id]) -> StyledStr { + fn write_smart_usage(&self, styled: &mut StyledStr, used: &[Id]) { debug!("Usage::create_smart_usage"); use std::fmt::Write; let literal = &self.styles.get_literal(); let placeholder = &self.styles.get_placeholder(); - let mut styled = StyledStr::new(); let bin_name = self .cmd @@ -184,7 +183,7 @@ impl<'cmd> Usage<'cmd> { literal.render_reset() ); - self.write_args(used, false, &mut styled); + self.write_args(used, false, styled); if self.cmd.is_subcommand_required_set() { let value_name = self @@ -198,7 +197,6 @@ impl<'cmd> Usage<'cmd> { placeholder.render_reset() ); } - styled } // Determines if we need the `[OPTIONS]` tag in the usage string From f50800f7638996dfb92cf03b798a3993e5c82860 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 8 Nov 2023 11:42:54 -0600 Subject: [PATCH 03/12] refactor(help): Only trim the end on usage --- clap_builder/src/builder/styled_str.rs | 4 ---- clap_builder/src/output/usage.rs | 21 +++++++++++---------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/clap_builder/src/builder/styled_str.rs b/clap_builder/src/builder/styled_str.rs index df0f1b03b7c..e06ddbc9edf 100644 --- a/clap_builder/src/builder/styled_str.rs +++ b/clap_builder/src/builder/styled_str.rs @@ -45,10 +45,6 @@ impl StyledStr { self.0.push_str(msg); } - pub(crate) fn trim(&mut self) { - self.0 = self.0.trim().to_owned() - } - pub(crate) fn trim_start_lines(&mut self) { if let Some(pos) = self.0.find('\n') { let (leading, help) = self.0.split_at(pos + 1); diff --git a/clap_builder/src/output/usage.rs b/clap_builder/src/output/usage.rs index 50161d58f32..fbcc3c95063 100644 --- a/clap_builder/src/output/usage.rs +++ b/clap_builder/src/output/usage.rs @@ -68,7 +68,7 @@ impl<'cmd> Usage<'cmd> { } else { self.write_smart_usage(&mut styled, used); } - styled.trim(); + styled.trim_end(); debug!("Usage::create_usage_no_title: usage={styled}"); Some(styled) } @@ -99,7 +99,7 @@ impl<'cmd> Usage<'cmd> { // the trim won't properly remove a leading space due to the formatting let _ = write!( styled, - "{}{name}{}", + "{}{name}{} ", literal.render(), literal.render_reset() ); @@ -108,7 +108,7 @@ impl<'cmd> Usage<'cmd> { if self.needs_options_tag() { let _ = write!( styled, - "{} [OPTIONS]{}", + "{}[OPTIONS]{} ", placeholder.render(), placeholder.render_reset() ); @@ -127,12 +127,13 @@ impl<'cmd> Usage<'cmd> { if self.cmd.is_subcommand_negates_reqs_set() || self.cmd.is_args_conflicts_with_subcommands_set() { + styled.trim_end(); let _ = write!(styled, "{}", USAGE_SEP); if self.cmd.is_args_conflicts_with_subcommands_set() { // Short-circuit full usage creation since no args will be relevant let _ = write!( styled, - "{}{name}{}", + "{}{name}{} ", literal.render(), literal.render_reset() ); @@ -141,21 +142,21 @@ impl<'cmd> Usage<'cmd> { } let _ = write!( styled, - " {}<{value_name}>{}", + "{}<{value_name}>{}", placeholder.render(), placeholder.render_reset() ); } else if self.cmd.is_subcommand_required_set() { let _ = write!( styled, - " {}<{value_name}>{}", + "{}<{value_name}>{}", placeholder.render(), placeholder.render_reset() ); } else { let _ = write!( styled, - " {}[{value_name}]{}", + "{}[{value_name}]{}", placeholder.render(), placeholder.render_reset() ); @@ -178,7 +179,7 @@ impl<'cmd> Usage<'cmd> { .unwrap_or_else(|| self.cmd.get_name()); let _ = write!( styled, - "{}{bin_name}{}", + "{}{bin_name}{} ", literal.render(), literal.render_reset() ); @@ -192,7 +193,7 @@ impl<'cmd> Usage<'cmd> { .unwrap_or(DEFAULT_SUB_VALUE_NAME); let _ = write!( styled, - " {}<{value_name}>{}", + "{}<{value_name}>{}", placeholder.render(), placeholder.render_reset() ); @@ -252,8 +253,8 @@ impl<'cmd> Usage<'cmd> { // Returns the required args in usage string form by fully unrolling all groups pub(crate) fn write_args(&self, incls: &[Id], force_optional: bool, styled: &mut StyledStr) { for required in self.get_args(incls, force_optional) { - styled.push_str(" "); styled.push_styled(&required); + styled.push_str(" "); } } From da98eb1a05dbefd4fbf3012a24ad9935162b5658 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 8 Nov 2023 11:49:07 -0600 Subject: [PATCH 04/12] refactor(help): Pull out top-level usage logic --- clap_builder/src/output/usage.rs | 37 ++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/clap_builder/src/output/usage.rs b/clap_builder/src/output/usage.rs index fbcc3c95063..bb2036c3fb0 100644 --- a/clap_builder/src/output/usage.rs +++ b/clap_builder/src/output/usage.rs @@ -40,8 +40,6 @@ impl<'cmd> Usage<'cmd> { // any subcommands have been parsed (so as to give subcommands their own usage recursively) pub(crate) fn create_usage_with_title(&self, used: &[Id]) -> Option { debug!("Usage::create_usage_with_title"); - let usage = some!(self.create_usage_no_title(used)); - use std::fmt::Write as _; let mut styled = StyledStr::new(); let _ = write!( @@ -50,32 +48,49 @@ impl<'cmd> Usage<'cmd> { self.styles.get_usage().render(), self.styles.get_usage().render_reset() ); - styled.push_styled(&usage); + if self.write_usage_no_title(&mut styled, used) { + styled.trim_end(); + } else { + return None; + } + debug!("Usage::create_usage_with_title: usage={styled}"); Some(styled) } // Creates a usage string (*without title*) if one was not provided by the user manually. pub(crate) fn create_usage_no_title(&self, used: &[Id]) -> Option { debug!("Usage::create_usage_no_title"); + + let mut styled = StyledStr::new(); + if self.write_usage_no_title(&mut styled, used) { + styled.trim_end(); + debug!("Usage::create_usage_no_title: usage={styled}"); + Some(styled) + } else { + None + } + } + + // Creates a usage string (*without title*) if one was not provided by the user manually. + fn write_usage_no_title(&self, styled: &mut StyledStr, used: &[Id]) -> bool { + debug!("Usage::create_usage_no_title"); if let Some(u) = self.cmd.get_override_usage() { - Some(u.clone()) + styled.push_styled(u); + true } else { #[cfg(feature = "usage")] { - let mut styled = StyledStr::new(); if used.is_empty() { - self.write_help_usage(&mut styled, true); + self.write_help_usage(styled, true); } else { - self.write_smart_usage(&mut styled, used); + self.write_smart_usage(styled, used); } - styled.trim_end(); - debug!("Usage::create_usage_no_title: usage={styled}"); - Some(styled) + true } #[cfg(not(feature = "usage"))] { - None + false } } } From acdd2c33f04034468a004a942aa1045108b897e9 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 9 Nov 2023 11:50:46 -0600 Subject: [PATCH 05/12] refactor(help): Make usage argument order consistent --- clap_builder/src/output/usage.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clap_builder/src/output/usage.rs b/clap_builder/src/output/usage.rs index bb2036c3fb0..ebd7257db88 100644 --- a/clap_builder/src/output/usage.rs +++ b/clap_builder/src/output/usage.rs @@ -129,7 +129,7 @@ impl<'cmd> Usage<'cmd> { ); } - self.write_args(&[], !incl_reqs, styled); + self.write_args(styled, &[], !incl_reqs); // incl_reqs is only false when this function is called recursively if self.cmd.has_visible_subcommands() && incl_reqs @@ -199,7 +199,7 @@ impl<'cmd> Usage<'cmd> { literal.render_reset() ); - self.write_args(used, false, styled); + self.write_args(styled, used, false); if self.cmd.is_subcommand_required_set() { let value_name = self @@ -266,7 +266,7 @@ impl<'cmd> Usage<'cmd> { } // Returns the required args in usage string form by fully unrolling all groups - pub(crate) fn write_args(&self, incls: &[Id], force_optional: bool, styled: &mut StyledStr) { + pub(crate) fn write_args(&self, styled: &mut StyledStr, incls: &[Id], force_optional: bool) { for required in self.get_args(incls, force_optional) { styled.push_styled(&required); styled.push_str(" "); From 676e934a6178877d59655ee3f57e9c8a3ea0d75e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 9 Nov 2023 11:57:15 -0600 Subject: [PATCH 06/12] refactor(help): More directly write args --- clap_builder/src/output/usage.rs | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/clap_builder/src/output/usage.rs b/clap_builder/src/output/usage.rs index ebd7257db88..b8e02fa5cc6 100644 --- a/clap_builder/src/output/usage.rs +++ b/clap_builder/src/output/usage.rs @@ -267,14 +267,7 @@ impl<'cmd> Usage<'cmd> { // Returns the required args in usage string form by fully unrolling all groups pub(crate) fn write_args(&self, styled: &mut StyledStr, incls: &[Id], force_optional: bool) { - for required in self.get_args(incls, force_optional) { - styled.push_styled(&required); - styled.push_str(" "); - } - } - - pub(crate) fn get_args(&self, incls: &[Id], force_optional: bool) -> Vec { - debug!("Usage::get_args: incls={incls:?}",); + debug!("Usage::write_args: incls={incls:?}",); use std::fmt::Write as _; let literal = &self.styles.get_literal(); @@ -381,17 +374,20 @@ impl<'cmd> Usage<'cmd> { } } - let mut ret_val = Vec::new(); if !force_optional { - ret_val.extend(required_opts); - ret_val.extend(required_groups); + for arg in required_opts { + styled.push_styled(&arg); + styled.push_str(" "); + } + for arg in required_groups { + styled.push_styled(&arg); + styled.push_str(" "); + } } - for pos in required_positionals.into_iter().flatten() { - ret_val.push(pos); + for arg in required_positionals.into_iter().flatten() { + styled.push_styled(&arg); + styled.push_str(" "); } - - debug!("Usage::get_args: ret_val={ret_val:?}"); - ret_val } pub(crate) fn get_required_usage_from( From 7472aba6ce83fccbdbb816d2ca83e922929a7f07 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 9 Nov 2023 12:00:52 -0600 Subject: [PATCH 07/12] refactor(help): Clarify usage condition --- clap_builder/src/output/usage.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clap_builder/src/output/usage.rs b/clap_builder/src/output/usage.rs index b8e02fa5cc6..2709c1bb94a 100644 --- a/clap_builder/src/output/usage.rs +++ b/clap_builder/src/output/usage.rs @@ -132,8 +132,8 @@ impl<'cmd> Usage<'cmd> { self.write_args(styled, &[], !incl_reqs); // incl_reqs is only false when this function is called recursively - if self.cmd.has_visible_subcommands() && incl_reqs - || self.cmd.is_allow_external_subcommands_set() + if (self.cmd.has_visible_subcommands() || self.cmd.is_allow_external_subcommands_set()) + && incl_reqs { let value_name = self .cmd From 0c668c39151cb9919ae0087d54bd8571019a16ed Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 9 Nov 2023 12:03:35 -0600 Subject: [PATCH 08/12] refactor(help): Pull out bin name logic --- clap_builder/src/output/usage.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/clap_builder/src/output/usage.rs b/clap_builder/src/output/usage.rs index 2709c1bb94a..bcff88dd2ba 100644 --- a/clap_builder/src/output/usage.rs +++ b/clap_builder/src/output/usage.rs @@ -105,16 +105,12 @@ impl<'cmd> Usage<'cmd> { let literal = &self.styles.get_literal(); let placeholder = &self.styles.get_placeholder(); - let name = self - .cmd - .get_usage_name() - .or_else(|| self.cmd.get_bin_name()) - .unwrap_or_else(|| self.cmd.get_name()); - if !name.is_empty() { + let bin_name = self.get_name(); + if !bin_name.is_empty() { // the trim won't properly remove a leading space due to the formatting let _ = write!( styled, - "{}{name}{} ", + "{}{bin_name}{} ", literal.render(), literal.render_reset() ); @@ -148,7 +144,7 @@ impl<'cmd> Usage<'cmd> { // Short-circuit full usage creation since no args will be relevant let _ = write!( styled, - "{}{name}{} ", + "{}{bin_name}{} ", literal.render(), literal.render_reset() ); @@ -187,11 +183,7 @@ impl<'cmd> Usage<'cmd> { let literal = &self.styles.get_literal(); let placeholder = &self.styles.get_placeholder(); - let bin_name = self - .cmd - .get_usage_name() - .or_else(|| self.cmd.get_bin_name()) - .unwrap_or_else(|| self.cmd.get_name()); + let bin_name = self.get_name(); let _ = write!( styled, "{}{bin_name}{} ", @@ -215,6 +207,13 @@ impl<'cmd> Usage<'cmd> { } } + fn get_name(&self) -> &str { + self.cmd + .get_usage_name() + .or_else(|| self.cmd.get_bin_name()) + .unwrap_or_else(|| self.cmd.get_name()) + } + // Determines if we need the `[OPTIONS]` tag in the usage string fn needs_options_tag(&self) -> bool { debug!("Usage::needs_options_tag"); From 83981a7f7bef20abe43e601614b4bd32882f9d9a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 9 Nov 2023 12:08:24 -0600 Subject: [PATCH 09/12] refactor: Pull out arg usage line --- clap_builder/src/output/usage.rs | 56 +++++++++++++++++++------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/clap_builder/src/output/usage.rs b/clap_builder/src/output/usage.rs index bcff88dd2ba..065c0301473 100644 --- a/clap_builder/src/output/usage.rs +++ b/clap_builder/src/output/usage.rs @@ -102,35 +102,15 @@ impl<'cmd> Usage<'cmd> { fn write_help_usage(&self, styled: &mut StyledStr, incl_reqs: bool) { debug!("Usage::create_help_usage; incl_reqs={incl_reqs:?}"); use std::fmt::Write as _; - let literal = &self.styles.get_literal(); - let placeholder = &self.styles.get_placeholder(); - let bin_name = self.get_name(); - if !bin_name.is_empty() { - // the trim won't properly remove a leading space due to the formatting - let _ = write!( - styled, - "{}{bin_name}{} ", - literal.render(), - literal.render_reset() - ); - } - - if self.needs_options_tag() { - let _ = write!( - styled, - "{}[OPTIONS]{} ", - placeholder.render(), - placeholder.render_reset() - ); - } - - self.write_args(styled, &[], !incl_reqs); + self.write_arg_usage(styled, incl_reqs); // incl_reqs is only false when this function is called recursively if (self.cmd.has_visible_subcommands() || self.cmd.is_allow_external_subcommands_set()) && incl_reqs { + let literal = &self.styles.get_literal(); + let placeholder = &self.styles.get_placeholder(); let value_name = self .cmd .get_subcommand_value_name() @@ -141,6 +121,7 @@ impl<'cmd> Usage<'cmd> { styled.trim_end(); let _ = write!(styled, "{}", USAGE_SEP); if self.cmd.is_args_conflicts_with_subcommands_set() { + let bin_name = self.get_name(); // Short-circuit full usage creation since no args will be relevant let _ = write!( styled, @@ -207,6 +188,35 @@ impl<'cmd> Usage<'cmd> { } } + fn write_arg_usage(&self, styled: &mut StyledStr, incl_reqs: bool) { + debug!("Usage::write_arg_usage; incl_reqs={incl_reqs:?}"); + use std::fmt::Write as _; + let literal = &self.styles.get_literal(); + let placeholder = &self.styles.get_placeholder(); + + let bin_name = self.get_name(); + if !bin_name.is_empty() { + // the trim won't properly remove a leading space due to the formatting + let _ = write!( + styled, + "{}{bin_name}{} ", + literal.render(), + literal.render_reset() + ); + } + + if self.needs_options_tag() { + let _ = write!( + styled, + "{}[OPTIONS]{} ", + placeholder.render(), + placeholder.render_reset() + ); + } + + self.write_args(styled, &[], !incl_reqs); + } + fn get_name(&self) -> &str { self.cmd .get_usage_name() From 25e3a87d3c9bf5d55c9904e160e9390a5ff1524f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 9 Nov 2023 12:14:25 -0600 Subject: [PATCH 10/12] refactor(help): Consolidate arg line usage generation --- clap_builder/src/output/usage.rs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/clap_builder/src/output/usage.rs b/clap_builder/src/output/usage.rs index 065c0301473..7739d3f1015 100644 --- a/clap_builder/src/output/usage.rs +++ b/clap_builder/src/output/usage.rs @@ -103,7 +103,7 @@ impl<'cmd> Usage<'cmd> { debug!("Usage::create_help_usage; incl_reqs={incl_reqs:?}"); use std::fmt::Write as _; - self.write_arg_usage(styled, incl_reqs); + self.write_arg_usage(styled, &[], incl_reqs); // incl_reqs is only false when this function is called recursively if (self.cmd.has_visible_subcommands() || self.cmd.is_allow_external_subcommands_set()) @@ -161,18 +161,9 @@ impl<'cmd> Usage<'cmd> { fn write_smart_usage(&self, styled: &mut StyledStr, used: &[Id]) { debug!("Usage::create_smart_usage"); use std::fmt::Write; - let literal = &self.styles.get_literal(); let placeholder = &self.styles.get_placeholder(); - let bin_name = self.get_name(); - let _ = write!( - styled, - "{}{bin_name}{} ", - literal.render(), - literal.render_reset() - ); - - self.write_args(styled, used, false); + self.write_arg_usage(styled, used, true); if self.cmd.is_subcommand_required_set() { let value_name = self @@ -188,7 +179,7 @@ impl<'cmd> Usage<'cmd> { } } - fn write_arg_usage(&self, styled: &mut StyledStr, incl_reqs: bool) { + fn write_arg_usage(&self, styled: &mut StyledStr, used: &[Id], incl_reqs: bool) { debug!("Usage::write_arg_usage; incl_reqs={incl_reqs:?}"); use std::fmt::Write as _; let literal = &self.styles.get_literal(); @@ -205,7 +196,7 @@ impl<'cmd> Usage<'cmd> { ); } - if self.needs_options_tag() { + if used.is_empty() && self.needs_options_tag() { let _ = write!( styled, "{}[OPTIONS]{} ", @@ -214,7 +205,7 @@ impl<'cmd> Usage<'cmd> { ); } - self.write_args(styled, &[], !incl_reqs); + self.write_args(styled, used, !incl_reqs); } fn get_name(&self) -> &str { From d9685bcc71df19af85d870faf89a6ac0353d5a8b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 9 Nov 2023 12:20:53 -0600 Subject: [PATCH 11/12] refactor(help): Bypass outer usage layer --- clap_builder/src/output/usage.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/clap_builder/src/output/usage.rs b/clap_builder/src/output/usage.rs index 7739d3f1015..7fdccfc2dd9 100644 --- a/clap_builder/src/output/usage.rs +++ b/clap_builder/src/output/usage.rs @@ -81,7 +81,7 @@ impl<'cmd> Usage<'cmd> { #[cfg(feature = "usage")] { if used.is_empty() { - self.write_help_usage(styled, true); + self.write_help_usage(styled); } else { self.write_smart_usage(styled, used); } @@ -99,16 +99,14 @@ impl<'cmd> Usage<'cmd> { #[cfg(feature = "usage")] impl<'cmd> Usage<'cmd> { // Creates a usage string for display in help messages (i.e. not for errors) - fn write_help_usage(&self, styled: &mut StyledStr, incl_reqs: bool) { - debug!("Usage::create_help_usage; incl_reqs={incl_reqs:?}"); + fn write_help_usage(&self, styled: &mut StyledStr) { + debug!("Usage::write_help_usage"); use std::fmt::Write as _; - self.write_arg_usage(styled, &[], incl_reqs); + self.write_arg_usage(styled, &[], true); // incl_reqs is only false when this function is called recursively - if (self.cmd.has_visible_subcommands() || self.cmd.is_allow_external_subcommands_set()) - && incl_reqs - { + if self.cmd.has_visible_subcommands() || self.cmd.is_allow_external_subcommands_set() { let literal = &self.styles.get_literal(); let placeholder = &self.styles.get_placeholder(); let value_name = self @@ -130,7 +128,7 @@ impl<'cmd> Usage<'cmd> { literal.render_reset() ); } else { - self.write_help_usage(styled, false); + self.write_arg_usage(styled, &[], false); } let _ = write!( styled, From c1c2e95ab685722c05f220575d2e90d50e5e9bcb Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 9 Nov 2023 12:23:35 -0600 Subject: [PATCH 12/12] refactor(help): Pull out subcommand usage logic --- clap_builder/src/output/usage.rs | 103 ++++++++++++++++--------------- 1 file changed, 54 insertions(+), 49 deletions(-) diff --git a/clap_builder/src/output/usage.rs b/clap_builder/src/output/usage.rs index 7fdccfc2dd9..4bb901f812b 100644 --- a/clap_builder/src/output/usage.rs +++ b/clap_builder/src/output/usage.rs @@ -101,57 +101,9 @@ impl<'cmd> Usage<'cmd> { // Creates a usage string for display in help messages (i.e. not for errors) fn write_help_usage(&self, styled: &mut StyledStr) { debug!("Usage::write_help_usage"); - use std::fmt::Write as _; self.write_arg_usage(styled, &[], true); - - // incl_reqs is only false when this function is called recursively - if self.cmd.has_visible_subcommands() || self.cmd.is_allow_external_subcommands_set() { - let literal = &self.styles.get_literal(); - let placeholder = &self.styles.get_placeholder(); - let value_name = self - .cmd - .get_subcommand_value_name() - .unwrap_or(DEFAULT_SUB_VALUE_NAME); - if self.cmd.is_subcommand_negates_reqs_set() - || self.cmd.is_args_conflicts_with_subcommands_set() - { - styled.trim_end(); - let _ = write!(styled, "{}", USAGE_SEP); - if self.cmd.is_args_conflicts_with_subcommands_set() { - let bin_name = self.get_name(); - // Short-circuit full usage creation since no args will be relevant - let _ = write!( - styled, - "{}{bin_name}{} ", - literal.render(), - literal.render_reset() - ); - } else { - self.write_arg_usage(styled, &[], false); - } - let _ = write!( - styled, - "{}<{value_name}>{}", - placeholder.render(), - placeholder.render_reset() - ); - } else if self.cmd.is_subcommand_required_set() { - let _ = write!( - styled, - "{}<{value_name}>{}", - placeholder.render(), - placeholder.render_reset() - ); - } else { - let _ = write!( - styled, - "{}[{value_name}]{}", - placeholder.render(), - placeholder.render_reset() - ); - } - } + self.write_subcommand_usage(styled); } // Creates a context aware usage string, or "smart usage" from currently used @@ -206,6 +158,59 @@ impl<'cmd> Usage<'cmd> { self.write_args(styled, used, !incl_reqs); } + fn write_subcommand_usage(&self, styled: &mut StyledStr) { + debug!("Usage::write_subcommand_usage"); + use std::fmt::Write as _; + + // incl_reqs is only false when this function is called recursively + if self.cmd.has_visible_subcommands() || self.cmd.is_allow_external_subcommands_set() { + let literal = &self.styles.get_literal(); + let placeholder = &self.styles.get_placeholder(); + let value_name = self + .cmd + .get_subcommand_value_name() + .unwrap_or(DEFAULT_SUB_VALUE_NAME); + if self.cmd.is_subcommand_negates_reqs_set() + || self.cmd.is_args_conflicts_with_subcommands_set() + { + styled.trim_end(); + let _ = write!(styled, "{}", USAGE_SEP); + if self.cmd.is_args_conflicts_with_subcommands_set() { + let bin_name = self.get_name(); + // Short-circuit full usage creation since no args will be relevant + let _ = write!( + styled, + "{}{bin_name}{} ", + literal.render(), + literal.render_reset() + ); + } else { + self.write_arg_usage(styled, &[], false); + } + let _ = write!( + styled, + "{}<{value_name}>{}", + placeholder.render(), + placeholder.render_reset() + ); + } else if self.cmd.is_subcommand_required_set() { + let _ = write!( + styled, + "{}<{value_name}>{}", + placeholder.render(), + placeholder.render_reset() + ); + } else { + let _ = write!( + styled, + "{}[{value_name}]{}", + placeholder.render(), + placeholder.render_reset() + ); + } + } + } + fn get_name(&self) -> &str { self.cmd .get_usage_name()