From c37ab6c205b4723584c8a6569b82b45105c99f0b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 7 Nov 2022 09:41:43 -0600 Subject: [PATCH] fix(derive): Allow 'long_help' to force populating from doc comment Fixes #4441 --- clap_derive/src/attr.rs | 4 ++++ clap_derive/src/item.rs | 19 ++++++++++++++++++- clap_derive/src/utils/doc_comments.rs | 20 ++++++++++++++------ src/_derive/mod.rs | 6 ++++-- tests/derive/doc_comments_help.rs | 4 ++-- 5 files changed, 42 insertions(+), 11 deletions(-) diff --git a/clap_derive/src/attr.rs b/clap_derive/src/attr.rs index f97ba7d0a7f..5ea49a1dd6b 100644 --- a/clap_derive/src/attr.rs +++ b/clap_derive/src/attr.rs @@ -105,6 +105,8 @@ impl Parse for ClapAttr { "external_subcommand" => Some(MagicAttrName::ExternalSubcommand), "verbatim_doc_comment" => Some(MagicAttrName::VerbatimDocComment), "about" => Some(MagicAttrName::About), + "long_about" => Some(MagicAttrName::LongAbout), + "long_help" => Some(MagicAttrName::LongHelp), "author" => Some(MagicAttrName::Author), "version" => Some(MagicAttrName::Version), _ => None, @@ -160,6 +162,8 @@ pub enum MagicAttrName { VerbatimDocComment, ExternalSubcommand, About, + LongAbout, + LongHelp, Author, Version, RenameAllEnv, diff --git a/clap_derive/src/item.rs b/clap_derive/src/item.rs index 71154c243e9..a068e36011a 100644 --- a/clap_derive/src/item.rs +++ b/clap_derive/src/item.rs @@ -43,6 +43,7 @@ pub struct Item { value_parser: Option, action: Option, verbatim_doc_comment: bool, + force_long_help: bool, next_display_order: Option, next_help_heading: Option, is_enum: bool, @@ -266,6 +267,7 @@ impl Item { value_parser: None, action: None, verbatim_doc_comment: false, + force_long_help: false, next_display_order: None, next_help_heading: None, is_enum: false, @@ -504,6 +506,18 @@ impl Item { } } + Some(MagicAttrName::LongAbout) if attr.value.is_none() => { + assert_attr_kind(attr, &[AttrKind::Command]); + + self.force_long_help = true; + } + + Some(MagicAttrName::LongHelp) if attr.value.is_none() => { + assert_attr_kind(attr, &[AttrKind::Arg]); + + self.force_long_help = true; + } + Some(MagicAttrName::Author) if attr.value.is_none() => { assert_attr_kind(attr, &[AttrKind::Command]); @@ -820,6 +834,8 @@ impl Item { | Some(MagicAttrName::Long) | Some(MagicAttrName::Env) | Some(MagicAttrName::About) + | Some(MagicAttrName::LongAbout) + | Some(MagicAttrName::LongHelp) | Some(MagicAttrName::Author) | Some(MagicAttrName::Version) => { @@ -873,7 +889,8 @@ impl Item { let lines = extract_doc_comment(attrs); if !lines.is_empty() { - let (short_help, long_help) = format_doc_comment(&lines, !self.verbatim_doc_comment); + let (short_help, long_help) = + format_doc_comment(&lines, !self.verbatim_doc_comment, self.force_long_help); let short_name = format_ident!("{}", short_name); let short = Method::new( short_name, diff --git a/clap_derive/src/utils/doc_comments.rs b/clap_derive/src/utils/doc_comments.rs index 1f88e4dfbd3..5183b6b25e1 100644 --- a/clap_derive/src/utils/doc_comments.rs +++ b/clap_derive/src/utils/doc_comments.rs @@ -47,7 +47,11 @@ pub fn extract_doc_comment(attrs: &[syn::Attribute]) -> Vec { lines } -pub fn format_doc_comment(lines: &[String], preprocess: bool) -> (Option, Option) { +pub fn format_doc_comment( + lines: &[String], + preprocess: bool, + force_long: bool, +) -> (Option, Option) { if let Some(first_blank) = lines.iter().position(|s| is_blank(s)) { let (short, long) = if preprocess { let paragraphs = split_paragraphs(lines); @@ -62,14 +66,18 @@ pub fn format_doc_comment(lines: &[String], preprocess: bool) -> (Option (Some(short), Some(long)) } else { - let short = if preprocess { - let s = merge_lines(lines); - remove_period(s) + let (short, long) = if preprocess { + let short = merge_lines(lines); + let long = force_long.then(|| short.clone()); + let short = remove_period(short); + (short, long) } else { - lines.join("\n") + let short = lines.join("\n"); + let long = force_long.then(|| short.clone()); + (short, long) }; - (Some(short), None) + (Some(short), long) } } diff --git a/src/_derive/mod.rs b/src/_derive/mod.rs index f2955e50be2..f5da23632ba 100644 --- a/src/_derive/mod.rs +++ b/src/_derive/mod.rs @@ -154,8 +154,9 @@ //! - **TIP:** When a doc comment is also present, you most likely want to add //! `#[arg(long_about = None)]` to clear the doc comment so only [`about`][crate::Command::about] //! gets shown with both `-h` and `--help`. -//! - `long_about = `: [`Command::long_about`][crate::Command::long_about] +//! - `long_about[ = ]`: [`Command::long_about`][crate::Command::long_about] //! - When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing +//! - When present without a value: [Doc comment](#doc-comments) //! - `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to [`about`][crate::Command::about] / [`long_about`][crate::Command::long_about] //! - `next_display_order`: [`Command::next_display_order`][crate::Command::next_display_order] //! - `next_help_heading`: [`Command::next_help_heading`][crate::Command::next_help_heading] @@ -200,8 +201,9 @@ //! - When not present: will auto-select an action based on the field type //! - `help = `: [`Arg::help`][crate::Arg::help] //! - When not present: [Doc comment summary](#doc-comments) -//! - `long_help = `: [`Arg::long_help`][crate::Arg::long_help] +//! - `long_help[ = ]`: [`Arg::long_help`][crate::Arg::long_help] //! - When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing +//! - When present without a value: [Doc comment](#doc-comments) //! - `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to [`help`][crate::Arg::help] / [`long_help`][crate::Arg::long_help] //! - `short [= ]`: [`Arg::short`][crate::Arg::short] //! - When not present: no short set diff --git a/tests/derive/doc_comments_help.rs b/tests/derive/doc_comments_help.rs index c7eff65a9dd..f8b3743a940 100644 --- a/tests/derive/doc_comments_help.rs +++ b/tests/derive/doc_comments_help.rs @@ -296,10 +296,10 @@ fn force_long_help() { struct LoremIpsum { /// Fooify a bar /// and a baz. - #[arg(short, long)] + #[arg(short, long, long_help)] foo: bool, } let help = utils::get_long_help::(); - assert!(help.contains("Fooify a bar and a baz")); + assert!(help.contains("Fooify a bar and a baz.")); }