Skip to content

Commit d02e24a

Browse files
authored
Merge pull request clap-rs#980 from little-dude/flag
Suggest to use flag after a sub-command
2 parents 2b144cf + e8518cf commit d02e24a

File tree

6 files changed

+51
-35
lines changed

6 files changed

+51
-35
lines changed

clap-test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ mod test {
7070
.version("0.1")
7171
.author("Kevin K. <[email protected]>")
7272
.arg_from_usage("-o --option [scoption]... 'tests options'")
73+
.arg_from_usage("-s --subcmdarg [subcmdarg] 'tests other args'")
7374
.arg_from_usage("[scpositional] 'tests positionals'"))
7475
}
7576
}

src/app/parser.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1652,11 +1652,10 @@ impl<'a, 'b> Parser<'a, 'b>
16521652
}
16531653

16541654
fn did_you_mean_error(&self, arg: &str, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
1655-
// Didn't match a flag or option...maybe it was a typo and close to one
1655+
1656+
// Didn't match a flag or option
16561657
let suffix =
1657-
suggestions::did_you_mean_suffix(arg,
1658-
longs!(self),
1659-
suggestions::DidYouMeanMessageStyle::LongFlag);
1658+
suggestions::did_you_mean_flag_suffix(arg, longs!(self), &self.subcommands);
16601659

16611660
// Add the arg to the matches to build a proper usage string
16621661
if let Some(name) = suffix.1 {

src/errors.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -483,9 +483,9 @@ impl Error {
483483
when: color,
484484
});
485485
let suffix =
486-
suggestions::did_you_mean_suffix(bad_val.as_ref(),
487-
good_vals.iter(),
488-
suggestions::DidYouMeanMessageStyle::EnumValue);
486+
suggestions::did_you_mean_value_suffix(
487+
bad_val.as_ref(),
488+
good_vals.iter());
489489

490490
let mut sorted = vec![];
491491
for v in good_vals {

src/suggestions.rs

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use app::App;
12
// Third Party
23
#[cfg(feature = "suggestions")]
34
use strsim;
@@ -40,40 +41,46 @@ pub fn did_you_mean<'a, T: ?Sized, I>(_: &str, _: I) -> Option<&'a str>
4041

4142
/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
4243
#[cfg_attr(feature = "lints", allow(needless_lifetimes))]
43-
pub fn did_you_mean_suffix<'z, T, I>(arg: &str,
44-
values: I,
45-
style: DidYouMeanMessageStyle)
44+
pub fn did_you_mean_flag_suffix<'z, T, I>(arg: &str, longs: I, subcommands: &'z [App])
4645
-> (String, Option<&'z str>)
4746
where T: AsRef<str> + 'z,
4847
I: IntoIterator<Item = &'z T>
4948
{
50-
match did_you_mean(arg, values) {
49+
match did_you_mean(arg, longs) {
5150
Some(candidate) => {
52-
let mut suffix = "\n\tDid you mean ".to_owned();
53-
match style {
54-
DidYouMeanMessageStyle::LongFlag => {
55-
suffix.push_str(&Format::Good("--").to_string())
51+
let suffix = format!("\n\tDid you mean {}{}?", Format::Good("--"), Format::Good(candidate));
52+
return (suffix, Some(candidate))
53+
}
54+
None => {
55+
for subcommand in subcommands {
56+
let opts = subcommand.p.flags.iter().filter_map(|f| f.s.long).chain(
57+
subcommand.p.opts.iter().filter_map(|o| o.s.long));
58+
59+
if let Some(candidate) = did_you_mean(arg, opts) {
60+
let suffix = format!(
61+
"\n\tDid you mean to put '--{}' after the subcommand '{}'?",
62+
Format::Good(arg),
63+
Format::Good(candidate));
64+
return (suffix, Some(candidate));
5665
}
57-
DidYouMeanMessageStyle::EnumValue => suffix.push('\''),
58-
}
59-
suffix.push_str(&Format::Good(candidate).to_string()[..]);
60-
if let DidYouMeanMessageStyle::EnumValue = style {
61-
suffix.push('\'');
6266
}
63-
suffix.push_str("?");
64-
(suffix, Some(candidate))
6567
}
66-
None => (String::new(), None),
6768
}
69+
return (String::new(), None)
6870
}
6971

70-
/// A helper to determine message formatting
71-
#[derive(Copy, Clone, Debug)]
72-
pub enum DidYouMeanMessageStyle {
73-
/// Suggested value is a long flag
74-
LongFlag,
75-
/// Suggested value is one of various possible values
76-
EnumValue,
72+
/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
73+
pub fn did_you_mean_value_suffix<'z, T, I>(arg: &str, values: I) -> (String, Option<&'z str>)
74+
where T: AsRef<str> + 'z,
75+
I: IntoIterator<Item = &'z T>
76+
{
77+
match did_you_mean(arg, values) {
78+
Some(candidate) => {
79+
let suffix = format!("\n\tDid you mean '{}'?", Format::Good(candidate));
80+
(suffix, Some(candidate))
81+
}
82+
None => (String::new(), None),
83+
}
7784
}
7885

7986
#[cfg(all(test, features = "suggestions"))]
@@ -96,15 +103,13 @@ mod test {
96103
fn suffix_long() {
97104
let p_vals = ["test", "possible", "values"];
98105
let suffix = "\n\tDid you mean \'--test\'?";
99-
assert_eq!(did_you_mean_suffix("tst", p_vals.iter(), DidYouMeanMessageStyle::LongFlag),
100-
(suffix, Some("test")));
106+
assert_eq!(did_you_mean_flag_suffix("tst", p_vals.iter(), []), (suffix, Some("test")));
101107
}
102108

103109
#[test]
104110
fn suffix_enum() {
105111
let p_vals = ["test", "possible", "values"];
106112
let suffix = "\n\tDid you mean \'test\'?";
107-
assert_eq!(did_you_mean_suffix("tst", p_vals.iter(), DidYouMeanMessageStyle::EnumValue),
108-
(suffix, Some("test")));
113+
assert_eq!(did_you_mean_value_suffix("tst", p_vals.iter()), (suffix, Some("test")));
109114
}
110115
}

tests/help.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ FLAGS:
118118
-V, --version Prints version information
119119
120120
OPTIONS:
121-
-o, --option <scoption>... tests options
121+
-o, --option <scoption>... tests options
122+
-s, --subcmdarg <subcmdarg> tests other args
122123
123124
ARGS:
124125
<scpositional> tests positionals";

tests/subcommands.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ USAGE:
4242
4343
For more information try --help";
4444

45+
#[cfg(feature = "suggestions")]
46+
static DYM2: &'static str = "error: Found argument '--subcmdarg' which wasn't expected, or isn't valid in this context
47+
\tDid you mean to put '--subcmdarg' after the subcommand 'subcmdarg'?
48+
49+
USAGE:
50+
clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]
51+
52+
For more information try --help";
53+
4554
#[test]
4655
fn subcommand() {
4756
let m = App::new("test")
@@ -121,6 +130,7 @@ fn multiple_aliases() {
121130
#[cfg(feature="suggestions")]
122131
fn subcmd_did_you_mean_output() {
123132
assert!(test::compare_output(test::complex_app(), "clap-test subcm", DYM, true));
133+
assert!(test::compare_output(test::complex_app(), "clap-test --subcmdarg foo", DYM2, true));
124134
}
125135

126136
#[test]

0 commit comments

Comments
 (0)