diff --git a/src/app/parser.rs b/src/app/parser.rs index 9f373fb6..afff8f2a 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -1662,11 +1662,10 @@ impl<'a, 'b> Parser<'a, 'b> } fn did_you_mean_error(&self, arg: &str, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { - // Didn't match a flag or option...maybe it was a typo and close to one + + // Didn't match a flag or option let suffix = - suggestions::did_you_mean_suffix(arg, - longs!(self), - suggestions::DidYouMeanMessageStyle::LongFlag); + suggestions::did_you_mean_arg_suffix(arg, longs!(self), &self.subcommands); // Add the arg to the matches to build a proper usage string if let Some(name) = suffix.1 { diff --git a/src/errors.rs b/src/errors.rs index 1781067f..bd1e7d55 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -483,9 +483,9 @@ impl Error { when: color, }); let suffix = - suggestions::did_you_mean_suffix(bad_val.as_ref(), - good_vals.iter(), - suggestions::DidYouMeanMessageStyle::EnumValue); + suggestions::did_you_mean_value_suffix( + bad_val.as_ref(), + good_vals.iter()); let mut sorted = vec![]; for v in good_vals { diff --git a/src/suggestions.rs b/src/suggestions.rs index 5c7cade5..2d3104b6 100644 --- a/src/suggestions.rs +++ b/src/suggestions.rs @@ -1,3 +1,4 @@ +use app::App; // Third Party #[cfg(feature = "suggestions")] use strsim; @@ -40,42 +41,48 @@ pub fn did_you_mean<'a, T: ?Sized, I>(_: &str, _: I) -> Option<&'a str> /// Returns a suffix that can be empty, or is the standard 'did you mean' phrase #[cfg_attr(feature = "lints", allow(needless_lifetimes))] -pub fn did_you_mean_suffix<'z, T, I>(arg: &str, - values: I, - style: DidYouMeanMessageStyle) +pub fn did_you_mean_flag_suffix<'z, T, I>(arg: &str, longs: I, subcommands: &'z [App]) -> (String, Option<&'z str>) where T: AsRef + 'z, I: IntoIterator +{ + match did_you_mean(arg, longs) { + Some(candidate) => { + let suffix = format!("\n\tDid you mean {}{}?", Format::Good("--"), Format::Good(candidate)); + return (suffix, Some(candidate)) + } + None => { + for subcommand in subcommands { + let opts = subcommand.p.flags.iter().filter_map(|f| f.s.long).chain( + subcommand.p.opts.iter().filter_map(|o| o.s.long)); + + if let Some(candidate) = did_you_mean(arg, opts) { + let suffix = format!( + "\n\tDid you mean to put '--{}' after the subcommand '{}'?", + Format::Good(arg), + Format::Good(candidate)); + return (suffix, Some(candidate)); + } + } + } + } + return (String::new(), None) +} + +/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase +pub fn did_you_mean_value_suffix<'z, T, I>(arg: &str, values: I) -> (String, Option<&'z str>) + where T: AsRef + 'z, + I: IntoIterator { match did_you_mean(arg, values) { Some(candidate) => { - let mut suffix = "\n\tDid you mean ".to_owned(); - match style { - DidYouMeanMessageStyle::LongFlag => { - suffix.push_str(&Format::Good("--").to_string()) - } - DidYouMeanMessageStyle::EnumValue => suffix.push('\''), - } - suffix.push_str(&Format::Good(candidate).to_string()[..]); - if let DidYouMeanMessageStyle::EnumValue = style { - suffix.push('\''); - } - suffix.push_str("?"); + let suffix = format!("\n\tDid you mean '{}'?", Format::Good(candidate)); (suffix, Some(candidate)) } None => (String::new(), None), } } -/// A helper to determine message formatting -#[derive(Copy, Clone, Debug)] -pub enum DidYouMeanMessageStyle { - /// Suggested value is a long flag - LongFlag, - /// Suggested value is one of various possible values - EnumValue, -} - #[cfg(all(test, features = "suggestions"))] mod test { use super::*;