diff --git a/clap_builder/src/parser/parser.rs b/clap_builder/src/parser/parser.rs index 98b28eeb..a00ed02a 100644 --- a/clap_builder/src/parser/parser.rs +++ b/clap_builder/src/parser/parser.rs @@ -544,19 +544,24 @@ impl<'cmd> Parser<'cmd> { if self.cmd.is_infer_subcommands_set() { // For subcommand `test`, we accepts it's prefix: `t`, `te`, // `tes` and `test`. - let v = self - .cmd - .all_subcommand_names() - .filter(|s| s.starts_with(arg)) - .collect::>(); + let mut iter = self.cmd.get_subcommands().filter_map(|s| { + if s.get_name().starts_with(arg) { + return Some(s.get_name()); + } - if v.len() == 1 { - return Some(v[0]); + // Use find here instead of chaining the iterator because we want to accept + // conflicts in aliases. + s.get_all_aliases().find(|s| s.starts_with(arg)) + }); + + if let name @ Some(_) = iter.next() { + if iter.next().is_none() { + return name; + } } - - // If there is any ambiguity, fallback to non-infer subcommand - // search. } + // Don't use an else here because we want inference to support exact matching even if + // there are conflicts. if let Some(sc) = self.cmd.find_subcommand(arg) { return Some(sc.get_name()); } diff --git a/tests/builder/app_settings.rs b/tests/builder/app_settings.rs index d9aafa77..1fa3d919 100644 --- a/tests/builder/app_settings.rs +++ b/tests/builder/app_settings.rs @@ -258,8 +258,9 @@ fn infer_subcommands_pass_conflicting_aliases() { let m = Command::new("prog") .infer_subcommands(true) .subcommand(Command::new("test").aliases(["testa", "t", "testb"])) - .try_get_matches_from(vec!["prog", "te"]); - assert!(m.is_err(), "{:#?}", m.unwrap()); + .try_get_matches_from(vec!["prog", "te"]) + .unwrap(); + assert_eq!(m.subcommand_name(), Some("test")); } #[test]