Repository: clap-rs/clap (rust)

Issue:
Extra newline printed when a flat subcommand has no arguments
When `flatten_help` is enabled and a subcommand doesn't have any arguments, an extra newline is printed like below:

```
Usage: cmd
       cmd foo [OPTIONS] [TO_VER]
       cmd bar

cmd foo:
Run foo
  -f, --from <FROM>     The version to upgrade from
  [TO_VER]           The version to upgrade to

cmd bar:
Run bar


After help:
...
```

It should instead be:

```
Usage: cmd
       cmd foo [OPTIONS] [TO_VER]
       cmd bar

cmd foo:
Run foo
  -f, --from <FROM>     The version to upgrade from
  [TO_VER]           The version to upgrade to

cmd bar:
Run bar

After help:
...
```

Pull request description:
fix(help): Don't add \n when a flat subcommand has no args
Check to see if a subcommand has arguments and only print the preceding newline if it does.

Fixes #5960.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2409269c..21e923fe 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -22,12 +22,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 <!-- next-header -->
 ## [Unreleased] - ReleaseDate
 
-## [4.5.33] - 2025-03-26
-
-### Fixes
-
-- *(error)* When showing the usage of a suggestion for an unknown argument, don't show the group
-
 ## [4.5.32] - 2025-03-10
 
 ### Features
@@ -4743,8 +4737,7 @@ Minimum version of Rust is now v1.13.0 (Stable)
 * **arg**  allow lifetimes other than 'static in arguments ([9e8c1fb9](https://github.com/clap-rs/clap/commit/9e8c1fb9406f8448873ca58bab07fe905f1551e5))
 
 <!-- next-url -->
-[Unreleased]: https://github.com/clap-rs/clap/compare/v4.5.33...HEAD
-[4.5.33]: https://github.com/clap-rs/clap/compare/v4.5.32...v4.5.33
+[Unreleased]: https://github.com/clap-rs/clap/compare/v4.5.32...HEAD
 [4.5.32]: https://github.com/clap-rs/clap/compare/v4.5.31...v4.5.32
 [4.5.31]: https://github.com/clap-rs/clap/compare/v4.5.30...v4.5.31
 [4.5.30]: https://github.com/clap-rs/clap/compare/v4.5.29...v4.5.30
diff --git a/CITATION.cff b/CITATION.cff
index 71eda7b9..15f4bec4 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -3,8 +3,8 @@ cff-version: 1.2.0
 message: Please cite this crate using these information.
 
 # Version information.
-date-released: 2025-03-26
-version: 4.5.33
+date-released: 2025-03-10
+version: 4.5.32
 
 # Project information.
 abstract: A full featured, fast Command Line Argument Parser for Rust
diff --git a/Cargo.lock b/Cargo.lock
index 61a32712..f8a402c4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -432,11 +432,11 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.33"
+version = "4.5.32"
 dependencies = [
  "automod",
  "clap-cargo",
- "clap_builder 4.5.33",
+ "clap_builder 4.5.32",
  "clap_derive",
  "jiff",
  "rustversion",
@@ -459,7 +459,7 @@ dependencies = [
 name = "clap_bench"
 version = "0.0.0"
 dependencies = [
- "clap 4.5.33",
+ "clap 4.5.32",
  "divan",
  "lazy_static",
 ]
@@ -479,7 +479,7 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.33"
+version = "4.5.32"
 dependencies = [
  "anstream",
  "anstyle",
@@ -499,7 +499,7 @@ name = "clap_complete"
 version = "4.5.47"
 dependencies = [
  "automod",
- "clap 4.5.33",
+ "clap 4.5.32",
  "clap_lex 0.7.4",
  "completest",
  "completest-pty",
@@ -513,7 +513,7 @@ dependencies = [
 name = "clap_complete_nushell"
 version = "4.5.5"
 dependencies = [
- "clap 4.5.33",
+ "clap 4.5.32",
  "clap_complete",
  "completest",
  "completest-nu",
@@ -550,7 +550,7 @@ name = "clap_mangen"
 version = "0.2.26"
 dependencies = [
  "automod",
- "clap 4.5.33",
+ "clap 4.5.32",
  "roff",
  "snapbox",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index 4ea9f889..4aa5c785 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -99,7 +99,7 @@ blocks_in_conditions = "allow"
 
 [package]
 name = "clap"
-version = "4.5.33"
+version = "4.5.32"
 description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
 categories = ["command-line-interface"]
 keywords = [
@@ -176,7 +176,7 @@ unstable-markdown = ["clap_derive/unstable-markdown"]
 bench = false
 
 [dependencies]
-clap_builder = { path = "./clap_builder", version = "=4.5.33", default-features = false }
+clap_builder = { path = "./clap_builder", version = "=4.5.32", default-features = false }
 clap_derive = { path = "./clap_derive", version = "=4.5.32", optional = true }
 
 [dev-dependencies]
diff --git a/clap_builder/Cargo.toml b/clap_builder/Cargo.toml
index ca675d2e..74f1531f 100644
--- a/clap_builder/Cargo.toml
+++ b/clap_builder/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clap_builder"
-version = "4.5.33"
+version = "4.5.32"
 description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
 categories = ["command-line-interface"]
 keywords = [
diff --git a/clap_builder/src/output/help_template.rs b/clap_builder/src/output/help_template.rs
index b968ad97..18f38d15 100644
--- a/clap_builder/src/output/help_template.rs
+++ b/clap_builder/src/output/help_template.rs
@@ -880,9 +880,17 @@ impl HelpTemplate<'_, '_> {
                 .or_else(|| subcommand.get_long_about())
                 .unwrap_or_default();
 
-            let _ = write!(self.writer, "{header}{heading}:{header:#}\n",);
+            let _ = write!(self.writer, "{header}{heading}:{header:#}",);
             if !about.is_empty() {
-                let _ = write!(self.writer, "{about}\n",);
+                let _ = write!(self.writer, "\n{about}",);
+            }
+
+            let args = subcommand
+                .get_arguments()
+                .filter(|arg| should_show_arg(self.use_long, arg) && !arg.is_global_set())
+                .collect::<Vec<_>>();
+            if !args.is_empty() {
+                self.writer.push_str("\n");
             }
 
             let mut sub_help = HelpTemplate {
@@ -894,10 +902,6 @@ impl HelpTemplate<'_, '_> {
                 term_w: self.term_w,
                 use_long: self.use_long,
             };
-            let args = subcommand
-                .get_arguments()
-                .filter(|arg| should_show_arg(self.use_long, arg) && !arg.is_global_set())
-                .collect::<Vec<_>>();
             sub_help.write_args(&args, heading, option_sort_key);
             if subcommand.is_flatten_help_set() {
                 sub_help.write_flat_subcommands(subcommand, first);
diff --git a/clap_builder/src/parser/parser.rs b/clap_builder/src/parser/parser.rs
index 1ae2355e..d787f89a 100644
--- a/clap_builder/src/parser/parser.rs
+++ b/clap_builder/src/parser/parser.rs
@@ -1586,7 +1586,7 @@ impl Parser<'_> {
             .filter(|arg_id| {
                 matcher.check_explicit(arg_id, &crate::builder::ArgPredicate::IsPresent)
             })
-            .filter(|n| self.cmd.find(n).map(|a| !a.is_hide_set()).unwrap_or(false))
+            .filter(|n| self.cmd.find(n).map(|a| !a.is_hide_set()).unwrap_or(true))
             .cloned()
             .collect();
 
diff --git a/src/lib.rs b/src/lib.rs
index aaabcd24..46f29002 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,7 +11,7 @@
 //! - [Cookbook][_cookbook]
 //! - [FAQ][_faq]
 //! - [Discussions](https://github.com/clap-rs/clap/discussions)
-//! - [CHANGELOG](https://github.com/clap-rs/clap/blob/v4.5.33/CHANGELOG.md) (includes major version migration
+//! - [CHANGELOG](https://github.com/clap-rs/clap/blob/v4.5.32/CHANGELOG.md) (includes major version migration
 //!   guides)
 //!
 //! ## Aspirations


Test patch:
diff --git a/tests/builder/help.rs b/tests/builder/help.rs
index fb203b0e..8341b7e4 100644
--- a/tests/builder/help.rs
+++ b/tests/builder/help.rs
@@ -3869,7 +3869,6 @@ greatgrandchild3 command
 parent child1 grandchild1 help:
 Print this message or the help of the given subcommand(s)
 
-
 parent child1 grandchild2:
 grandchild2 command
       --grandchild2 <grandchild>  
@@ -3883,7 +3882,6 @@ grandchild3 command
 parent child1 help:
 Print this message or the help of the given subcommand(s)
 
-
 parent child2:
 child2 command
       --child2 <child>  
diff --git a/tests/derive/doc_comments_help.rs b/tests/derive/doc_comments_help.rs
index 66320287..99324ec9 100644
--- a/tests/derive/doc_comments_help.rs
+++ b/tests/derive/doc_comments_help.rs
@@ -15,7 +15,6 @@
 use crate::utils;
 
 use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
-use snapbox::str;
 
 #[test]
 fn doc_comments() {
@@ -277,7 +276,7 @@ fn respect_subcommand_doc_comment() {
         Twp,
     }
 
-    let output = str![[r#"
+    const OUTPUT: &str = "\
 Usage: cmd <COMMAND>
 
 Commands:
@@ -286,9 +285,8 @@ Commands:
 
 Options:
   -h, --help  Print help
-
-"#]];
-    utils::assert_output::<Cmd>("cmd --help", output, false);
+";
+    utils::assert_output::<Cmd>("cmd --help", OUTPUT, false);
 }
 
 #[test]
diff --git a/tests/derive/groups.rs b/tests/derive/groups.rs
index a8f9f94b..37141968 100644
--- a/tests/derive/groups.rs
+++ b/tests/derive/groups.rs
@@ -1,5 +1,4 @@
 use clap::Parser;
-use snapbox::str;
 
 use crate::utils::assert_output;
 
@@ -45,16 +44,15 @@ fn implicit_struct_group() {
         git: Option<String>,
     }
 
-    let output = str![[r#"
+    const OUTPUT: &str = "\
 error: the following required arguments were not provided:
   <CRATES|--path <PATH>|--git <GIT>>
 
 Usage: prog --add <CRATES|--path <PATH>|--git <GIT>>
 
 For more information, try '--help'.
-
-"#]];
-    assert_output::<Opt>("prog --add", output, true);
+";
+    assert_output::<Opt>("prog --add", OUTPUT, true);
 
     use clap::Args;
     assert_eq!(Source::group_id(), Some(clap::Id::from("Source")));
@@ -231,76 +229,13 @@ fn required_group() {
         Opt::try_parse_from(["test", "--path=./"]).unwrap()
     );
 
-    let output = str![[r#"
+    const OUTPUT: &str = "\
 error: the following required arguments were not provided:
   <--path <PATH>|--git <GIT>>
 
 Usage: test <--path <PATH>|--git <GIT>>
 
 For more information, try '--help'.
-
-"#]];
-    assert_output::<Opt>("test", output, true);
-}
-
-#[test]
-#[cfg(feature = "error-context")]
-#[cfg(feature = "suggestions")]
-fn suggestion() {
-    #[derive(Parser, Debug)]
-    struct Args {
-        name: String,
-
-        #[arg(long)]
-        hello: Option<u8>,
-
-        #[arg(long)]
-        count01: Vec<u8>,
-        #[arg(long)]
-        count02: Vec<u8>,
-        #[arg(long)]
-        count03: Vec<u8>,
-        #[arg(long)]
-        count04: Vec<u8>,
-        #[arg(long)]
-        count05: Vec<u8>,
-        #[arg(long)]
-        count06: Vec<u8>,
-        #[arg(long)]
-        count07: Vec<u8>,
-        #[arg(long)]
-        count08: Vec<u8>,
-        #[arg(long)]
-        count09: Vec<u8>,
-        #[arg(long)]
-        count10: Vec<u8>,
-        #[arg(long)]
-        count11: Vec<u8>,
-        #[arg(long)]
-        count12: Vec<u8>,
-        #[arg(long)]
-        count13: Vec<u8>,
-        #[arg(long)]
-        count14: Vec<u8>,
-        #[arg(long)]
-        count15: Vec<u8>,
-        #[arg(long)]
-        count16: Vec<u8>,
-        #[arg(long)]
-        count17: Vec<u8>,
-        #[arg(long)]
-        count18: Vec<u8>,
-    }
-
-    let output = str![[r#"
-error: unexpected argument '--hell' found
-
-  tip: a similar argument exists: '--hello'
-
-Usage: test --hello <HELLO> <NAME>
-
-For more information, try '--help'.
-
-"#]];
-    assert_output::<Args>("test --hell", output, true);
+";
+    assert_output::<Opt>("test", OUTPUT, true);
 }
diff --git a/tests/derive/help.rs b/tests/derive/help.rs
index 558e45cd..cacf406a 100644
--- a/tests/derive/help.rs
+++ b/tests/derive/help.rs
@@ -220,16 +220,14 @@ fn derive_generated_error_has_full_context() {
         result.unwrap()
     );
 
-    let expected = str![[r#"
-error: The following required argument was not provided: req_str
+    let expected = r#"error: The following required argument was not provided: req_str
 
 Usage: clap --req-str <REQ_STR>
        clap <COMMAND>
 
 For more information, try '--help'.
-
-"#]];
-    assert_data_eq!(result.unwrap_err().to_string(), expected);
+"#;
+    assert_eq!(result.unwrap_err().to_string(), expected);
 }
 
 #[test]
@@ -342,6 +340,18 @@ Options:
 
 #[test]
 fn derive_order_no_next_order() {
+    static HELP: &str = "\
+Usage: test [OPTIONS]
+
+Options:
+      --flag-a               first flag
+      --flag-b               second flag
+  -h, --help                 Print help
+      --option-a <OPTION_A>  first option
+      --option-b <OPTION_B>  second option
+  -V, --version              Print version
+";
+
     #[derive(Parser, Debug)]
     #[command(name = "test", version = "1.2")]
     #[command(next_display_order = None)]
@@ -376,18 +386,7 @@ fn derive_order_no_next_order() {
     let mut cmd = Args::command();
 
     let help = cmd.render_help().to_string();
-    assert_data_eq!(help, str![[r#"
-Usage: test [OPTIONS]
-
-Options:
-      --flag-a               first flag
-      --flag-b               second flag
-  -h, --help                 Print help
-      --option-a <OPTION_A>  first option
-      --option-b <OPTION_B>  second option
-  -V, --version              Print version
-
-"#]]);
+    assert_data_eq!(HELP, help);
 }
 
 #[test]
diff --git a/tests/derive/utils.rs b/tests/derive/utils.rs
index c120a96a..61063e23 100644
--- a/tests/derive/utils.rs
+++ b/tests/derive/utils.rs
@@ -65,5 +65,5 @@ pub(crate) fn assert_output<P: clap::Parser + std::fmt::Debug>(
         stderr,
         err.use_stderr()
     );
-    assert_data_eq!(actual, expected.raw());
+    assert_data_eq!(actual, expected);
 }