Skip to content

Commit

Permalink
Suggest fuzzy matches in case of unrecognized arguments (#180)
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya authored Nov 13, 2023
1 parent f1037ba commit 6149a1a
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 4 deletions.
1 change: 1 addition & 0 deletions argh/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ readme = "README.md"
[dependencies]
argh_shared = { version = "0.1.12", path = "../argh_shared" }
argh_derive = { version = "0.1.12", path = "../argh_derive" }
rust-fuzzy-search = "0.1.1"

[dev-dependencies]
once_cell = "1.10.0"
Expand Down
24 changes: 21 additions & 3 deletions argh/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@ pub type SubCommandInfo = argh_shared::SubCommandInfo<'static>;

pub use argh_shared::{ErrorCodeInfo, FlagInfo, FlagInfoKind, Optionality, PositionalInfo};

use rust_fuzzy_search::fuzzy_search_best_n;

/// Structured information about the command line arguments.
pub trait ArgsInfo {
/// Returns the argument info.
Expand Down Expand Up @@ -976,7 +978,7 @@ impl<'a> ParseStructOptions<'a> {
.arg_to_slot
.iter()
.find_map(|&(name, pos)| if name == arg { Some(pos) } else { None })
.ok_or_else(|| unrecognized_argument(arg))?;
.ok_or_else(|| unrecognized_argument(arg, self.arg_to_slot, self.help_triggers))?;

match self.slots[pos] {
ParseStructOption::Flag(ref mut b) => b.set_flag(arg),
Expand All @@ -996,8 +998,24 @@ impl<'a> ParseStructOptions<'a> {
}
}

fn unrecognized_argument(x: &str) -> String {
["Unrecognized argument: ", x, "\n"].concat()
fn unrecognized_argument(
given: &str,
arg_to_slot: &[(&str, usize)],
extra_suggestions: &[&str],
) -> String {
// get the list of available arguments
let available = arg_to_slot
.iter()
.map(|(name, _pos)| *name)
.chain(extra_suggestions.iter().copied())
.collect::<Vec<&str>>();

if available.is_empty() {
return format!("Unrecognized argument: \"{}\"\n", given);
}

let suggestions = fuzzy_search_best_n(given, &available, 1);
format!("Unrecognized argument: \"{}\". Did you mean \"{}\"?\n", given, suggestions[0].0)
}

// `--` or `-` options, including a mutable reference to their value.
Expand Down
2 changes: 1 addition & 1 deletion argh/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -911,7 +911,7 @@ mod fuchsia_commandline_tools_rubric {

let e = OneOption::from_args(&["cmdname"], &["--foo=bar"])
.expect_err("Parsing option value using `=` should fail");
assert_eq!(e.output, "Unrecognized argument: --foo=bar\n");
assert_eq!(e.output, "Unrecognized argument: \"--foo=bar\". Did you mean \"--foo\"?\n");
assert!(e.status.is_err());
}

Expand Down

0 comments on commit 6149a1a

Please sign in to comment.