Repository: clap-rs/clap (rust)

Issue:
Excessively long "Usage:" line when specifying invalid option.
### Please complete the following tasks

- [x] I have searched the [discussions](https://github.com/clap-rs/clap/discussions)
- [x] I have searched the [open](https://github.com/clap-rs/clap/issues) and [rejected](https://github.com/clap-rs/clap/issues?q=is%3Aissue+label%3AS-wont-fix+is%3Aclosed) issues

### Rust Version

rustc 1.85.0-nightly (4363f9b6f 2025-01-02)

### Clap Version

4.5.32

### Minimal reproducible code

```rust
use clap::Parser;
#[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>,
}

fn main() {
    let _args = Args::parse();
}
```


### Steps to reproduce the bug with the above code

```cargo run -- --hell```

### Actual Behaviour

```
error: unexpected argument '--hell' found

  tip: a similar argument exists: '--hello'

Usage: qqq <NAME|--hello <HELLO>|--count01 <COUNT01>|--count02 <COUNT02>|--count03 <COUNT03>|--count04 <COUNT04>|--count05 <COUNT05>|--count06 <COUNT06>|--count07 <COUNT07>|--count08 <COUNT08>|--count09 <COUNT09>|--count10 <COUNT10>|--count11 <COUNT11>|--count12 <COUNT12>|--count13 <COUNT13>|--count14 <COUNT14>|--count15 <COUNT15>|--count16 <COUNT16>|--count17 <COUNT17>|--count18 <COUNT18>>

For more information, try '--help'.
```

### Expected Behaviour

Either "Usage:" like just omitted, or minimized (like as if I specify `cargo run -- --qqqqqqq`, i.e. option not similar to anything).

```
error: unexpected argument '--hell' found

  tip: a similar argument exists: '--hello'

For more information, try '--help'.
```

---

```
error: unexpected argument '--hell' found

  tip: a similar argument exists: '--hello'

Usage: qqq <NAME> [--hello <HELLO>]

For more information, try '--help'.
```

### Additional Context

If I disable `suggestions` Cargo feature, it stops mention name of invalid option (`--hell` in this example) completely, not just omit suggestions.

```
error: unexpected argument found
```

Without `suggestions` it is overly short, with `suggestions` it is overly long.

### Debug Output

<details> <summary> Debug output </summary>

```
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.07s
     Running `target/debug/qqq --hell`
[clap_builder::builder::command]Command::_do_parse
[clap_builder::builder::command]Command::_build: name="qqq"
[clap_builder::builder::command]Command::_propagate:qqq
[clap_builder::builder::command]Command::_check_help_and_version:qqq expand_help_tree=false
[clap_builder::builder::command]Command::long_help_exists
[clap_builder::builder::command]Command::_check_help_and_version: Building default --help
[clap_builder::builder::command]Command::_propagate_global_args:qqq
[clap_builder::builder::debug_asserts]Command::_debug_asserts
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:name
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:hello
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count01
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count02
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count03
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count04
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count05
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count06
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count07
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count08
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count09
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count10
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count11
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count12
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count13
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count14
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count15
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count16
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count17
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:count18
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:help
[clap_builder::builder::debug_asserts]Command::_verify_positionals
[clap_builder::parser::parser]Parser::get_matches_with
[clap_builder::parser::parser]Parser::parse
[clap_builder::parser::parser]Parser::get_matches_with: Begin parsing '"--hell"'
[clap_builder::parser::parser]Parser::possible_subcommand: arg=Ok("--hell")
[clap_builder::parser::parser]Parser::get_matches_with: sc=None
[clap_builder::parser::parser]Parser::parse_long_arg
[clap_builder::parser::parser]Parser::parse_long_arg: Does it contain '='...
[clap_builder::parser::parser]Parser::possible_long_flag_subcommand: arg="hell"
[clap_builder::parser::parser]Parser::get_matches_with: After parse_long_arg NoMatchingArg { arg: "hell" }
[clap_builder::parser::parser]Parser::did_you_mean_error: arg=hell
[clap_builder::parser::parser]Parser::did_you_mean_error: longs=["hello", "count01", "count02", "count03", "count04", "count05", "count06", "count07", "count08", "count09", "count10", "count11", "count12", "count13", "count14", "count15", "count16", "count17", "count18", "help"]
[clap_builder::parser::parser]Parser::remove_overrides: id="hello"
[clap_builder::parser::arg_matcher]ArgMatcher::start_custom_arg: id="hello", source=CommandLine
[clap_builder::builder::command]Command::groups_for_arg: id="hello"
[clap_builder::parser::arg_matcher]ArgMatcher::start_custom_arg: id="Args", source=CommandLine
[ clap_builder::output::usage]Usage::create_usage_with_title
[ clap_builder::output::usage]Usage::create_usage_no_title
[ clap_builder::output::usage]Usage::create_smart_usage
[ clap_builder::output::usage]Usage::write_arg_usage; incl_reqs=true
[ clap_builder::output::usage]Usage::write_args: incls=["hello", "Args"]
[ clap_builder::output::usage]Usage::get_args: unrolled_reqs=["name"]
[clap_builder::builder::command]Command::unroll_args_in_group: group="Args"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="name"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="hello"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count01"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count02"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count03"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count04"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count05"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count06"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count07"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count08"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count09"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count10"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count11"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count12"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count13"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count14"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count15"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count16"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count17"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count18"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group: group="Args"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="name"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="hello"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count01"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count02"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count03"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count04"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count05"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count06"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count07"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count08"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count09"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count10"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count11"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count12"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count13"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count14"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count15"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count16"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count17"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[clap_builder::builder::command]Command::unroll_args_in_group:iter: entity="count18"
[clap_builder::builder::command]Command::unroll_args_in_group:iter: this is an arg
[  clap_builder::builder::arg]Arg::name_no_brackets:name
[  clap_builder::builder::arg]Arg::name_no_brackets: val_names=[
    "NAME",
]
[ clap_builder::output::usage]Usage::create_usage_with_title: usage=Usage: qqq <NAME|--hello <HELLO>|--count01 <COUNT01>|--count02 <COUNT02>|--count03 <COUNT03>|--count04 <COUNT04>|--count05 <COUNT05>|--count06 <COUNT06>|--count07 <COUNT07>|--count08 <COUNT08>|--count09 <COUNT09>|--count10 <COUNT10>|--count11 <COUNT11>|--count12 <COUNT12>|--count13 <COUNT13>|--count14 <COUNT14>|--count15 <COUNT15>|--count16 <COUNT16>|--count17 <COUNT17>|--count18 <COUNT18>>
[clap_builder::builder::command]Command::color: Color setting...
[clap_builder::builder::command]Auto
[clap_builder::builder::command]Command::color: Color setting...
[clap_builder::builder::command]Auto
error: unexpected argument '--hell' found

  tip: a similar argument exists: '--hello'

Usage: qqq <NAME|--hello <HELLO>|--count01 <COUNT01>|--count02 <COUNT02>|--count03 <COUNT03>|--count04 <COUNT04>|--count05 <COUNT05>|--count06 <COUNT06>|--count07 <COUNT07>|--count08 <COUNT08>|--count09 <COUNT09>|--count10 <COUNT10>|--count11 <COUNT11>|--count12 <COUNT12>|--count13 <COUNT13>|--count14 <COUNT14>|--count15 <COUNT15>|--count16 <COUNT16>|--count17 <COUNT17>|--count18 <COUNT18>>

For more information, try '--help'.
```

</details>

Pull request:
fix(parser): Don't include groups in argument suggestions 
If we are assuming the arguments are present, then there is no reason to
show alternatives from the group.

There may be other ways large groups show up.
For now, I'm taking the whack-a-mole approach of handling them on a
case-by-case basis.
When we get to one where the group is relevant to show,
we should handle a general case then.

Fixes #5958

Patch:
diff --git a/clap_builder/src/parser/parser.rs b/clap_builder/src/parser/parser.rs
index d787f89a..1ae2355e 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(true))
+            .filter(|n| self.cmd.find(n).map(|a| !a.is_hide_set()).unwrap_or(false))
             .cloned()
             .collect();
 


Test patch:
diff --git a/tests/derive/doc_comments_help.rs b/tests/derive/doc_comments_help.rs
index 99324ec9..66320287 100644
--- a/tests/derive/doc_comments_help.rs
+++ b/tests/derive/doc_comments_help.rs
@@ -15,6 +15,7 @@
 use crate::utils;
 
 use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
+use snapbox::str;
 
 #[test]
 fn doc_comments() {
@@ -276,7 +277,7 @@ fn respect_subcommand_doc_comment() {
         Twp,
     }
 
-    const OUTPUT: &str = "\
+    let output = str![[r#"
 Usage: cmd <COMMAND>
 
 Commands:
@@ -285,8 +286,9 @@ 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 37141968..a8f9f94b 100644
--- a/tests/derive/groups.rs
+++ b/tests/derive/groups.rs
@@ -1,4 +1,5 @@
 use clap::Parser;
+use snapbox::str;
 
 use crate::utils::assert_output;
 
@@ -44,15 +45,16 @@ fn implicit_struct_group() {
         git: Option<String>,
     }
 
-    const OUTPUT: &str = "\
+    let output = str![[r#"
 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")));
@@ -229,13 +231,76 @@ fn required_group() {
         Opt::try_parse_from(["test", "--path=./"]).unwrap()
     );
 
-    const OUTPUT: &str = "\
+    let output = str![[r#"
 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);
+
+"#]];
+    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);
 }
diff --git a/tests/derive/help.rs b/tests/derive/help.rs
index cacf406a..558e45cd 100644
--- a/tests/derive/help.rs
+++ b/tests/derive/help.rs
@@ -220,14 +220,16 @@ fn derive_generated_error_has_full_context() {
         result.unwrap()
     );
 
-    let expected = r#"error: The following required argument was not provided: req_str
+    let expected = str![[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_eq!(result.unwrap_err().to_string(), expected);
+
+"#]];
+    assert_data_eq!(result.unwrap_err().to_string(), expected);
 }
 
 #[test]
@@ -340,18 +342,6 @@ 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)]
@@ -386,7 +376,18 @@ Options:
     let mut cmd = Args::command();
 
     let help = cmd.render_help().to_string();
-    assert_data_eq!(HELP, help);
+    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
+
+"#]]);
 }
 
 #[test]
diff --git a/tests/derive/utils.rs b/tests/derive/utils.rs
index 61063e23..c120a96a 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);
+    assert_data_eq!(actual, expected.raw());
 }