2157: Suggest using subcommand when supplied after `--` r=pksunkara a=ldm0



Co-authored-by: Donough Liu <ldm2993593805@163.com>
This commit is contained in:
bors[bot] 2020-10-09 16:44:53 +00:00 committed by GitHub
commit 7df091775c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 18 deletions

View file

@ -828,6 +828,27 @@ impl Error {
} }
} }
pub(crate) fn unnecessary_double_dash(arg: String, usage: String, color: ColorChoice) -> Self {
let mut c = Colorizer::new(true, color);
start_error(&mut c, "Found argument '");
c.warning(arg.clone());
c.none("' which wasn't expected, or isn't valid in this context");
c.none(format!(
"\n\nIf you tried to supply `{}` as a subcommand, remove the '--' before it.",
arg
));
put_usage(&mut c, usage);
try_help(&mut c);
Error {
message: c,
kind: ErrorKind::UnknownArgument,
info: vec![arg],
}
}
pub(crate) fn argument_not_found_auto(arg: String) -> Self { pub(crate) fn argument_not_found_auto(arg: String) -> Self {
let mut c = Colorizer::new(true, ColorChoice::Auto); let mut c = Colorizer::new(true, ColorChoice::Auto);

View file

@ -350,8 +350,6 @@ impl<'help, 'app> Parser<'help, 'app> {
// Verify all positional assertions pass // Verify all positional assertions pass
self._build(); self._build();
let has_args = self.has_args();
let mut subcmd_name: Option<String> = None; let mut subcmd_name: Option<String> = None;
let mut keep_state = false; let mut keep_state = false;
let mut external_subcommand = false; let mut external_subcommand = false;
@ -681,18 +679,9 @@ impl<'help, 'app> Parser<'help, 'app> {
external_subcommand = true; external_subcommand = true;
break; break;
} else if !((self.is_set(AS::AllowLeadingHyphen) } else if !self.has_args()
|| self.is_set(AS::AllowNegativeNumbers)) || self.is_set(AS::InferSubcommands) && self.has_subcommands()
&& arg_os.starts_with("-"))
&& !self.is_set(AS::InferSubcommands)
{ {
return Err(ClapError::unknown_argument(
arg_os.to_string_lossy().to_string(),
None,
Usage::new(self).create_usage_with_title(&[]),
self.app.color(),
));
} else if !has_args || self.is_set(AS::InferSubcommands) && self.has_subcommands() {
let cands = suggestions::did_you_mean( let cands = suggestions::did_you_mean(
&*arg_os.to_string_lossy(), &*arg_os.to_string_lossy(),
self.app.all_subcommand_names(), self.app.all_subcommand_names(),
@ -721,6 +710,22 @@ impl<'help, 'app> Parser<'help, 'app> {
self.app.color(), self.app.color(),
)); ));
} }
} else if self.is_set(AS::TrailingValues) {
// If argument followed by a `--`
if self.possible_subcommand(&arg_os).is_some() {
return Err(ClapError::unnecessary_double_dash(
arg_os.to_string_lossy().to_string(),
Usage::new(self).create_usage_with_title(&[]),
self.app.color(),
));
} else {
return Err(ClapError::unknown_argument(
arg_os.to_string_lossy().to_string(),
None,
Usage::new(self).create_usage_with_title(&[]),
self.app.color(),
));
}
} else { } else {
return Err(ClapError::unknown_argument( return Err(ClapError::unknown_argument(
arg_os.to_string_lossy().to_string(), arg_os.to_string_lossy().to_string(),
@ -1192,18 +1197,16 @@ impl<'help, 'app> Parser<'help, 'app> {
// Update the curent index // Update the curent index
self.cur_idx.set(self.cur_idx.get() + 1); self.cur_idx.set(self.cur_idx.get() + 1);
let mut val = None;
debug!("Parser::parse_long_arg: Does it contain '='..."); debug!("Parser::parse_long_arg: Does it contain '='...");
let matches; let matches;
let arg = if full_arg.contains_byte(b'=') { let (arg, val) = if full_arg.contains_byte(b'=') {
matches = full_arg.trim_start_matches(b'-'); matches = full_arg.trim_start_matches(b'-');
let (p0, p1) = matches.split_at_byte(b'='); let (p0, p1) = matches.split_at_byte(b'=');
debug!("Yes '{:?}'", p1); debug!("Yes '{:?}'", p1);
val = Some(p1); (p0, Some(p1))
p0
} else { } else {
debug!("No"); debug!("No");
full_arg.trim_start_matches(b'-') (full_arg.trim_start_matches(b'-'), None)
}; };
if let Some(opt) = self.app.args.get(&KeyType::Long(arg.to_os_string())) { if let Some(opt) = self.app.args.get(&KeyType::Long(arg.to_os_string())) {
debug!( debug!(

View file

@ -93,6 +93,16 @@ USAGE:
For more information try --help"; For more information try --help";
static SUBCMD_AFTER_DOUBLE_DASH: &str =
"error: Found argument 'subcmd' which wasn't expected, or isn't valid in this context
If you tried to supply `subcmd` as a subcommand, remove the '--' before it.
USAGE:
app [SUBCOMMAND]
For more information try --help";
#[test] #[test]
fn subcommand() { fn subcommand() {
let m = App::new("test") let m = App::new("test")
@ -382,3 +392,15 @@ fn subcommand_placeholder_test() {
.unwrap() .unwrap()
.contains("TEST_HEADER:")); .contains("TEST_HEADER:"));
} }
#[test]
fn subcommand_used_after_double_dash() {
let app = App::new("app").subcommand(App::new("subcmd"));
assert!(utils::compare_output(
app,
"app -- subcmd",
SUBCMD_AFTER_DOUBLE_DASH,
true
));
}