From d857e496d45d37daf6ddb95c4b93eea387a52703 Mon Sep 17 00:00:00 2001 From: Connor Gray Date: Thu, 1 May 2025 22:28:21 -0500 Subject: [PATCH] polish: Add `show_aliases` option + change where aliases appear --- docs/examples/complex-app-custom.md | 4 +- docs/examples/complex-app.md | 6 ++- src/lib.rs | 69 ++++++++++++++++------------- src/utils.rs | 6 +++ tests/test_examples.rs | 1 + 5 files changed, 51 insertions(+), 35 deletions(-) create mode 100644 src/utils.rs diff --git a/docs/examples/complex-app-custom.md b/docs/examples/complex-app-custom.md index 7161fb2..fc1dd07 100644 --- a/docs/examples/complex-app-custom.md +++ b/docs/examples/complex-app-custom.md @@ -10,7 +10,7 @@ An example command-line tool ###### **Subcommands:** -* `test` [alias: `tester`] — does testing things +* `test` — does testing things * `only-hidden-options` — Demo that `Options` is not printed if all options are hidden ###### **Arguments:** @@ -38,7 +38,7 @@ An example command-line tool -## `complex-app test` [alias: `tester`] +## `complex-app test` does testing things diff --git a/docs/examples/complex-app.md b/docs/examples/complex-app.md index edd8156..a2fd3a9 100644 --- a/docs/examples/complex-app.md +++ b/docs/examples/complex-app.md @@ -16,7 +16,7 @@ An example command-line tool ###### **Subcommands:** -* `test` [alias: `tester`] — does testing things +* `test` — does testing things * `only-hidden-options` — Demo that `Options` is not printed if all options are hidden ###### **Arguments:** @@ -44,12 +44,14 @@ An example command-line tool -## `complex-app test` [alias: `tester`] +## `complex-app test` does testing things **Usage:** `complex-app test [OPTIONS]` +**Command Alias:** `tester` + ###### **Options:** * `-l`, `--list` — lists test values diff --git a/src/lib.rs b/src/lib.rs index af34d74..207cd95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,10 +12,14 @@ mod test_readme { #![doc = include_str!("../README.md")] } +mod utils; + use std::fmt::{self, Write}; use clap::builder::PossibleValue; +use utils::pluralize; + //====================================== // Public API types //====================================== @@ -28,6 +32,7 @@ pub struct MarkdownOptions { title: Option, show_footer: bool, show_table_of_contents: bool, + show_aliases: bool, } impl MarkdownOptions { @@ -37,6 +42,7 @@ impl MarkdownOptions { title: None, show_footer: true, show_table_of_contents: true, + show_aliases: true, }; } @@ -60,6 +66,13 @@ impl MarkdownOptions { return self; } + + /// Whether to show aliases for arguments and commands. + pub fn show_aliases(mut self, show: bool) -> Self { + self.show_aliases = show; + + return self; + } } impl Default for MarkdownOptions { @@ -166,7 +179,7 @@ fn write_help_markdown( // Write the commands/subcommands sections //---------------------------------------- - build_command_markdown(buffer, Vec::new(), command, 0).unwrap(); + build_command_markdown(buffer, Vec::new(), command, 0, options).unwrap(); //----------------- // Write the footer @@ -278,6 +291,7 @@ fn build_command_markdown( parent_command_path: Vec, command: &clap::Command, depth: usize, + options: &MarkdownOptions, ) -> std::fmt::Result { // Don't document commands marked with `clap(hide = true)` (which includes // `print-all-help`). @@ -307,12 +321,7 @@ fn build_command_markdown( ) } */ - let aliases = command.get_visible_aliases().collect::>(); - let aliases = get_alias_str(&aliases) - .map(|s| format!(" {s}")) - .unwrap_or_default(); - - writeln!(buffer, "## `{}`{aliases}\n", command_path.join(" "),)?; + writeln!(buffer, "## `{}`\n", command_path.join(" "))?; if let Some(long_about) = command.get_long_about() { writeln!(buffer, "{}\n", long_about)?; @@ -343,6 +352,17 @@ fn build_command_markdown( .replace("Usage: ", "") )?; + if options.show_aliases { + let aliases = command.get_visible_aliases().collect::>(); + if let Some(aliases_str) = get_alias_string(&aliases) { + writeln!( + buffer, + "**{}:** {aliases_str}\n", + pluralize(aliases.len(), "Command Alias", "Command Aliases") + )?; + } + } + if let Some(help) = command.get_after_long_help() { writeln!(buffer, "{}\n", help)?; } else if let Some(help) = command.get_after_help() { @@ -362,17 +382,13 @@ fn build_command_markdown( } let title_name = get_canonical_name(subcommand); - let aliases = subcommand.get_visible_aliases().collect::>(); - let aliases = get_alias_str(&aliases) - .map(|s| format!(" {s}")) - .unwrap_or_default(); let about = match subcommand.get_about() { Some(about) => about.to_string(), None => String::new(), }; - writeln!(buffer, "* `{title_name}`{aliases} — {about}",)?; + writeln!(buffer, "* `{title_name}` — {about}",)?; } write!(buffer, "\n")?; @@ -425,6 +441,7 @@ fn build_command_markdown( command_path.clone(), subcommand, depth + 1, + options, )?; } @@ -474,8 +491,12 @@ fn write_arg_markdown(buffer: &mut String, arg: &clap::Arg) -> fmt::Result { } if let Some(aliases) = arg.get_visible_aliases().as_deref() { - if let Some(aliases) = get_alias_str(aliases) { - write!(buffer, " {aliases}")?; + if let Some(aliases_str) = get_alias_string(aliases) { + write!( + buffer, + " [{}: {aliases_str}]", + pluralize(aliases.len(), "alias", "aliases") + )?; } } @@ -605,30 +626,16 @@ fn indent(s: &str, first: &str, rest: &str) -> String { result } -fn wrap_with(s: &str, wrapper: &str) -> String { - format!("{wrapper}{s}{wrapper}") -} - -fn wrap_with_backticks(s: &str) -> String { - wrap_with(s, "`") -} - -fn get_alias_str(aliases: &[&str]) -> Option { +fn get_alias_string(aliases: &[&str]) -> Option { if aliases.is_empty() { return None; } - let prefix = if aliases.len() == 1 { - "alias" - } else { - "aliases" - }; - Some(format!( - "[{prefix}: {}]", + "{}", aliases .iter() - .map(|s| wrap_with_backticks(s)) + .map(|alias| format!("`{alias}`")) .collect::>() .join(", ") )) diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..ef17f17 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,6 @@ +pub fn pluralize(len: usize, singular: T, plural: T) -> T { + match len { + 1 => singular, + _ => plural, + } +} diff --git a/tests/test_examples.rs b/tests/test_examples.rs index b63b386..a4b91f2 100644 --- a/tests/test_examples.rs +++ b/tests/test_examples.rs @@ -20,6 +20,7 @@ fn test_example_complex_app() { .title("Some Custom Title for Complex App".to_string()) .show_footer(false) .show_table_of_contents(false) + .show_aliases(false) ), include_str!("../docs/examples/complex-app-custom.md"), "Mismatch testing CUSTOM Markdown output"