mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 22:32:33 +00:00
Merge pull request #2525 from tertsdiepraam/infer-long-args
Infer long arguments
This commit is contained in:
commit
dc8d0f1b08
3 changed files with 80 additions and 5 deletions
|
@ -50,6 +50,7 @@ bitflags! {
|
|||
const DISABLE_HELP_FLAG = 1 << 42;
|
||||
const USE_LONG_FORMAT_FOR_HELP_SC = 1 << 43;
|
||||
const DISABLE_ENV = 1 << 44;
|
||||
const INFER_LONG_ARGS = 1 << 45;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,7 +154,9 @@ impl_settings! { AppSettings, AppFlags,
|
|||
InferSubcommands("infersubcommands")
|
||||
=> Flags::INFER_SUBCOMMANDS,
|
||||
AllArgsOverrideSelf("allargsoverrideself")
|
||||
=> Flags::ARGS_OVERRIDE_SELF
|
||||
=> Flags::ARGS_OVERRIDE_SELF,
|
||||
InferLongArgs("inferlongargs")
|
||||
=> Flags::INFER_LONG_ARGS
|
||||
}
|
||||
|
||||
/// Application level settings, which affect how [`App`] operates
|
||||
|
@ -826,6 +829,14 @@ pub enum AppSettings {
|
|||
/// [aliases]: App::alias()
|
||||
InferSubcommands,
|
||||
|
||||
/// Tries to match unknown args to partial long arguments or their [aliases]. For example, to
|
||||
/// match an argument named `--test`, one could use `--t`, `--te`, `--tes`, and `--test`.
|
||||
///
|
||||
/// **NOTE:** The match *must not* be ambiguous at all in order to succeed. i.e. to match
|
||||
/// `--te` to `--test` there could not also be another argument or alias `--temp` because both
|
||||
/// start with `--te`
|
||||
InferLongArgs,
|
||||
|
||||
/// Specifies that the parser should not assume the first argument passed is the binary name.
|
||||
/// This is normally the case when using a "daemon" style mode, or an interactive CLI where one
|
||||
/// one would not normally type the binary or program name for each command.
|
||||
|
|
|
@ -1041,6 +1041,7 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
debug!("No");
|
||||
(long_arg, None)
|
||||
};
|
||||
|
||||
if let Some(opt) = self.app.args.get(&arg.to_os_string()) {
|
||||
debug!(
|
||||
"Parser::parse_long_arg: Found valid opt or flag '{}'",
|
||||
|
@ -1049,12 +1050,45 @@ impl<'help, 'app> Parser<'help, 'app> {
|
|||
self.app.settings.set(AS::ValidArgFound);
|
||||
self.seen.push(opt.id.clone());
|
||||
if opt.is_set(ArgSettings::TakesValue) {
|
||||
Ok(self.parse_opt(&val, opt, matcher)?)
|
||||
return self.parse_opt(&val, opt, matcher);
|
||||
} else {
|
||||
self.check_for_help_and_version_str(&arg)?;
|
||||
Ok(self.parse_flag(opt, matcher))
|
||||
return Ok(self.parse_flag(opt, matcher));
|
||||
}
|
||||
} else if let Some(sc_name) = self.possible_long_flag_subcommand(&arg) {
|
||||
}
|
||||
|
||||
if self.is_set(AS::InferLongArgs) {
|
||||
let arg_str = arg.to_string_lossy();
|
||||
let matches: Vec<_> = self
|
||||
.app
|
||||
.args
|
||||
.args()
|
||||
.filter(|a| {
|
||||
a.long
|
||||
.map_or(false, |long| long.starts_with(arg_str.as_ref()))
|
||||
|| a.aliases
|
||||
.iter()
|
||||
.any(|(alias, _)| alias.starts_with(arg_str.as_ref()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let [opt] = matches.as_slice() {
|
||||
debug!(
|
||||
"Parser::parse_long_arg: Found valid opt or flag '{}'",
|
||||
opt.to_string()
|
||||
);
|
||||
self.app.settings.set(AS::ValidArgFound);
|
||||
self.seen.push(opt.id.clone());
|
||||
if opt.is_set(ArgSettings::TakesValue) {
|
||||
return self.parse_opt(&val, opt, matcher);
|
||||
} else {
|
||||
self.check_for_help_and_version_str(&arg)?;
|
||||
return Ok(self.parse_flag(opt, matcher));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(sc_name) = self.possible_long_flag_subcommand(&arg) {
|
||||
Ok(ParseResult::FlagSubCommand(sc_name.to_string()))
|
||||
} else if self.is_set(AS::AllowLeadingHyphen) {
|
||||
Ok(ParseResult::MaybeHyphenValue)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
mod utils;
|
||||
|
||||
use clap::{App, Arg, ArgMatches, ArgSettings, ErrorKind};
|
||||
use clap::{App, AppSettings, Arg, ArgMatches, ArgSettings, ErrorKind};
|
||||
|
||||
#[cfg(feature = "suggestions")]
|
||||
static DYM: &str =
|
||||
|
@ -577,3 +577,33 @@ fn issue_2279() {
|
|||
|
||||
assert_eq!(after_help_heading.value_of("foo"), Some("bar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_long_arg() {
|
||||
let app = App::new("test")
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
.arg(Arg::new("racetrack").long("racetrack").alias("autobahn"))
|
||||
.arg(Arg::new("racecar").long("racecar").takes_value(true));
|
||||
|
||||
let matches = app.clone().get_matches_from(&["test", "--racec=hello"]);
|
||||
assert!(!matches.is_present("racetrack"));
|
||||
assert_eq!(matches.value_of("racecar"), Some("hello"));
|
||||
|
||||
let matches = app.clone().get_matches_from(&["test", "--racet"]);
|
||||
assert!(matches.is_present("racetrack"));
|
||||
assert_eq!(matches.value_of("racecar"), None);
|
||||
|
||||
let matches = app.clone().get_matches_from(&["test", "--auto"]);
|
||||
assert!(matches.is_present("racetrack"));
|
||||
assert_eq!(matches.value_of("racecar"), None);
|
||||
|
||||
let app = App::new("test")
|
||||
.setting(AppSettings::InferLongArgs)
|
||||
.arg(Arg::new("arg").long("arg"));
|
||||
|
||||
let matches = app.clone().get_matches_from(&["test", "--"]);
|
||||
assert!(!matches.is_present("arg"));
|
||||
|
||||
let matches = app.clone().get_matches_from(&["test", "--a"]);
|
||||
assert!(matches.is_present("arg"));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue