Skip to content

Commit b05506b

Browse files
committed
feat: suggest fuzzy matches in case of unrecognized arguments
1 parent 7c4d1e6 commit b05506b

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

argh/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ readme = "README.md"
1212
[dependencies]
1313
argh_shared = { version = "0.1.12", path = "../argh_shared" }
1414
argh_derive = { version = "0.1.12", path = "../argh_derive" }
15+
rust-fuzzy-search = "0.1.1"
1516

1617
[dev-dependencies]
1718
once_cell = "1.10.0"

argh/src/lib.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@ pub type SubCommandInfo = argh_shared::SubCommandInfo<'static>;
331331

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

334+
use rust_fuzzy_search::fuzzy_search_best_n;
335+
334336
/// Structured information about the command line arguments.
335337
pub trait ArgsInfo {
336338
/// Returns the argument info.
@@ -972,7 +974,13 @@ impl<'a> ParseStructOptions<'a> {
972974
.arg_to_slot
973975
.iter()
974976
.find_map(|&(name, pos)| if name == arg { Some(pos) } else { None })
975-
.ok_or_else(|| unrecognized_argument(arg))?;
977+
.ok_or_else(|| {
978+
unrecognized_argument(
979+
arg,
980+
self.arg_to_slot,
981+
&vec!["--help".to_owned(), "help".to_owned()],
982+
)
983+
})?;
976984

977985
match self.slots[pos] {
978986
ParseStructOption::Flag(ref mut b) => b.set_flag(arg),
@@ -992,8 +1000,24 @@ impl<'a> ParseStructOptions<'a> {
9921000
}
9931001
}
9941002

995-
fn unrecognized_argument(x: &str) -> String {
996-
["Unrecognized argument: ", x, "\n"].concat()
1003+
fn unrecognized_argument(
1004+
given: &str,
1005+
arg_to_slot: &[(&str, usize)],
1006+
extra_suggestions: &[String],
1007+
) -> String {
1008+
// get the list of available arguments
1009+
let available = arg_to_slot
1010+
.iter()
1011+
.map(|(name, _pos)| *name)
1012+
.chain(extra_suggestions.iter().map(|s| s.as_str()))
1013+
.collect::<Vec<&str>>();
1014+
1015+
if available.is_empty() {
1016+
return format!("Unrecognized argument: \"{}\"", given);
1017+
}
1018+
1019+
let suggestions = fuzzy_search_best_n(given, &available, 1);
1020+
format!("Unrecognized argument: \"{}\". Did you mean \"{}\"?", given, suggestions[0].0)
9971021
}
9981022

9991023
// `--` or `-` options, including a mutable reference to their value.

0 commit comments

Comments
 (0)