Only show global options in the top-level help output.

- Fixes #202.
This commit is contained in:
Neal H. Walfield 2024-02-21 11:35:30 +01:00
parent 19f8893c46
commit 0382001a65
No known key found for this signature in database
GPG Key ID: 6863C9AD5B4D22D3
3 changed files with 72 additions and 4 deletions

View File

@ -23,7 +23,7 @@ fn main() {
subplot_build::codegen("sq.subplot") subplot_build::codegen("sq.subplot")
.expect("failed to generate code with Subplot"); .expect("failed to generate code with Subplot");
let mut sq = cli::build(); let mut sq = cli::build(false);
generate_shell_completions(&mut sq).unwrap(); generate_shell_completions(&mut sq).unwrap();
generate_man_pages(&sq).unwrap(); generate_man_pages(&sq).unwrap();
} }

View File

@ -125,7 +125,12 @@ pub const THIRD_PARTY_CERTIFICATION_VALIDITY_DURATION: Duration = Duration::new(
pub const GLOBAL_OPTIONS_HEADER: &str = "Global Options"; pub const GLOBAL_OPTIONS_HEADER: &str = "Global Options";
pub fn build() -> Command { /// Builds the top-level Clap command.
///
/// If `globals_hidden` is true, then top-level, global arguments are
/// marked as hidden, which means they won't be displayed in the help
/// output.
pub fn build(globals_hidden: bool) -> Command {
let sq_version = Box::leak( let sq_version = Box::leak(
format!( format!(
"{} (sequoia-openpgp {}, using {})", "{} (sequoia-openpgp {}, using {})",
@ -135,7 +140,20 @@ pub fn build() -> Command {
) )
.into_boxed_str(), .into_boxed_str(),
) as &str; ) as &str;
SqCommand::command().version(sq_version)
let mut command = SqCommand::command().version(sq_version);
// Change the globals to be hidden.
if globals_hidden {
command = command.mut_args(|mut a| {
if a.is_global_set() {
a = a.hide(globals_hidden);
}
a
});
};
command
} }
/// Defines the CLI. /// Defines the CLI.

View File

@ -1053,7 +1053,57 @@ impl<'store> Config<'store> {
// TODO: Use `derive`d command structs. No more values_of // TODO: Use `derive`d command structs. No more values_of
// TODO: Handling (and cli position) of global arguments // TODO: Handling (and cli position) of global arguments
fn main() -> Result<()> { fn main() -> Result<()> {
let c = cli::SqCommand::from_arg_matches(&cli::build().get_matches())?; let mut cli = cli::build(true);
let matches = cli.clone().try_get_matches();
let c = match matches {
Ok(matches) => {
cli::SqCommand::from_arg_matches(&matches)?
}
Err(err) => {
// Warning: hack ahead!
//
// If we are showing the help output, we only want to
// display the global options at the top-level; for
// subcommands we hide the global options to not overwhelm
// the user.
//
// Ideally, clap would provide a mechanism to only show
// the help output for global options at the level they
// are defined at. That's not the case.
//
// We can use `err` to figure out if we are showing the
// help output, but it doesn't tell us what subcommand we
// are showing the help for. Instead (and here's the
// hack!), we compare the output. If it is the output for
// the top-level `--help` or `-h`, then we are showing the
// help for the top-level. If not, then we are showing
// the help for a subcommand. In the former case, we
// unhide the global options.
use clap::error::ErrorKind;
if err.kind() == ErrorKind::DisplayHelp
|| err.kind() == ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
{
let output = err.render();
let output = if output == cli.render_long_help() {
Some(cli::build(false).render_long_help())
} else if output == cli.render_help() {
Some(cli::build(false).render_help())
} else {
None
};
if let Some(output) = output {
if err.use_stderr() {
eprint!("{}", output);
} else {
print!("{}", output);
}
std::process::exit(err.exit_code());
}
}
err.exit();
}
};
let time: SystemTime = let time: SystemTime =
c.time.clone().unwrap_or_else(|| Time::now()).into(); c.time.clone().unwrap_or_else(|| Time::now()).into();