diff options
Diffstat (limited to 'vendor/clap_builder/src')
-rw-r--r-- | vendor/clap_builder/src/builder/arg.rs | 2 | ||||
-rw-r--r-- | vendor/clap_builder/src/builder/command.rs | 60 | ||||
-rw-r--r-- | vendor/clap_builder/src/builder/debug_asserts.rs | 3 | ||||
-rw-r--r-- | vendor/clap_builder/src/builder/mod.rs | 8 | ||||
-rw-r--r-- | vendor/clap_builder/src/builder/range.rs | 2 | ||||
-rw-r--r-- | vendor/clap_builder/src/builder/styled_str.rs | 15 | ||||
-rw-r--r-- | vendor/clap_builder/src/builder/styling.rs | 2 | ||||
-rw-r--r-- | vendor/clap_builder/src/builder/value_parser.rs | 190 | ||||
-rw-r--r-- | vendor/clap_builder/src/derive.rs | 2 | ||||
-rw-r--r-- | vendor/clap_builder/src/error/mod.rs | 4 | ||||
-rw-r--r-- | vendor/clap_builder/src/lib.rs | 7 | ||||
-rw-r--r-- | vendor/clap_builder/src/macros.rs | 6 | ||||
-rw-r--r-- | vendor/clap_builder/src/mkeymap.rs | 9 | ||||
-rw-r--r-- | vendor/clap_builder/src/output/help.rs | 6 | ||||
-rw-r--r-- | vendor/clap_builder/src/parser/matches/arg_matches.rs | 12 | ||||
-rw-r--r-- | vendor/clap_builder/src/parser/parser.rs | 83 |
16 files changed, 336 insertions, 75 deletions
diff --git a/vendor/clap_builder/src/builder/arg.rs b/vendor/clap_builder/src/builder/arg.rs index d067dec1d..5634078c5 100644 --- a/vendor/clap_builder/src/builder/arg.rs +++ b/vendor/clap_builder/src/builder/arg.rs @@ -470,7 +470,7 @@ impl Arg { /// /// [`Command`] will [`panic!`] if indexes are skipped (such as defining `index(1)` and `index(3)` /// but not `index(2)`, or a positional argument is defined as multiple and is not the highest - /// index + /// index (debug builds) /// /// # Examples /// diff --git a/vendor/clap_builder/src/builder/command.rs b/vendor/clap_builder/src/builder/command.rs index b2efdbc7e..b1623cf8c 100644 --- a/vendor/clap_builder/src/builder/command.rs +++ b/vendor/clap_builder/src/builder/command.rs @@ -252,6 +252,52 @@ impl Command { self } + /// Allows one to mutate all [`Arg`]s after they've been added to a [`Command`]. + /// + /// This does not affect the built-in `--help` or `--version` arguments. + /// + /// # Examples + /// + #[cfg_attr(feature = "string", doc = "```")] + #[cfg_attr(not(feature = "string"), doc = "```ignore")] + /// # use clap_builder as clap; + /// # use clap::{Command, Arg, ArgAction}; + /// + /// let mut cmd = Command::new("foo") + /// .arg(Arg::new("bar") + /// .long("bar") + /// .action(ArgAction::SetTrue)) + /// .arg(Arg::new("baz") + /// .long("baz") + /// .action(ArgAction::SetTrue)) + /// .mut_args(|a| { + /// if let Some(l) = a.get_long().map(|l| format!("prefix-{l}")) { + /// a.long(l) + /// } else { + /// a + /// } + /// }); + /// + /// let res = cmd.try_get_matches_from_mut(vec!["foo", "--bar"]); + /// + /// // Since we changed `bar`'s long to "prefix-bar" this should err as there + /// // is no `--bar` anymore, only `--prefix-bar`. + /// + /// assert!(res.is_err()); + /// + /// let res = cmd.try_get_matches_from_mut(vec!["foo", "--prefix-bar"]); + /// assert!(res.is_ok()); + /// ``` + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn mut_args<F>(mut self, f: F) -> Self + where + F: FnMut(Arg) -> Arg, + { + self.args.mut_args(f); + self + } + /// Allows one to mutate a [`Command`] after it's been added as a subcommand. /// /// This can be useful for modifying auto-generated arguments of nested subcommands with @@ -507,7 +553,7 @@ impl Command { /// /// # Panics /// - /// If contradictory arguments or settings exist. + /// If contradictory arguments or settings exist (debug builds). /// /// # Examples /// @@ -531,7 +577,7 @@ impl Command { /// /// # Panics /// - /// If contradictory arguments or settings exist. + /// If contradictory arguments or settings exist (debug builds). /// /// # Examples /// @@ -559,7 +605,7 @@ impl Command { /// /// # Panics /// - /// If contradictory arguments or settings exist. + /// If contradictory arguments or settings exist (debug builds). /// /// # Examples /// @@ -592,7 +638,7 @@ impl Command { /// /// # Panics /// - /// If contradictory arguments or settings exist. + /// If contradictory arguments or settings exist (debug builds). /// /// # Examples /// @@ -631,7 +677,7 @@ impl Command { /// /// # Panics /// - /// If contradictory arguments or settings exist. + /// If contradictory arguments or settings exist (debug builds). /// /// # Examples /// @@ -677,7 +723,7 @@ impl Command { /// /// # Panics /// - /// If contradictory arguments or settings exist. + /// If contradictory arguments or settings exist (debug builds). /// /// # Examples /// @@ -1124,7 +1170,6 @@ impl Command { #[cfg(feature = "color")] #[inline] #[must_use] - #[cfg(feature = "unstable-styles")] pub fn styles(mut self, styles: Styles) -> Self { self.app_ext.set(styles); self @@ -1369,6 +1414,7 @@ impl Command { /// /// # Panics /// + /// On debug builds: /// ```rust,no_run /// # use clap_builder as clap; /// # use clap::{Command, Arg}; diff --git a/vendor/clap_builder/src/builder/debug_asserts.rs b/vendor/clap_builder/src/builder/debug_asserts.rs index 29008be9f..afc181c54 100644 --- a/vendor/clap_builder/src/builder/debug_asserts.rs +++ b/vendor/clap_builder/src/builder/debug_asserts.rs @@ -746,8 +746,9 @@ fn assert_arg(arg: &Arg) { ); assert!( arg.is_takes_value_set(), - "Argument '{}` is positional, it must take a value{}", + "Argument '{}` is positional and it must take a value but action is {:?}{}", arg.get_id(), + arg.get_action(), if arg.get_id() == Id::HELP { " (`mut_arg` no longer works with implicit `--help`)" } else if arg.get_id() == Id::VERSION { diff --git a/vendor/clap_builder/src/builder/mod.rs b/vendor/clap_builder/src/builder/mod.rs index ad70911a9..320a45344 100644 --- a/vendor/clap_builder/src/builder/mod.rs +++ b/vendor/clap_builder/src/builder/mod.rs @@ -23,10 +23,7 @@ mod debug_asserts; #[cfg(test)] mod tests; -#[cfg(feature = "unstable-styles")] pub mod styling; -#[cfg(not(feature = "unstable-styles"))] -pub(crate) mod styling; pub use self::str::Str; pub use action::ArgAction; @@ -40,7 +37,6 @@ pub use range::ValueRange; pub use resettable::IntoResettable; pub use resettable::Resettable; pub use styled_str::StyledStr; -#[cfg(feature = "unstable-styles")] pub use styling::Styles; pub use value_hint::ValueHint; pub use value_parser::_AutoValueParser; @@ -57,7 +53,9 @@ pub use value_parser::PossibleValuesParser; pub use value_parser::RangedI64ValueParser; pub use value_parser::RangedU64ValueParser; pub use value_parser::StringValueParser; +pub use value_parser::TryMapValueParser; pub use value_parser::TypedValueParser; +pub use value_parser::UnknownArgumentValueParser; pub use value_parser::ValueParser; pub use value_parser::ValueParserFactory; pub use value_parser::_AnonymousValueParser; @@ -67,5 +65,3 @@ pub(crate) use self::str::Inner as StrInner; pub(crate) use action::CountType; pub(crate) use arg_settings::{ArgFlags, ArgSettings}; pub(crate) use command::AppTag; -#[cfg(not(feature = "unstable-styles"))] -pub(crate) use styling::Styles; diff --git a/vendor/clap_builder/src/builder/range.rs b/vendor/clap_builder/src/builder/range.rs index a40391545..158d02ccb 100644 --- a/vendor/clap_builder/src/builder/range.rs +++ b/vendor/clap_builder/src/builder/range.rs @@ -22,7 +22,7 @@ impl ValueRange { /// /// # Panics /// - /// If the end is less than the start + /// If the end is less than the start (debug builds) /// /// # Examples /// diff --git a/vendor/clap_builder/src/builder/styled_str.rs b/vendor/clap_builder/src/builder/styled_str.rs index d856a3015..df0f1b03b 100644 --- a/vendor/clap_builder/src/builder/styled_str.rs +++ b/vendor/clap_builder/src/builder/styled_str.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "usage"), allow(dead_code))] + /// Terminal-styling container /// /// Styling may be encoded as [ANSI Escape Code](https://en.wikipedia.org/wiki/ANSI_escape_code) @@ -47,6 +49,19 @@ impl StyledStr { self.0 = self.0.trim().to_owned() } + pub(crate) fn trim_start_lines(&mut self) { + if let Some(pos) = self.0.find('\n') { + let (leading, help) = self.0.split_at(pos + 1); + if leading.trim().is_empty() { + self.0 = help.to_owned() + } + } + } + + pub(crate) fn trim_end(&mut self) { + self.0 = self.0.trim_end().to_owned() + } + #[cfg(feature = "help")] pub(crate) fn replace_newline_var(&mut self) { self.0 = self.0.replace("{n}", "\n"); diff --git a/vendor/clap_builder/src/builder/styling.rs b/vendor/clap_builder/src/builder/styling.rs index f7f2ee1e3..3a034489b 100644 --- a/vendor/clap_builder/src/builder/styling.rs +++ b/vendor/clap_builder/src/builder/styling.rs @@ -10,7 +10,6 @@ pub use anstyle::*; /// /// clap v3 styling /// ```rust -/// # #[cfg(feature = "unstable-styles")] { /// # use clap_builder as clap; /// # use clap::builder::styling::*; /// let styles = Styles::styled() @@ -18,7 +17,6 @@ pub use anstyle::*; /// .usage(AnsiColor::Green.on_default()) /// .literal(AnsiColor::Green.on_default()) /// .placeholder(AnsiColor::Green.on_default()); -/// # } /// ``` #[derive(Clone, Debug)] #[allow(missing_copy_implementations)] // Large enough type that I want an explicit `clone()` for now diff --git a/vendor/clap_builder/src/builder/value_parser.rs b/vendor/clap_builder/src/builder/value_parser.rs index c7c7e61eb..1f0ef925f 100644 --- a/vendor/clap_builder/src/builder/value_parser.rs +++ b/vendor/clap_builder/src/builder/value_parser.rs @@ -1,6 +1,9 @@ use std::convert::TryInto; use std::ops::RangeBounds; +use crate::builder::Str; +use crate::builder::StyledStr; +use crate::parser::ValueSource; use crate::util::AnyValue; use crate::util::AnyValueId; @@ -234,8 +237,9 @@ impl ValueParser { cmd: &crate::Command, arg: Option<&crate::Arg>, value: &std::ffi::OsStr, + source: ValueSource, ) -> Result<AnyValue, crate::Error> { - self.any_value_parser().parse_ref(cmd, arg, value) + self.any_value_parser().parse_ref_(cmd, arg, value, source) } /// Describes the content of `AnyValue` @@ -592,6 +596,16 @@ trait AnyValueParser: Send + Sync + 'static { value: &std::ffi::OsStr, ) -> Result<AnyValue, crate::Error>; + fn parse_ref_( + &self, + cmd: &crate::Command, + arg: Option<&crate::Arg>, + value: &std::ffi::OsStr, + _source: ValueSource, + ) -> Result<AnyValue, crate::Error> { + self.parse_ref(cmd, arg, value) + } + fn parse( &self, cmd: &crate::Command, @@ -599,6 +613,16 @@ trait AnyValueParser: Send + Sync + 'static { value: std::ffi::OsString, ) -> Result<AnyValue, crate::Error>; + fn parse_( + &self, + cmd: &crate::Command, + arg: Option<&crate::Arg>, + value: std::ffi::OsString, + _source: ValueSource, + ) -> Result<AnyValue, crate::Error> { + self.parse(cmd, arg, value) + } + /// Describes the content of `AnyValue` fn type_id(&self) -> AnyValueId; @@ -624,6 +648,17 @@ where Ok(AnyValue::new(value)) } + fn parse_ref_( + &self, + cmd: &crate::Command, + arg: Option<&crate::Arg>, + value: &std::ffi::OsStr, + source: ValueSource, + ) -> Result<AnyValue, crate::Error> { + let value = ok!(TypedValueParser::parse_ref_(self, cmd, arg, value, source)); + Ok(AnyValue::new(value)) + } + fn parse( &self, cmd: &crate::Command, @@ -634,6 +669,17 @@ where Ok(AnyValue::new(value)) } + fn parse_( + &self, + cmd: &crate::Command, + arg: Option<&crate::Arg>, + value: std::ffi::OsString, + source: ValueSource, + ) -> Result<AnyValue, crate::Error> { + let value = ok!(TypedValueParser::parse_(self, cmd, arg, value, source)); + Ok(AnyValue::new(value)) + } + fn type_id(&self) -> AnyValueId { AnyValueId::of::<T>() } @@ -717,6 +763,19 @@ pub trait TypedValueParser: Clone + Send + Sync + 'static { /// Parse the argument value /// /// When `arg` is `None`, an external subcommand value is being parsed. + fn parse_ref_( + &self, + cmd: &crate::Command, + arg: Option<&crate::Arg>, + value: &std::ffi::OsStr, + _source: ValueSource, + ) -> Result<Self::Value, crate::Error> { + self.parse_ref(cmd, arg, value) + } + + /// Parse the argument value + /// + /// When `arg` is `None`, an external subcommand value is being parsed. fn parse( &self, cmd: &crate::Command, @@ -726,6 +785,19 @@ pub trait TypedValueParser: Clone + Send + Sync + 'static { self.parse_ref(cmd, arg, &value) } + /// Parse the argument value + /// + /// When `arg` is `None`, an external subcommand value is being parsed. + fn parse_( + &self, + cmd: &crate::Command, + arg: Option<&crate::Arg>, + value: std::ffi::OsString, + _source: ValueSource, + ) -> Result<Self::Value, crate::Error> { + self.parse(cmd, arg, value) + } + /// Reflect on enumerated value properties /// /// Error checking should not be done with this; it is mostly targeted at user-facing @@ -2086,6 +2158,122 @@ where } } +/// When encountered, report [ErrorKind::UnknownArgument][crate::error::ErrorKind::UnknownArgument] +/// +/// Useful to help users migrate, either from old versions or similar tools. +/// +/// # Examples +/// +/// ```rust +/// # use clap_builder as clap; +/// # use clap::Command; +/// # use clap::Arg; +/// let cmd = Command::new("mycmd") +/// .args([ +/// Arg::new("current-dir") +/// .short('C'), +/// Arg::new("current-dir-unknown") +/// .long("cwd") +/// .aliases(["current-dir", "directory", "working-directory", "root"]) +/// .value_parser(clap::builder::UnknownArgumentValueParser::suggest_arg("-C")) +/// .hide(true), +/// ]); +/// +/// // Use a supported version of the argument +/// let matches = cmd.clone().try_get_matches_from(["mycmd", "-C", ".."]).unwrap(); +/// assert!(matches.contains_id("current-dir")); +/// assert_eq!( +/// matches.get_many::<String>("current-dir").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(), +/// vec![".."] +/// ); +/// +/// // Use one of the invalid versions +/// let err = cmd.try_get_matches_from(["mycmd", "--cwd", ".."]).unwrap_err(); +/// assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument); +/// ``` +#[derive(Clone, Debug)] +pub struct UnknownArgumentValueParser { + arg: Option<Str>, + suggestions: Vec<StyledStr>, +} + +impl UnknownArgumentValueParser { + /// Suggest an alternative argument + pub fn suggest_arg(arg: impl Into<Str>) -> Self { + Self { + arg: Some(arg.into()), + suggestions: Default::default(), + } + } + + /// Provide a general suggestion + pub fn suggest(text: impl Into<StyledStr>) -> Self { + Self { + arg: Default::default(), + suggestions: vec![text.into()], + } + } + + /// Extend the suggestions + pub fn and_suggest(mut self, text: impl Into<StyledStr>) -> Self { + self.suggestions.push(text.into()); + self + } +} + +impl TypedValueParser for UnknownArgumentValueParser { + type Value = String; + + fn parse_ref( + &self, + cmd: &crate::Command, + arg: Option<&crate::Arg>, + value: &std::ffi::OsStr, + ) -> Result<Self::Value, crate::Error> { + TypedValueParser::parse_ref_(self, cmd, arg, value, ValueSource::CommandLine) + } + + fn parse_ref_( + &self, + cmd: &crate::Command, + arg: Option<&crate::Arg>, + _value: &std::ffi::OsStr, + source: ValueSource, + ) -> Result<Self::Value, crate::Error> { + match source { + ValueSource::DefaultValue => { + TypedValueParser::parse_ref_(&StringValueParser::new(), cmd, arg, _value, source) + } + ValueSource::EnvVariable | ValueSource::CommandLine => { + let arg = match arg { + Some(arg) => arg.to_string(), + None => "..".to_owned(), + }; + let err = crate::Error::unknown_argument( + cmd, + arg, + self.arg.as_ref().map(|s| (s.as_str().to_owned(), None)), + false, + crate::output::Usage::new(cmd).create_usage_with_title(&[]), + ); + #[cfg(feature = "error-context")] + let err = { + debug_assert_eq!( + err.get(crate::error::ContextKind::Suggested), + None, + "Assuming `Error::unknown_argument` doesn't apply any `Suggested` so we can without caution" + ); + err.insert_context_unchecked( + crate::error::ContextKind::Suggested, + crate::error::ContextValue::StyledStrs(self.suggestions.clone()), + ) + }; + Err(err) + } + } + } +} + /// Register a type with [value_parser!][crate::value_parser!] /// /// # Example diff --git a/vendor/clap_builder/src/derive.rs b/vendor/clap_builder/src/derive.rs index 71c0e8251..7494e8461 100644 --- a/vendor/clap_builder/src/derive.rs +++ b/vendor/clap_builder/src/derive.rs @@ -1,4 +1,4 @@ -//! This module contains traits that are usable with the `#[derive(...)].` +//! This module contains traits that are usable with the `#[derive(...)]` //! macros in `clap_derive`. use crate::builder::PossibleValue; diff --git a/vendor/clap_builder/src/error/mod.rs b/vendor/clap_builder/src/error/mod.rs index 772058a5f..af90e2756 100644 --- a/vendor/clap_builder/src/error/mod.rs +++ b/vendor/clap_builder/src/error/mod.rs @@ -718,7 +718,7 @@ impl<F: ErrorFormatter> Error<F> { let mut styled_suggestion = StyledStr::new(); let _ = write!( styled_suggestion, - "'{}{sub} --{flag}{}' exists", + "'{}{sub} {flag}{}' exists", valid.render(), valid.render_reset() ); @@ -727,7 +727,7 @@ impl<F: ErrorFormatter> Error<F> { Some((flag, None)) => { err = err.insert_context_unchecked( ContextKind::SuggestedArg, - ContextValue::String(format!("--{flag}")), + ContextValue::String(flag), ); } None => {} diff --git a/vendor/clap_builder/src/lib.rs b/vendor/clap_builder/src/lib.rs index 97c32c141..7d49d41df 100644 --- a/vendor/clap_builder/src/lib.rs +++ b/vendor/clap_builder/src/lib.rs @@ -48,13 +48,6 @@ pub type Error = crate::error::Error<crate::error::DefaultFormatter>; pub use crate::derive::{Args, CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum}; -#[doc(hidden)] -pub mod __macro_refs { - #[cfg(feature = "cargo")] - #[doc(hidden)] - pub use once_cell; -} - #[macro_use] #[allow(missing_docs)] mod macros; diff --git a/vendor/clap_builder/src/macros.rs b/vendor/clap_builder/src/macros.rs index 945cdaaab..767ea94bc 100644 --- a/vendor/clap_builder/src/macros.rs +++ b/vendor/clap_builder/src/macros.rs @@ -44,9 +44,9 @@ macro_rules! crate_authors { ($sep:expr) => {{ static authors: &str = env!("CARGO_PKG_AUTHORS"); if authors.contains(':') { - static CACHED: clap::__macro_refs::once_cell::sync::Lazy<String> = - clap::__macro_refs::once_cell::sync::Lazy::new(|| authors.replace(':', $sep)); - let s: &'static str = &*CACHED; + static CACHED: std::sync::OnceLock<String> = std::sync::OnceLock::new(); + let s = CACHED.get_or_init(|| authors.replace(':', $sep)); + let s: &'static str = &*s; s } else { authors diff --git a/vendor/clap_builder/src/mkeymap.rs b/vendor/clap_builder/src/mkeymap.rs index e9d6ab844..301c7bc56 100644 --- a/vendor/clap_builder/src/mkeymap.rs +++ b/vendor/clap_builder/src/mkeymap.rs @@ -123,6 +123,15 @@ impl MKeyMap { self.args.iter_mut() } + /// Mutate every argument. + pub(crate) fn mut_args<F>(&mut self, f: F) + where + F: FnMut(Arg) -> Arg, + { + let mut args = std::mem::take(&mut self.args); + self.args.extend(args.drain(..).map(f)); + } + /// We need a lazy build here since some we may change args after creating /// the map, you can checkout who uses `args_mut`. pub(crate) fn _build(&mut self) { diff --git a/vendor/clap_builder/src/output/help.rs b/vendor/clap_builder/src/output/help.rs index 410616eb1..a5073a9e4 100644 --- a/vendor/clap_builder/src/output/help.rs +++ b/vendor/clap_builder/src/output/help.rs @@ -30,8 +30,10 @@ pub(crate) fn write_help(writer: &mut StyledStr, cmd: &Command, usage: &Usage<'_ } } - // Remove any extra lines caused by book keeping - writer.trim(); + // Remove any lines from unused sections + writer.trim_start_lines(); + // Remove any whitespace caused by book keeping + writer.trim_end(); // Ensure there is still a trailing newline writer.push_str("\n"); } diff --git a/vendor/clap_builder/src/parser/matches/arg_matches.rs b/vendor/clap_builder/src/parser/matches/arg_matches.rs index 525904291..8390b0b58 100644 --- a/vendor/clap_builder/src/parser/matches/arg_matches.rs +++ b/vendor/clap_builder/src/parser/matches/arg_matches.rs @@ -237,7 +237,7 @@ impl ArgMatches { /// /// # Panics /// - /// If the argument definition and access mismatch. To handle this case programmatically, see + /// If the argument definition and access mismatch (debug builds). To handle this case programmatically, see /// [`ArgMatches::try_get_occurrences`]. /// /// # Examples @@ -490,7 +490,7 @@ impl ArgMatches { /// /// # Panics /// - /// If `id` is not a valid argument or group name. To handle this case programmatically, see + /// If `id` is not a valid argument or group name (debug builds). To handle this case programmatically, see /// [`ArgMatches::try_contains_id`]. /// /// # Examples @@ -570,7 +570,7 @@ impl ArgMatches { /// /// # Panics /// - /// If `id` is not a valid argument or group id. + /// If `id` is not a valid argument or group id (debug builds). /// /// # Examples /// @@ -617,7 +617,7 @@ impl ArgMatches { /// /// # Panics /// - /// If `id` is not a valid argument or group id. + /// If `id` is not a valid argument or group id (debug builds). /// /// # Examples /// @@ -765,7 +765,7 @@ impl ArgMatches { /// /// # Panics /// - /// If `id` is not a valid argument or group id. + /// If `id` is not a valid argument or group id (debug builds). /// /// # Examples /// @@ -969,7 +969,7 @@ impl ArgMatches { /// /// # Panics /// - /// If `id` is not a valid subcommand. + /// If `id` is not a valid subcommand (debug builds). /// /// # Examples /// diff --git a/vendor/clap_builder/src/parser/parser.rs b/vendor/clap_builder/src/parser/parser.rs index d6d8e8da4..fcde4a86e 100644 --- a/vendor/clap_builder/src/parser/parser.rs +++ b/vendor/clap_builder/src/parser/parser.rs @@ -421,7 +421,12 @@ impl<'cmd> Parser<'cmd> { sc_m.start_occurrence_of_external(self.cmd); for raw_val in raw_args.remaining(&mut args_cursor) { - let val = ok!(external_parser.parse_ref(self.cmd, None, raw_val)); + let val = ok!(external_parser.parse_ref( + self.cmd, + None, + raw_val, + ValueSource::CommandLine + )); let external_id = Id::from_static_ref(Id::EXTERNAL); sc_m.add_val_to(&external_id, val, raw_val.to_os_string()); } @@ -539,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::<Vec<_>>(); + 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 there is any ambiguity, fallback to non-infer subcommand - // search. + if let name @ Some(_) = iter.next() { + if iter.next().is_none() { + return name; + } + } } + // 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()); } @@ -563,28 +573,29 @@ impl<'cmd> Parser<'cmd> { fn possible_long_flag_subcommand(&self, arg: &str) -> Option<&str> { debug!("Parser::possible_long_flag_subcommand: arg={arg:?}"); if self.cmd.is_infer_subcommands_set() { - let options = self - .cmd - .get_subcommands() - .fold(Vec::new(), |mut options, sc| { - if let Some(long) = sc.get_long_flag() { - if long.starts_with(arg) { - options.push(long); - } - options.extend(sc.get_all_aliases().filter(|alias| alias.starts_with(arg))) + let mut iter = self.cmd.get_subcommands().filter_map(|sc| { + sc.get_long_flag().and_then(|long| { + if long.starts_with(arg) { + Some(sc.get_name()) + } else { + sc.get_all_long_flag_aliases().find_map(|alias| { + if alias.starts_with(arg) { + Some(sc.get_name()) + } else { + None + } + }) } - options - }); - if options.len() == 1 { - return Some(options[0]); - } + }) + }); - for sc in options { - if sc == arg { - return Some(sc); + if let name @ Some(_) = iter.next() { + if iter.next().is_none() { + return name; } } - } else if let Some(sc_name) = self.cmd.find_long_subcmd(arg) { + } + if let Some(sc_name) = self.cmd.find_long_subcmd(arg) { return Some(sc_name); } None @@ -1032,6 +1043,7 @@ impl<'cmd> Parser<'cmd> { &self, arg: &Arg, raw_vals: Vec<OsString>, + source: ValueSource, matcher: &mut ArgMatcher, ) -> ClapResult<()> { debug!("Parser::push_arg_values: {raw_vals:?}"); @@ -1044,7 +1056,7 @@ impl<'cmd> Parser<'cmd> { self.cur_idx.get() ); let value_parser = arg.get_value_parser(); - let val = ok!(value_parser.parse_ref(self.cmd, Some(arg), &raw_val)); + let val = ok!(value_parser.parse_ref(self.cmd, Some(arg), &raw_val, source)); matcher.add_val_to(arg.get_id(), val, raw_val); matcher.add_index_to(arg.get_id(), self.cur_idx.get()); @@ -1153,7 +1165,7 @@ impl<'cmd> Parser<'cmd> { )); } self.start_custom_arg(matcher, arg, source); - ok!(self.push_arg_values(arg, raw_vals, matcher)); + ok!(self.push_arg_values(arg, raw_vals, source, matcher)); if cfg!(debug_assertions) && matcher.needs_more_vals(arg) { debug!( "Parser::react not enough values passed in, leaving it to the validator to complain", @@ -1170,7 +1182,7 @@ impl<'cmd> Parser<'cmd> { debug!("Parser::react: cur_idx:={}", self.cur_idx.get()); } self.start_custom_arg(matcher, arg, source); - ok!(self.push_arg_values(arg, raw_vals, matcher)); + ok!(self.push_arg_values(arg, raw_vals, source, matcher)); if cfg!(debug_assertions) && matcher.needs_more_vals(arg) { debug!( "Parser::react not enough values passed in, leaving it to the validator to complain", @@ -1196,7 +1208,7 @@ impl<'cmd> Parser<'cmd> { )); } self.start_custom_arg(matcher, arg, source); - ok!(self.push_arg_values(arg, raw_vals, matcher)); + ok!(self.push_arg_values(arg, raw_vals, source, matcher)); Ok(ParseResult::ValuesDone) } ArgAction::SetFalse => { @@ -1217,7 +1229,7 @@ impl<'cmd> Parser<'cmd> { )); } self.start_custom_arg(matcher, arg, source); - ok!(self.push_arg_values(arg, raw_vals, matcher)); + ok!(self.push_arg_values(arg, raw_vals, source, matcher)); Ok(ParseResult::ValuesDone) } ArgAction::Count => { @@ -1233,7 +1245,7 @@ impl<'cmd> Parser<'cmd> { matcher.remove(arg.get_id()); self.start_custom_arg(matcher, arg, source); - ok!(self.push_arg_values(arg, raw_vals, matcher)); + ok!(self.push_arg_values(arg, raw_vals, source, matcher)); Ok(ParseResult::ValuesDone) } ArgAction::Help => { @@ -1521,6 +1533,7 @@ impl<'cmd> Parser<'cmd> { self.start_custom_arg(matcher, arg, ValueSource::CommandLine); } } + let did_you_mean = did_you_mean.map(|(arg, cmd)| (format!("--{arg}"), cmd)); let required = self.cmd.required_graph(); let used: Vec<Id> = matcher |