Repository: clap-rs/clap
Pull request #1514 (2019-06-30 23:56:55)

Pattern arg suggestion
Addresses issue #1284

## Implemented Functionality

Outputs a suggestion to try as pattern argument whenever an unknown argument is reached. If we'd like to limit those situations, I need more details.

## Refactoring

I changed the `unknown_argument` function to take an `Option<String>` rather than a `str` reference and then comparing to a magic string value. Let me know If there is a good reason not to do this.

Dylan-DPC: Thanks. Can you change this to be against v3-master branch?

Patch:
diff --git a/src/parse/errors.rs b/src/parse/errors.rs
index 8a7b94d4..45ce5708 100644
--- a/src/parse/errors.rs
+++ b/src/parse/errors.rs
@@ -842,7 +842,7 @@ impl Error {
     }
 
     #[doc(hidden)]
-    pub fn unknown_argument<A, U>(arg: A, did_you_mean: &str, usage: U, color: ColorWhen) -> Self
+    pub fn unknown_argument<A, U>(arg: A, did_you_mean: Option<String>, usage: U, color: ColorWhen) -> Self
     where
         A: Into<String>,
         U: Display,
@@ -852,19 +852,25 @@ impl Error {
             use_stderr: true,
             when: color,
         });
+
+        let suggest_pattern = format!("If you tried to supply `{}` as a PATTERN use `-- {}`", a, a);
+
+        let did_you_mean_message = match did_you_mean {
+            Some(s) => format!("{}\n", s),
+            _ => "\n".to_owned()
+        };
+
         Error {
             message: format!(
                 "{} Found argument '{}' which wasn't expected, or isn't valid in \
-                 this context{}\n\
+                 this context{}\
+                 {}\n\n\
                  {}\n\n\
                  For more information try {}",
                 c.error("error:"),
                 c.warning(&*a),
-                if did_you_mean.is_empty() {
-                    "\n".to_owned()
-                } else {
-                    format!("{}\n", did_you_mean)
-                },
+                did_you_mean_message,
+                suggest_pattern,
                 usage,
                 c.good("--help")
             ),
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 314fe73a..64072b32 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -459,7 +459,7 @@ where
                                 {
                                     return Err(ClapError::unknown_argument(
                                         &*arg_os.to_string_lossy(),
-                                        "",
+                                        None,
                                         &*Usage::new(self).create_usage_with_title(&[]),
                                         self.app.color(),
                                     ));
@@ -578,7 +578,7 @@ where
                 if p.is_set(ArgSettings::Last) && !self.is_set(AS::TrailingValues) {
                     return Err(ClapError::unknown_argument(
                         &*arg_os.to_string_lossy(),
-                        "",
+                        None,
                         &*Usage::new(self).create_usage_with_title(&[]),
                         self.app.color(),
                     ));
@@ -652,7 +652,7 @@ where
             {
                 return Err(ClapError::unknown_argument(
                     &*arg_os.to_string_lossy(),
-                    "",
+                    None,
                     &*Usage::new(self).create_usage_with_title(&[]),
                     self.app.color(),
                 ));
@@ -677,7 +677,7 @@ where
             } else {
                 return Err(ClapError::unknown_argument(
                     &*arg_os.to_string_lossy(),
-                    "",
+                    None,
                     &*Usage::new(self).create_usage_with_title(&[]),
                     self.app.color(),
                 ));
@@ -1129,7 +1129,7 @@ where
                 let arg = format!("-{}", c);
                 return Err(ClapError::unknown_argument(
                     &*arg,
-                    "",
+                    None,
                     &*Usage::new(self).create_usage_with_title(&[]),
                     self.app.color(),
                 ));
@@ -1499,9 +1499,16 @@ where
             })
             .cloned()
             .collect();
+
+        let did_you_mean_msg = if suffix.0.is_empty() {
+            None
+        } else {
+            Some(suffix.0)
+        };
+
         Err(ClapError::unknown_argument(
             &*format!("--{}", arg),
-            &*suffix.0,
+            did_you_mean_msg,
             &*Usage::new(self).create_usage_with_title(&*used),
             self.app.color(),
         ))


Test patch:
diff --git a/tests/opts.rs b/tests/opts.rs
index 6016f9f8..6c38d336 100644
--- a/tests/opts.rs
+++ b/tests/opts.rs
@@ -9,6 +9,7 @@ use clap::{App, Arg, ArgMatches, ArgSettings, ErrorKind};
 static DYM: &'static str =
     "error: Found argument '--optio' which wasn't expected, or isn't valid in this context
 \tDid you mean --option?
+If you tried to supply `--optio` as a PATTERN use `-- --optio`
 
 USAGE:
     clap-test --option <opt>...
diff --git a/tests/subcommands.rs b/tests/subcommands.rs
index c2036a01..5959f282 100644
--- a/tests/subcommands.rs
+++ b/tests/subcommands.rs
@@ -46,6 +46,7 @@ For more information try --help";
 static DYM_ARG: &'static str =
     "error: Found argument '--subcm' which wasn't expected, or isn't valid in this context
 \tDid you mean to put '--subcmdarg' after the subcommand 'subcmd'?
+If you tried to supply `--subcm` as a PATTERN use `-- --subcm`
 
 USAGE:
     dym [SUBCOMMAND]