Repository: clap-rs/clap (rust)

Issue:
--help message randomly show and hide docs lines
### Please complete the following tasks

- [X] I have searched the [discussions](https://github.com/clap-rs/clap/discussions)
- [X] I have searched the existing issues

### Rust Version

rustc 1.58.0-nightly (e249ce6b2 2021-10-30)

### Clap Version

3.0.0-beta.5

### Minimal reproducible code

```rust
use clap::Parser;

#[derive(Parser, Debug)]
#[clap(version, about)]
pub struct Opts {
    #[clap(subcommand)]
    pub cmd: Subcommand,
}

// Ouch commands:
// - `compress`
// - `decompress`
// - `list`
//
// Clap commands:
//  - `help`
/// Repository: https://github.com/ouch-org/ouch
#[derive(Parser, PartialEq, Eq, Debug)]
pub enum Subcommand {
    Compress { output: String },
}

fn main() {
    let _ = Opts::parse();
}
```

### Steps to reproduce the bug with the above code

`cargo run -q -- --help`

### Actual Behaviour

This is a tricky one, if you copy my code example, here is the --help message:

```
teste 0.1.0



USAGE:
    teste <SUBCOMMAND>

OPTIONS:
    -h, --help       Print help information
    -V, --version    Print version information

SUBCOMMANDS:
    compress    
    help        Print this message or the help of the given subcommand(s)
```

So, that `Repository` line does not appear in the help message :-1:, but if we change all the `//` comments to be `///` (to three slashes):

```
teste 0.1.0

Ouch commands: - `compress` - `decompress` - `list`

Clap commands: - `help` Repository: https://github.com/ouch-org/ouch

USAGE:
    teste <SUBCOMMAND>

OPTIONS:
    -h, --help
            Print help information

    -V, --version
            Print version information

SUBCOMMANDS:
    compress
            
    help
            Print this message or the help of the given subcommand(s)
```

Now it appears!! :+1:.

Now try deleting the empty comment `"///\n"`. Does not appear anymore :-1:.
Now you delete the `#[clap(version, about)]` line. Appears again :+1:.

So, we went :-1: -> :+1: -> :-1: -> :+1: just by making small random changes.

### Expected Behaviour

I assume it should be consistent and always show that repository line.

### Additional Context

_No response_

### Debug Output

With the starter code:

```
[            clap::build::app] 	App::_do_parse
[            clap::build::app] 	App::_build
[            clap::build::app] 	App::_propagate:teste
[            clap::build::app] 	App::_check_help_and_version
[            clap::build::app] 	App::_check_help_and_version: Building help subcommand
[            clap::build::app] 	App::_propagate_global_args:teste
[            clap::build::app] 	App::_derive_display_order:teste
[            clap::build::app] 	App::_derive_display_order:compress
[            clap::build::app] 	App::_derive_display_order:help
[clap::build::app::debug_asserts] 	App::_debug_asserts
[clap::build::arg::debug_asserts] 	Arg::_debug_asserts:help
[clap::build::arg::debug_asserts] 	Arg::_debug_asserts:version
[         clap::parse::parser] 	Parser::get_matches_with
[         clap::parse::parser] 	Parser::_build
[         clap::parse::parser] 	Parser::_verify_positionals
[         clap::parse::parser] 	Parser::get_matches_with: Begin parsing 'RawOsStr("--help")' ([45, 45, 104, 101, 108, 112])
[         clap::parse::parser] 	Parser::get_matches_with: Positional counter...1
[         clap::parse::parser] 	Parser::get_matches_with: Low index multiples...false
[         clap::parse::parser] 	Parser::possible_subcommand: arg=RawOsStr("--help")
[         clap::parse::parser] 	Parser::get_matches_with: sc=None
[         clap::parse::parser] 	Parser::parse_long_arg
[         clap::parse::parser] 	Parser::parse_long_arg: cur_idx:=1
[         clap::parse::parser] 	Parser::parse_long_arg: Does it contain '='...
[         clap::parse::parser] 	No
[         clap::parse::parser] 	Parser::parse_long_arg: Found valid opt or flag '--help'
[         clap::parse::parser] 	Parser::check_for_help_and_version_str
[         clap::parse::parser] 	Parser::check_for_help_and_version_str: Checking if --RawOsStr("help") is help or version...
[         clap::parse::parser] 	Help
[         clap::parse::parser] 	Parser::get_matches_with: After parse_long_arg HelpFlag
[         clap::parse::parser] 	[         clap::parse::parser] 	Parser::use_long_help
Parser::help_err: use_long=false
[         clap::parse::parser] 	Parser::use_long_help
[          clap::output::help] 	Help::new
[          clap::output::help] 	Help::write_help
[          clap::output::help] 	should_show_arg: use_long=false, arg=help
[          clap::output::help] 	Help::write_templated_help
[          clap::output::help] 	Help::write_before_help
[          clap::output::help] 	Help::write_bin_name
[         clap::output::usage] 	Usage::create_usage_no_title
[         clap::output::usage] 	Usage::create_help_usage; incl_reqs=true
[         clap::output::usage] 	Usage::get_required_usage_from: incls=[], matcher=false, incl_last=false
[         clap::output::usage] 	Usage::get_required_usage_from: unrolled_reqs={}
[         clap::output::usage] 	Usage::get_required_usage_from: ret_val=[]
[         clap::output::usage] 	Usage::needs_options_tag
[         clap::output::usage] 	Usage::needs_options_tag:iter: f=help
[         clap::output::usage] 	Usage::needs_options_tag:iter Option is built-in
[         clap::output::usage] 	Usage::needs_options_tag:iter: f=version
[         clap::output::usage] 	Usage::needs_options_tag:iter Option is built-in
[         clap::output::usage] 	Usage::needs_options_tag: [OPTIONS] not required
[         clap::output::usage] 	Usage::create_help_usage: usage=teste <SUBCOMMAND>
[          clap::output::help] 	Help::write_all_args
[          clap::output::help] 	should_show_arg: use_long=false, arg=help
[          clap::output::help] 	should_show_arg: use_long=false, arg=version
[          clap::output::help] 	Help::write_args
[          clap::output::help] 	should_show_arg: use_long=false, arg=help
[          clap::output::help] 	Help::write_args: Current Longest...2
[          clap::output::help] 	Help::write_args: New Longest...6
[          clap::output::help] 	should_show_arg: use_long=false, arg=version
[          clap::output::help] 	Help::write_args: Current Longest...6
[          clap::output::help] 	Help::write_args: New Longest...9
[          clap::output::help] 	should_show_arg: use_long=false, arg=help
[          clap::output::help] 	Help::spec_vals: a=--help
[          clap::output::help] 	should_show_arg: use_long=false, arg=version
[          clap::output::help] 	Help::spec_vals: a=--version
[          clap::output::help] 	Help::spec_vals: a=--help
[          clap::output::help] 	Help::short
[          clap::output::help] 	Help::long
[          clap::output::help] 	Help::val: arg=help
[          clap::output::help] 	Help::val: Has switch...
[          clap::output::help] 	Yes
[          clap::output::help] 	Help::val: nlh...false
[          clap::output::help] 	Help::help
[          clap::output::help] 	Help::help: Next Line...false
[          clap::output::help] 	Help::help: Too long...
[          clap::output::help] 	No
[          clap::output::help] 	Help::spec_vals: a=--version
[          clap::output::help] 	Help::short
[          clap::output::help] 	Help::long
[          clap::output::help] 	Help::val: arg=version
[          clap::output::help] 	Help::val: Has switch...
[          clap::output::help] 	Yes
[          clap::output::help] 	Help::val: nlh...false
[          clap::output::help] 	Help::help
[          clap::output::help] 	Help::help: Next Line...false
[          clap::output::help] 	Help::help: Too long...
[          clap::output::help] 	No
[          clap::output::help] 	Help::write_subcommands
[          clap::output::help] 	Help::write_subcommands longest = 8
[          clap::output::help] 	Help::sc_spec_vals: a=compress
[          clap::output::help] 	Help::sc_spec_vals: a=help
[          clap::output::help] 	Help::write_subcommand
[          clap::output::help] 	Help::sc_spec_vals: a=compress
[          clap::output::help] 	Help::help
[          clap::output::help] 	Help::help: Next Line...false
[          clap::output::help] 	Help::help: Too long...
[          clap::output::help] 	No
[          clap::output::help] 	Help::write_subcommand
[          clap::output::help] 	Help::sc_spec_vals: a=help
[          clap::output::help] 	Help::help
[          clap::output::help] 	Help::help: Next Line...false
[          clap::output::help] 	Help::help: Too long...
[          clap::output::help] 	No
[          clap::output::help] 	Help::write_after_help
[           clap::output::fmt] 	is_a_tty: stderr=false
```

Pull request:
fix(derive)!: Set both about/long_about with doc comments 
The main care about is that when we override a `flatten` / `subcommand` doc comment in a parent
container, that we make sure we take nothing from the child container,
rather than implicitly taking one `about` ut not `long_about`.

To do this, and to play the most safe with long help detection, we reset
`long_about` to default when there is no doc comment body to use for
`long_about`.

Fixes #2983

BREAKING CHANGE: We changed the signatures for `App::about`,
`App::long_about`, `Arg::help`, and `Arg::long_help` from accepting anything `Into<&str>` to `&str`.

Patch:
diff --git a/clap_derive/src/utils/doc_comments.rs b/clap_derive/src/utils/doc_comments.rs
index f0cb9621..7ac872cf 100644
--- a/clap_derive/src/utils/doc_comments.rs
+++ b/clap_derive/src/utils/doc_comments.rs
@@ -61,7 +61,10 @@ pub fn process_doc_comment(lines: Vec<String>, name: &str, preprocess: bool) ->
             lines.join("\n")
         };
 
-        vec![Method::new(short_name, quote!(#short))]
+        vec![
+            Method::new(short_name, quote!(#short)),
+            Method::new(long_name, quote!(None)),
+        ]
     }
 }
 
diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs
index 32dc75a3..22136f7a 100644
--- a/src/build/app/mod.rs
+++ b/src/build/app/mod.rs
@@ -896,8 +896,8 @@ impl<'help> App<'help> {
     ///     .about("Does really amazing things for great people")
     /// # ;
     /// ```
-    pub fn about<S: Into<&'help str>>(mut self, about: S) -> Self {
-        self.about = Some(about.into());
+    pub fn about<O: Into<Option<&'help str>>>(mut self, about: O) -> Self {
+        self.about = about.into();
         self
     }
 
@@ -920,8 +920,8 @@ impl<'help> App<'help> {
     /// # ;
     /// ```
     /// [`App::about`]: App::about()
-    pub fn long_about<S: Into<&'help str>>(mut self, about: S) -> Self {
-        self.long_about = Some(about.into());
+    pub fn long_about<O: Into<Option<&'help str>>>(mut self, long_about: O) -> Self {
+        self.long_about = long_about.into();
         self
     }
 
diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs
index 539ec685..ff9d05ed 100644
--- a/src/build/arg/mod.rs
+++ b/src/build/arg/mod.rs
@@ -2712,8 +2712,8 @@ impl<'help> Arg<'help> {
     /// ```
     /// [`Arg::long_help`]: Arg::long_help()
     #[inline]
-    pub fn help(mut self, h: &'help str) -> Self {
-        self.help = Some(h);
+    pub fn help(mut self, h: impl Into<Option<&'help str>>) -> Self {
+        self.help = h.into();
         self
     }
 
@@ -2773,8 +2773,8 @@ impl<'help> Arg<'help> {
     /// ```
     /// [`Arg::help`]: Arg::help()
     #[inline]
-    pub fn long_help(mut self, h: &'help str) -> Self {
-        self.long_help = Some(h);
+    pub fn long_help(mut self, h: impl Into<Option<&'help str>>) -> Self {
+        self.long_help = h.into();
         self
     }
 


Test patch:
diff --git a/tests/derive/doc_comments_help.rs b/tests/derive/doc_comments_help.rs
index 000b98e5..4b2d22c0 100644
--- a/tests/derive/doc_comments_help.rs
+++ b/tests/derive/doc_comments_help.rs
@@ -14,7 +14,7 @@
 
 use crate::utils;
 
-use clap::{ArgEnum, Parser};
+use clap::{ArgEnum, IntoApp, Parser};
 
 #[test]
 fn doc_comments() {
@@ -214,3 +214,27 @@ fn argenum_multiline_doc_comment() {
         Bar,
     }
 }
+
+#[test]
+fn doc_comment_about_handles_both_abouts() {
+    /// Opts doc comment summary
+    #[derive(Parser, Debug)]
+    pub struct Opts {
+        #[clap(subcommand)]
+        pub cmd: Sub,
+    }
+
+    /// Sub doc comment summary
+    ///
+    /// Sub doc comment body
+    #[derive(Parser, PartialEq, Eq, Debug)]
+    pub enum Sub {
+        Compress { output: String },
+    }
+
+    let app = Opts::into_app();
+    assert_eq!(app.get_about(), Some("Opts doc comment summary"));
+    // clap will fallback to `about` on `None`.  The main care about is not providing a `Sub` doc
+    // comment.
+    assert_eq!(app.get_long_about(), None);
+}