Skip to content

Commit

Permalink
imp(Suggestions): suggests to use flag after subcommand when applicable
Browse files Browse the repository at this point in the history
If an invalid flag is found and this flag is a valid flag for a
sub-command, suggest using it after the subcommand

fix #927
  • Loading branch information
little-dude committed Jun 12, 2017
1 parent 49f9dc1 commit 2671ca7
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 30 deletions.
7 changes: 3 additions & 4 deletions src/app/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 3 additions & 3 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
53 changes: 30 additions & 23 deletions src/suggestions.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use app::App;
// Third Party
#[cfg(feature = "suggestions")]
use strsim;
Expand Down Expand Up @@ -40,40 +41,46 @@ 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<str> + 'z,
I: IntoIterator<Item = &'z T>
{
match did_you_mean(arg, values) {
match did_you_mean(arg, longs) {
Some(candidate) => {
let mut suffix = "\n\tDid you mean ".to_owned();
match style {
DidYouMeanMessageStyle::LongFlag => {
suffix.push_str(&Format::Good("--").to_string())
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));
}
DidYouMeanMessageStyle::EnumValue => suffix.push('\''),
}
suffix.push_str(&Format::Good(candidate).to_string()[..]);
if let DidYouMeanMessageStyle::EnumValue = style {
suffix.push('\'');
}
suffix.push_str("?");
(suffix, Some(candidate))
}
None => (String::new(), None),
}
return (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,
/// 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<str> + 'z,
I: IntoIterator<Item = &'z T>
{
match did_you_mean(arg, values) {
Some(candidate) => {
let suffix = format!("\n\tDid you mean '{}'?", Format::Good(candidate));
(suffix, Some(candidate))
}
None => (String::new(), None),
}
}

#[cfg(all(test, features = "suggestions"))]
Expand Down

0 comments on commit 2671ca7

Please sign in to comment.