From 31f2df96ea6df7310c0ecd6a2aea27d13fc77287 Mon Sep 17 00:00:00 2001 From: Juan Ibiapina Date: Wed, 15 May 2024 23:09:39 +0200 Subject: [PATCH] feat: Rewrite help for file commands using clap --- integration/help.bats | 46 +++++++++++++++++++++-------------- src/commands/directory.rs | 51 +++++++++++++++++++++++++++++++++++++-- src/commands/file.rs | 6 ++++- src/commands/mod.rs | 42 +------------------------------- src/parser.rs | 6 ++--- src/usage.rs | 2 +- 6 files changed, 87 insertions(+), 66 deletions(-) diff --git a/integration/help.bats b/integration/help.bats index 09608e3..0e7f3a6 100644 --- a/integration/help.bats +++ b/integration/help.bats @@ -38,7 +38,13 @@ Available subcommands: run main --help no-doc assert_success - assert_output "Usage: main no-doc [args]..." + assert_output "Usage: main no-doc [args]... + +Arguments: + [args]... + +Options: + -h, --help Print help" } @test "help: displays help for a subcommand" { @@ -47,26 +53,18 @@ Available subcommands: run main --help with-help assert_success - assert_output "Usage: main with-help + assert_output "Command with complete help -Command with complete help +Usage: main with-help + +Options: + -h, --help Print help This is a complete test script with documentation. The help section can span multiple lines." } -@test "help: displays summary for subcommand if help is not available" { - fixture "project" - - run main --help only-summary - - assert_success - assert_output "Usage: main only-summary [args]... - -Return with error 4" -} - @test "help: fails gracefully when requested command doesn't exist" { fixture "project" @@ -101,9 +99,15 @@ Available subcommands: run main --help directory with-help assert_success - assert_output "Usage: main directory with-help [args]... + assert_output "Help 2 + +Usage: main directory with-help [args]... -Help 2 +Arguments: + [args]... + +Options: + -h, --help Print help This is a complete test script with documentation. @@ -134,9 +138,15 @@ Available subcommands: run main --help directory double with-help assert_success - assert_output "Usage: main directory double with-help [args]... + assert_output "Help 3 + +Usage: main directory double with-help [args]... + +Arguments: + [args]... -Help 3 +Options: + -h, --help Print help This is a complete test script with documentation. diff --git a/src/commands/directory.rs b/src/commands/directory.rs index 148aff5..49c9565 100644 --- a/src/commands/directory.rs +++ b/src/commands/directory.rs @@ -29,7 +29,7 @@ impl<'a> DirectoryCommand<'a> { } if let Some(description) = docs.description { - command = command.long_about(description); + command = command.after_help(description); } } @@ -58,7 +58,54 @@ impl<'a> Command for DirectoryCommand<'a> { } fn description(&self) -> String { - self.usage.command().get_long_about().map(|s| s.ansi().to_string()).unwrap_or_default() + self.usage.command().get_after_help().map(|s| s.ansi().to_string()).unwrap_or_default() + } + + fn help(&self) -> String { + let mut help = String::new(); + + let usage = self.usage(); + if !usage.is_empty() { + help.push_str(&usage); + help.push_str("\n\n"); + } + + let summary = self.summary(); + if !summary.is_empty() { + help.push_str(&summary); + help.push_str("\n\n"); + } + + let description = self.description(); + if !description.is_empty() { + help.push_str(&description); + help.push_str("\n\n"); + } + + let subcommands = self.subcommands(); + if !subcommands.is_empty() { + help.push_str("Available subcommands:\n"); + + let max_width = subcommands + .iter() + .map(|subcommand| subcommand.name()) + .map(|name| name.len()) + .max() + .unwrap(); + + let width = max_width + 4; + + for subcommand in subcommands { + help.push_str(&format!( + " {:width$}{}\n", + subcommand.name(), + subcommand.summary(), + width = width + )); + } + } + + help } fn subcommands(&self) -> Vec> { diff --git a/src/commands/file.rs b/src/commands/file.rs index 42a69a0..ccfa020 100644 --- a/src/commands/file.rs +++ b/src/commands/file.rs @@ -47,7 +47,11 @@ impl<'a> Command for FileCommand<'a> { } fn description(&self) -> String { - self.usage.command().get_long_about().map(|s| s.ansi().to_string()).unwrap_or_default() + self.usage.command().get_after_help().map(|s| s.ansi().to_string()).unwrap_or_default() + } + + fn help(&self) -> String { + self.usage.command().render_help().ansi().to_string() } fn subcommands(&self) -> Vec> { diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 5c57725..3b4e7ca 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -17,47 +17,7 @@ pub trait Command { fn subcommands(&self) -> Vec>; fn completions(&self) -> Result; fn invoke(&self) -> Result; - - fn help(&self) -> String { - let mut help = String::new(); - - let usage = self.usage(); - if !usage.is_empty() { - help.push_str(&usage); - help.push_str("\n\n"); - } - - let summary = self.summary(); - if !summary.is_empty() { - help.push_str(&summary); - help.push_str("\n\n"); - } - - let description = self.description(); - if !description.is_empty() { - help.push_str(&description); - } - - let subcommands = self.subcommands(); - if !subcommands.is_empty() { - help.push_str("\n\nAvailable subcommands:\n"); - - let max_width = subcommands - .iter() - .map(|subcommand| subcommand.name()) - .map(|name| name.len()) - .max() - .unwrap(); - - let width = max_width + 4; - - for subcommand in subcommands { - help.push_str(&format!(" {:width$}{}\n", subcommand.name(), subcommand.summary(), width = width)); - } - } - - help - } + fn help(&self) -> String; } pub fn subcommand(config: &Config, mut cliargs: Vec) -> Result> { diff --git a/src/parser.rs b/src/parser.rs index 7b96061..c5a4e3e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -59,7 +59,7 @@ pub fn extract_docs(path: &Path) -> Docs { if let Some(caps) = SUMMARY_RE.captures(&line) { if let Some(m) = caps.get(1) { - summary = Some(m.as_str().to_owned()); + summary = Some(m.as_str().trim().to_owned()); continue; } } @@ -71,7 +71,7 @@ pub fn extract_docs(path: &Path) -> Docs { if let Some(caps) = EXTENDED_RE.captures(&line) { if let Some(m) = caps.get(1) { - description.push(m.as_str().to_owned()); + description.push(m.as_str().trim().to_owned()); mode = Mode::Description; continue; } @@ -86,7 +86,7 @@ pub fn extract_docs(path: &Path) -> Docs { if let Some(caps) = EXTENDED_RE.captures(&line) { if let Some(m) = caps.get(1) { - description.push(m.as_str().to_owned()); + description.push(m.as_str().trim().to_owned()); continue; } } diff --git a/src/usage.rs b/src/usage.rs index b3477ff..40c9f75 100644 --- a/src/usage.rs +++ b/src/usage.rs @@ -74,7 +74,7 @@ pub fn extract_usage(config: &Config, path: &Path, cmd: &str) -> Result { } if let Some(description) = docs.description { - command = command.long_about(description); + command = command.after_help(description); } if let Some(line) = docs.usage {