From 22b545b98b71b0e58b0f3a855a199a5d834ad7e8 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Jul 2023 10:37:26 -0500 Subject: [PATCH] feat(help): Explicit control over short/long help Fixes #4687 --- clap_builder/src/builder/action.rs | 62 ++++++++++++++++++++++++++++++ clap_builder/src/parser/parser.rs | 10 +++++ tests/builder/help.rs | 59 ++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) diff --git a/clap_builder/src/builder/action.rs b/clap_builder/src/builder/action.rs index 79ee9238e47..2def801f401 100644 --- a/clap_builder/src/builder/action.rs +++ b/clap_builder/src/builder/action.rs @@ -257,6 +257,58 @@ pub enum ArgAction { /// # } /// ``` Help, + /// When encountered, display [`Command::print_help`][super::Command::print_help] + /// + /// # Examples + /// + /// ```rust + /// # #[cfg(feature = "help")] { + /// # use clap_builder as clap; + /// # use clap::Command; + /// # use clap::Arg; + /// let cmd = Command::new("mycmd") + /// .arg( + /// Arg::new("special-help") + /// .short('?') + /// .action(clap::ArgAction::HelpShort) + /// ); + /// + /// // Existing help still exists + /// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err(); + /// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp); + /// + /// // New help available + /// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err(); + /// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp); + /// # } + /// ``` + HelpShort, + /// When encountered, display [`Command::print_long_help`][super::Command::print_long_help] + /// + /// # Examples + /// + /// ```rust + /// # #[cfg(feature = "help")] { + /// # use clap_builder as clap; + /// # use clap::Command; + /// # use clap::Arg; + /// let cmd = Command::new("mycmd") + /// .arg( + /// Arg::new("special-help") + /// .short('?') + /// .action(clap::ArgAction::HelpLong) + /// ); + /// + /// // Existing help still exists + /// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err(); + /// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp); + /// + /// // New help available + /// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err(); + /// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp); + /// # } + /// ``` + HelpLong, /// When encountered, display [`Command::version`][super::Command::version] /// /// Depending on the flag, [`Command::long_version`][super::Command::long_version] may be shown @@ -299,6 +351,8 @@ impl ArgAction { Self::SetFalse => false, Self::Count => false, Self::Help => false, + Self::HelpShort => false, + Self::HelpLong => false, Self::Version => false, } } @@ -311,6 +365,8 @@ impl ArgAction { Self::SetFalse => Some(std::ffi::OsStr::new("true")), Self::Count => Some(std::ffi::OsStr::new("0")), Self::Help => None, + Self::HelpShort => None, + Self::HelpLong => None, Self::Version => None, } } @@ -323,6 +379,8 @@ impl ArgAction { Self::SetFalse => Some(std::ffi::OsStr::new("false")), Self::Count => None, Self::Help => None, + Self::HelpShort => None, + Self::HelpLong => None, Self::Version => None, } } @@ -335,6 +393,8 @@ impl ArgAction { Self::SetFalse => Some(super::ValueParser::bool()), Self::Count => Some(crate::value_parser!(u8).into()), Self::Help => None, + Self::HelpShort => None, + Self::HelpLong => None, Self::Version => None, } } @@ -348,6 +408,8 @@ impl ArgAction { Self::SetFalse => None, Self::Count => Some(AnyValueId::of::()), Self::Help => None, + Self::HelpShort => None, + Self::HelpLong => None, Self::Version => None, } } diff --git a/clap_builder/src/parser/parser.rs b/clap_builder/src/parser/parser.rs index d2e198b2885..3e02d4c0bf7 100644 --- a/clap_builder/src/parser/parser.rs +++ b/clap_builder/src/parser/parser.rs @@ -1237,6 +1237,16 @@ impl<'cmd> Parser<'cmd> { debug!("Help: use_long={use_long}"); Err(self.help_err(use_long)) } + ArgAction::HelpShort => { + let use_long = false; + debug!("Help: use_long={use_long}"); + Err(self.help_err(use_long)) + } + ArgAction::HelpLong => { + let use_long = true; + debug!("Help: use_long={use_long}"); + Err(self.help_err(use_long)) + } ArgAction::Version => { let use_long = match ident { Some(Identifier::Long) => true, diff --git a/tests/builder/help.rs b/tests/builder/help.rs index 401bc432ff2..b4e6e358525 100644 --- a/tests/builder/help.rs +++ b/tests/builder/help.rs @@ -1063,6 +1063,65 @@ Options: utils::assert_output(cmd, "myapp --help", LONG_ABOUT, false); } +#[test] +fn explicit_short_long_help() { + static SHORT_ABOUT: &str = "\ +bar + +Usage: myapp [OPTIONS] [arg1] + +Arguments: + [arg1] some option + +Options: + -? + -h, --help + -V, --version Print version +"; + + static LONG_ABOUT: &str = "\ +something really really long, with +multiple lines of text +that should be displayed + +Usage: myapp [OPTIONS] [arg1] + +Arguments: + [arg1] + some option + +Options: + -? + + + -h, --help + + + -V, --version + Print version +"; + + let cmd = Command::new("myapp") + .disable_help_flag(true) + .version("1.0") + .author("foo") + .about("bar") + .long_about( + "something really really long, with\nmultiple lines of text\nthat should be displayed", + ) + .arg(Arg::new("arg1").help("some option")) + .arg(Arg::new("short").short('?').action(ArgAction::HelpShort)) + .arg( + Arg::new("long") + .short('h') + .long("help") + .action(ArgAction::HelpLong), + ); + utils::assert_output(cmd.clone(), "myapp -?", SHORT_ABOUT, false); + utils::assert_output(cmd.clone(), "myapp -h", LONG_ABOUT, false); + utils::assert_output(cmd, "myapp --help", LONG_ABOUT, false); +} + #[test] fn ripgrep_usage() { static RIPGREP_USAGE: &str = "\