feat(help): Explicit control over short/long help

Fixes #4687
This commit is contained in:
Ed Page 2023-07-17 10:37:26 -05:00
parent c2191674b0
commit 22b545b98b
3 changed files with 131 additions and 0 deletions

View file

@ -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::<CountType>()),
Self::Help => None,
Self::HelpShort => None,
Self::HelpLong => None,
Self::Version => None,
}
}

View file

@ -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,

View file

@ -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 = "\