From 0c82929fe4381528eb835f2313783ff9f5eaffe4 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Mon, 8 Jul 2024 17:29:42 -0500 Subject: [PATCH] feat: show user defined help flags during help hints if present --- clap_builder/src/error/format.rs | 28 +++++++++++++++++++++++----- clap_builder/src/error/mod.rs | 4 ++-- tests/builder/help.rs | 8 +++++++- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/clap_builder/src/error/format.rs b/clap_builder/src/error/format.rs index 0f8644f6adc..b1e3037411c 100644 --- a/clap_builder/src/error/format.rs +++ b/clap_builder/src/error/format.rs @@ -3,6 +3,8 @@ #![cfg_attr(not(feature = "error-context"), allow(dead_code))] #![cfg_attr(not(feature = "error-context"), allow(unused_imports))] +use std::borrow::Cow; + use crate::builder::Command; use crate::builder::StyledStr; use crate::builder::Styles; @@ -12,6 +14,7 @@ use crate::error::ContextKind; use crate::error::ContextValue; use crate::error::ErrorKind; use crate::output::TAB; +use crate::ArgAction; /// Defines how to format an error for displaying to the user pub trait ErrorFormatter: Sized { @@ -120,7 +123,7 @@ impl ErrorFormatter for RichFormatter { put_usage(&mut styled, usage); } - try_help(&mut styled, styles, error.inner.help_flag); + try_help(&mut styled, styles, error.inner.help_flag.as_deref()); styled } @@ -461,7 +464,7 @@ pub(crate) fn format_error_message( put_usage(&mut styled, usage); } if let Some(cmd) = cmd { - try_help(&mut styled, styles, get_help_flag(cmd)); + try_help(&mut styled, styles, get_help_flag(cmd).as_deref()); } styled } @@ -480,16 +483,31 @@ fn put_usage(styled: &mut StyledStr, usage: &StyledStr) { styled.push_styled(usage); } -pub(crate) fn get_help_flag(cmd: &Command) -> Option<&'static str> { +pub(crate) fn get_help_flag(cmd: &Command) -> Option> { if !cmd.is_disable_help_flag_set() { - Some("--help") + Some(Cow::Borrowed("--help")) + } else if let Some(flag) = get_user_help_flag(cmd) { + Some(Cow::Owned(flag)) } else if cmd.has_subcommands() && !cmd.is_disable_help_subcommand_set() { - Some("help") + Some(Cow::Borrowed("help")) } else { None } } +fn get_user_help_flag(cmd: &Command) -> Option { + let arg = cmd.get_arguments().find(|arg| { + matches!( + arg.get_action(), + ArgAction::Help | ArgAction::HelpShort | ArgAction::HelpLong + ) + })?; + + arg.get_long() + .map(|long| format!("--{long}")) + .or_else(|| arg.get_short().map(|short| format!("-{short}"))) +} + fn try_help(styled: &mut StyledStr, styles: &Styles, help: Option<&str>) { if let Some(help) = help { use std::fmt::Write as _; diff --git a/clap_builder/src/error/mod.rs b/clap_builder/src/error/mod.rs index 1e8fcd57bab..cfba5a818b4 100644 --- a/clap_builder/src/error/mod.rs +++ b/clap_builder/src/error/mod.rs @@ -69,7 +69,7 @@ struct ErrorInner { context: FlatMap, message: Option, source: Option>, - help_flag: Option<&'static str>, + help_flag: Option>, styles: Styles, color_when: ColorChoice, color_help_when: ColorChoice, @@ -319,7 +319,7 @@ impl Error { self } - pub(crate) fn set_help_flag(mut self, help_flag: Option<&'static str>) -> Self { + pub(crate) fn set_help_flag(mut self, help_flag: Option>) -> Self { self.inner.help_flag = help_flag; self } diff --git a/tests/builder/help.rs b/tests/builder/help.rs index d1f53de4583..4b336031a01 100644 --- a/tests/builder/help.rs +++ b/tests/builder/help.rs @@ -374,6 +374,8 @@ fn try_help_custom_flag() { error: unexpected argument 'bar' found Usage: ctest + +For more information, try '--help'. "; let cmd = Command::new("ctest") @@ -395,6 +397,8 @@ fn try_help_custom_flag_short() { error: unexpected argument 'bar' found Usage: ctest + +For more information, try '-h'. "; let cmd = Command::new("ctest") @@ -411,6 +415,8 @@ fn try_help_custom_flag_long() { error: unexpected argument 'bar' found Usage: ctest + +For more information, try '--help'. "; let cmd = Command::new("ctest") @@ -462,7 +468,7 @@ error: unrecognized subcommand 'bar' Usage: ctest [COMMAND] -For more information, try 'help'. +For more information, try '--help'. "; let cmd = Command::new("ctest")