Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
418
vendor/clap_builder/src/builder/action.rs
vendored
Normal file
418
vendor/clap_builder/src/builder/action.rs
vendored
Normal file
@ -0,0 +1,418 @@
|
||||
#[cfg(debug_assertions)]
|
||||
use crate::util::AnyValueId;
|
||||
|
||||
/// Behavior of arguments when they are encountered while parsing
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("special-help")
|
||||
/// .short('?')
|
||||
/// .action(clap::ArgAction::Help)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_copy_implementations)] // In the future, we may accept `Box<dyn ...>`
|
||||
pub enum ArgAction {
|
||||
/// When encountered, store the associated value(s) in [`ArgMatches`][crate::ArgMatches]
|
||||
///
|
||||
/// **NOTE:** If the argument has previously been seen, it will result in a
|
||||
/// [`ArgumentConflict`][crate::error::ErrorKind::ArgumentConflict] unless
|
||||
/// [`Command::args_override_self(true)`][crate::Command::args_override_self] is set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::Set)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd", "--flag", "value"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_many::<String>("flag").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(),
|
||||
/// vec!["value"]
|
||||
/// );
|
||||
/// ```
|
||||
Set,
|
||||
/// When encountered, store the associated value(s) in [`ArgMatches`][crate::ArgMatches]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::Append)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd", "--flag", "value1", "--flag", "value2"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_many::<String>("flag").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(),
|
||||
/// vec!["value1", "value2"]
|
||||
/// );
|
||||
/// ```
|
||||
Append,
|
||||
/// When encountered, act as if `"true"` was encountered on the command-line
|
||||
///
|
||||
/// If no [`default_value`][super::Arg::default_value] is set, it will be `false`.
|
||||
///
|
||||
/// No value is allowed. To optionally accept a value, see
|
||||
/// [`Arg::default_missing_value`][super::Arg::default_missing_value]
|
||||
///
|
||||
/// **NOTE:** If the argument has previously been seen, it will result in a
|
||||
/// [`ArgumentConflict`][crate::error::ErrorKind::ArgumentConflict] unless
|
||||
/// [`Command::args_override_self(true)`][crate::Command::args_override_self] is set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::SetTrue)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_flag("flag"),
|
||||
/// true
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_flag("flag"),
|
||||
/// false
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// You can use [`TypedValueParser::map`][crate::builder::TypedValueParser::map] to have the
|
||||
/// flag control an application-specific type:
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// # use clap::builder::TypedValueParser as _;
|
||||
/// # use clap::builder::BoolishValueParser;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::SetTrue)
|
||||
/// .value_parser(
|
||||
/// BoolishValueParser::new()
|
||||
/// .map(|b| -> usize {
|
||||
/// if b { 10 } else { 5 }
|
||||
/// })
|
||||
/// )
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_one::<usize>("flag").copied(),
|
||||
/// Some(10)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_one::<usize>("flag").copied(),
|
||||
/// Some(5)
|
||||
/// );
|
||||
/// ```
|
||||
SetTrue,
|
||||
/// When encountered, act as if `"false"` was encountered on the command-line
|
||||
///
|
||||
/// If no [`default_value`][super::Arg::default_value] is set, it will be `true`.
|
||||
///
|
||||
/// No value is allowed. To optionally accept a value, see
|
||||
/// [`Arg::default_missing_value`][super::Arg::default_missing_value]
|
||||
///
|
||||
/// **NOTE:** If the argument has previously been seen, it will result in a
|
||||
/// [`ArgumentConflict`][crate::error::ErrorKind::ArgumentConflict] unless
|
||||
/// [`Command::args_override_self(true)`][crate::Command::args_override_self] is set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::SetFalse)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_flag("flag"),
|
||||
/// false
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_flag("flag"),
|
||||
/// true
|
||||
/// );
|
||||
/// ```
|
||||
SetFalse,
|
||||
/// When encountered, increment a `u8` counter
|
||||
///
|
||||
/// If no [`default_value`][super::Arg::default_value] is set, it will be `0`.
|
||||
///
|
||||
/// No value is allowed. To optionally accept a value, see
|
||||
/// [`Arg::default_missing_value`][super::Arg::default_missing_value]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::Count)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_count("flag"),
|
||||
/// 2
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_count("flag"),
|
||||
/// 0
|
||||
/// );
|
||||
/// ```
|
||||
Count,
|
||||
/// When encountered, display [`Command::print_help`][super::Command::print_help]
|
||||
///
|
||||
/// Depending on the flag, [`Command::print_long_help`][super::Command::print_long_help] may be shown
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("special-help")
|
||||
/// .short('?')
|
||||
/// .action(clap::ArgAction::Help)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
Help,
|
||||
/// When encountered, display [`Command::print_help`][super::Command::print_help]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("special-help")
|
||||
/// .short('?')
|
||||
/// .action(clap::ArgAction::HelpShort)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
HelpShort,
|
||||
/// When encountered, display [`Command::print_long_help`][super::Command::print_long_help]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("special-help")
|
||||
/// .short('?')
|
||||
/// .action(clap::ArgAction::HelpLong)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
HelpLong,
|
||||
/// When encountered, display [`Command::version`][super::Command::version]
|
||||
///
|
||||
/// Depending on the flag, [`Command::long_version`][super::Command::long_version] may be shown
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .version("1.0.0")
|
||||
/// .arg(
|
||||
/// Arg::new("special-version")
|
||||
/// .long("special-version")
|
||||
/// .action(clap::ArgAction::Version)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "--version"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayVersion);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "--special-version"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayVersion);
|
||||
/// ```
|
||||
Version,
|
||||
}
|
||||
|
||||
impl ArgAction {
|
||||
/// Returns whether this action accepts values on the command-line
|
||||
///
|
||||
/// [`default_values`][super::Arg::default_values] and [`env`][super::Arg::env] may still be
|
||||
/// processed.
|
||||
pub fn takes_values(&self) -> bool {
|
||||
match self {
|
||||
Self::Set => true,
|
||||
Self::Append => true,
|
||||
Self::SetTrue => false,
|
||||
Self::SetFalse => false,
|
||||
Self::Count => false,
|
||||
Self::Help => false,
|
||||
Self::HelpShort => false,
|
||||
Self::HelpLong => false,
|
||||
Self::Version => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default_value(&self) -> Option<&'static std::ffi::OsStr> {
|
||||
match self {
|
||||
Self::Set => None,
|
||||
Self::Append => None,
|
||||
Self::SetTrue => Some(std::ffi::OsStr::new("false")),
|
||||
Self::SetFalse => Some(std::ffi::OsStr::new("true")),
|
||||
Self::Count => Some(std::ffi::OsStr::new("0")),
|
||||
Self::Help => None,
|
||||
Self::HelpShort => None,
|
||||
Self::HelpLong => None,
|
||||
Self::Version => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default_missing_value(&self) -> Option<&'static std::ffi::OsStr> {
|
||||
match self {
|
||||
Self::Set => None,
|
||||
Self::Append => None,
|
||||
Self::SetTrue => Some(std::ffi::OsStr::new("true")),
|
||||
Self::SetFalse => Some(std::ffi::OsStr::new("false")),
|
||||
Self::Count => None,
|
||||
Self::Help => None,
|
||||
Self::HelpShort => None,
|
||||
Self::HelpLong => None,
|
||||
Self::Version => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default_value_parser(&self) -> Option<super::ValueParser> {
|
||||
match self {
|
||||
Self::Set => None,
|
||||
Self::Append => None,
|
||||
Self::SetTrue => Some(super::ValueParser::bool()),
|
||||
Self::SetFalse => Some(super::ValueParser::bool()),
|
||||
Self::Count => Some(crate::value_parser!(u8).into()),
|
||||
Self::Help => None,
|
||||
Self::HelpShort => None,
|
||||
Self::HelpLong => None,
|
||||
Self::Version => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) fn value_type_id(&self) -> Option<AnyValueId> {
|
||||
match self {
|
||||
Self::Set => None,
|
||||
Self::Append => None,
|
||||
Self::SetTrue => None,
|
||||
Self::SetFalse => None,
|
||||
Self::Count => Some(AnyValueId::of::<CountType>()),
|
||||
Self::Help => None,
|
||||
Self::HelpShort => None,
|
||||
Self::HelpLong => None,
|
||||
Self::Version => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type CountType = u8;
|
84
vendor/clap_builder/src/builder/app_settings.rs
vendored
Normal file
84
vendor/clap_builder/src/builder/app_settings.rs
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
#[allow(unused)]
|
||||
use crate::Arg;
|
||||
#[allow(unused)]
|
||||
use crate::Command;
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct AppFlags(u32);
|
||||
|
||||
impl AppFlags {
|
||||
pub(crate) fn set(&mut self, setting: AppSettings) {
|
||||
self.0 |= setting.bit();
|
||||
}
|
||||
|
||||
pub(crate) fn unset(&mut self, setting: AppSettings) {
|
||||
self.0 &= !setting.bit();
|
||||
}
|
||||
|
||||
pub(crate) fn is_set(&self, setting: AppSettings) -> bool {
|
||||
self.0 & setting.bit() != 0
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, other: Self) {
|
||||
self.0 |= other.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for AppFlags {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(mut self, rhs: Self) -> Self::Output {
|
||||
self.insert(rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Application level settings, which affect how [`Command`] operates
|
||||
///
|
||||
/// **NOTE:** When these settings are used, they apply only to current command, and are *not*
|
||||
/// propagated down or up through child or parent subcommands
|
||||
///
|
||||
/// [`Command`]: crate::Command
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub(crate) enum AppSettings {
|
||||
IgnoreErrors,
|
||||
AllowHyphenValues,
|
||||
AllowNegativeNumbers,
|
||||
AllArgsOverrideSelf,
|
||||
AllowMissingPositional,
|
||||
TrailingVarArg,
|
||||
DontDelimitTrailingValues,
|
||||
InferLongArgs,
|
||||
InferSubcommands,
|
||||
SubcommandRequired,
|
||||
AllowExternalSubcommands,
|
||||
Multicall,
|
||||
SubcommandsNegateReqs,
|
||||
ArgsNegateSubcommands,
|
||||
SubcommandPrecedenceOverArg,
|
||||
FlattenHelp,
|
||||
ArgRequiredElseHelp,
|
||||
NextLineHelp,
|
||||
DisableColoredHelp,
|
||||
DisableHelpFlag,
|
||||
DisableHelpSubcommand,
|
||||
DisableVersionFlag,
|
||||
PropagateVersion,
|
||||
Hidden,
|
||||
HidePossibleValues,
|
||||
HelpExpected,
|
||||
NoBinaryName,
|
||||
#[allow(dead_code)]
|
||||
ColorAuto,
|
||||
ColorAlways,
|
||||
ColorNever,
|
||||
Built,
|
||||
BinNameBuilt,
|
||||
}
|
||||
|
||||
impl AppSettings {
|
||||
fn bit(self) -> u32 {
|
||||
1 << (self as u8)
|
||||
}
|
||||
}
|
4800
vendor/clap_builder/src/builder/arg.rs
vendored
Normal file
4800
vendor/clap_builder/src/builder/arg.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
611
vendor/clap_builder/src/builder/arg_group.rs
vendored
Normal file
611
vendor/clap_builder/src/builder/arg_group.rs
vendored
Normal file
@ -0,0 +1,611 @@
|
||||
// Internal
|
||||
use crate::builder::IntoResettable;
|
||||
use crate::util::Id;
|
||||
|
||||
/// Family of related [arguments].
|
||||
///
|
||||
/// By placing arguments in a logical group, you can create easier requirement and
|
||||
/// exclusion rules instead of having to list each argument individually, or when you want a rule
|
||||
/// to apply "any but not all" arguments.
|
||||
///
|
||||
/// For instance, you can make an entire `ArgGroup` required. If [`ArgGroup::multiple(true)`] is
|
||||
/// set, this means that at least one argument from that group must be present. If
|
||||
/// [`ArgGroup::multiple(false)`] is set (the default), one and *only* one must be present.
|
||||
///
|
||||
/// You can also do things such as name an entire `ArgGroup` as a [conflict] or [requirement] for
|
||||
/// another argument, meaning any of the arguments that belong to that group will cause a failure
|
||||
/// if present, or must be present respectively.
|
||||
///
|
||||
/// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
|
||||
/// present out of a given set. Imagine that you had multiple arguments, and you want one of them
|
||||
/// to be required, but making all of them required isn't feasible because perhaps they conflict
|
||||
/// with each other. For example, lets say that you were building an application where one could
|
||||
/// set a given version number by supplying a string with an option argument, i.e.
|
||||
/// `--set-ver v1.2.3`, you also wanted to support automatically using a previous version number
|
||||
/// and simply incrementing one of the three numbers. So you create three flags `--major`,
|
||||
/// `--minor`, and `--patch`. All of these arguments shouldn't be used at one time but you want to
|
||||
/// specify that *at least one* of them is used. For this, you can create a group.
|
||||
///
|
||||
/// Finally, you may use `ArgGroup`s to pull a value from a group of arguments when you don't care
|
||||
/// exactly which argument was actually used at runtime.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The following example demonstrates using an `ArgGroup` to ensure that one, and only one, of
|
||||
/// the arguments from the specified group is present at runtime.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, arg, ArgGroup, error::ErrorKind};
|
||||
/// let result = Command::new("cmd")
|
||||
/// .arg(arg!(--"set-ver" <ver> "set the version manually"))
|
||||
/// .arg(arg!(--major "auto increase major"))
|
||||
/// .arg(arg!(--minor "auto increase minor"))
|
||||
/// .arg(arg!(--patch "auto increase patch"))
|
||||
/// .group(ArgGroup::new("vers")
|
||||
/// .args(["set-ver", "major", "minor", "patch"])
|
||||
/// .required(true))
|
||||
/// .try_get_matches_from(vec!["cmd", "--major", "--patch"]);
|
||||
/// // Because we used two args in the group it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
///
|
||||
/// This next example shows a passing parse of the same scenario
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, arg, ArgGroup, Id};
|
||||
/// let result = Command::new("cmd")
|
||||
/// .arg(arg!(--"set-ver" <ver> "set the version manually"))
|
||||
/// .arg(arg!(--major "auto increase major"))
|
||||
/// .arg(arg!(--minor "auto increase minor"))
|
||||
/// .arg(arg!(--patch "auto increase patch"))
|
||||
/// .group(ArgGroup::new("vers")
|
||||
/// .args(["set-ver", "major", "minor","patch"])
|
||||
/// .required(true))
|
||||
/// .try_get_matches_from(vec!["cmd", "--major"]);
|
||||
/// assert!(result.is_ok());
|
||||
/// let matches = result.unwrap();
|
||||
/// // We may not know which of the args was used, so we can test for the group...
|
||||
/// assert!(matches.contains_id("vers"));
|
||||
/// // We can also ask the group which arg was used
|
||||
/// assert_eq!(matches
|
||||
/// .get_one::<Id>("vers")
|
||||
/// .expect("`vers` is required")
|
||||
/// .as_str(),
|
||||
/// "major"
|
||||
/// );
|
||||
/// // we could also alternatively check each arg individually (not shown here)
|
||||
/// ```
|
||||
/// [`ArgGroup::multiple(true)`]: ArgGroup::multiple()
|
||||
///
|
||||
/// [`ArgGroup::multiple(false)`]: ArgGroup::multiple()
|
||||
/// [arguments]: crate::Arg
|
||||
/// [conflict]: crate::Arg::conflicts_with()
|
||||
/// [requirement]: crate::Arg::requires()
|
||||
#[derive(Default, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ArgGroup {
|
||||
pub(crate) id: Id,
|
||||
pub(crate) args: Vec<Id>,
|
||||
pub(crate) required: bool,
|
||||
pub(crate) requires: Vec<Id>,
|
||||
pub(crate) conflicts: Vec<Id>,
|
||||
pub(crate) multiple: bool,
|
||||
}
|
||||
|
||||
/// # Builder
|
||||
impl ArgGroup {
|
||||
/// Create a `ArgGroup` using a unique name.
|
||||
///
|
||||
/// The name will be used to get values from the group or refer to the group inside of conflict
|
||||
/// and requirement rules.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ArgGroup};
|
||||
/// ArgGroup::new("config")
|
||||
/// # ;
|
||||
/// ```
|
||||
pub fn new(id: impl Into<Id>) -> Self {
|
||||
ArgGroup::default().id(id)
|
||||
}
|
||||
|
||||
/// Sets the group name.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ArgGroup};
|
||||
/// ArgGroup::default().id("config")
|
||||
/// # ;
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn id(mut self, id: impl Into<Id>) -> Self {
|
||||
self.id = id.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds an [argument] to this group by name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, ArgAction};
|
||||
/// let m = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .arg("flag")
|
||||
/// .arg("color"))
|
||||
/// .get_matches_from(vec!["myprog", "-f"]);
|
||||
/// // maybe we don't know which of the two flags was used...
|
||||
/// assert!(m.contains_id("req_flags"));
|
||||
/// // but we can also check individually if needed
|
||||
/// assert!(m.contains_id("flag"));
|
||||
/// ```
|
||||
/// [argument]: crate::Arg
|
||||
#[must_use]
|
||||
pub fn arg(mut self, arg_id: impl IntoResettable<Id>) -> Self {
|
||||
if let Some(arg_id) = arg_id.into_resettable().into_option() {
|
||||
self.args.push(arg_id);
|
||||
} else {
|
||||
self.args.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds multiple [arguments] to this group by name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, ArgAction};
|
||||
/// let m = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"]))
|
||||
/// .get_matches_from(vec!["myprog", "-f"]);
|
||||
/// // maybe we don't know which of the two flags was used...
|
||||
/// assert!(m.contains_id("req_flags"));
|
||||
/// // but we can also check individually if needed
|
||||
/// assert!(m.contains_id("flag"));
|
||||
/// ```
|
||||
/// [arguments]: crate::Arg
|
||||
#[must_use]
|
||||
pub fn args(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self {
|
||||
for n in ns {
|
||||
self = self.arg(n);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Getters for all args. It will return a vector of `Id`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{ArgGroup};
|
||||
/// let args: Vec<&str> = vec!["a1".into(), "a4".into()];
|
||||
/// let grp = ArgGroup::new("program").args(&args);
|
||||
///
|
||||
/// for (pos, arg) in grp.get_args().enumerate() {
|
||||
/// assert_eq!(*arg, args[pos]);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_args(&self) -> impl Iterator<Item = &Id> {
|
||||
self.args.iter()
|
||||
}
|
||||
|
||||
/// Allows more than one of the [`Arg`]s in this group to be used. (Default: `false`)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Notice in this example we use *both* the `-f` and `-c` flags which are both part of the
|
||||
/// group
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, ArgAction};
|
||||
/// let m = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .multiple(true))
|
||||
/// .get_matches_from(vec!["myprog", "-f", "-c"]);
|
||||
/// // maybe we don't know which of the two flags was used...
|
||||
/// assert!(m.contains_id("req_flags"));
|
||||
/// ```
|
||||
/// In this next example, we show the default behavior (i.e. `multiple(false)) which will throw
|
||||
/// an error if more than one of the args in the group was used.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"]))
|
||||
/// .try_get_matches_from(vec!["myprog", "-f", "-c"]);
|
||||
/// // Because we used both args in the group it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
///
|
||||
/// [`Arg`]: crate::Arg
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn multiple(mut self, yes: bool) -> Self {
|
||||
self.multiple = yes;
|
||||
self
|
||||
}
|
||||
|
||||
/// Return true if the group allows more than one of the arguments
|
||||
/// in this group to be used. (Default: `false`)
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{ArgGroup};
|
||||
/// let mut group = ArgGroup::new("myprog")
|
||||
/// .args(["f", "c"])
|
||||
/// .multiple(true);
|
||||
///
|
||||
/// assert!(group.is_multiple());
|
||||
/// ```
|
||||
pub fn is_multiple(&mut self) -> bool {
|
||||
self.multiple
|
||||
}
|
||||
|
||||
/// Require an argument from the group to be present when parsing.
|
||||
///
|
||||
/// This is unless conflicting with another argument. A required group will be displayed in
|
||||
/// the usage string of the application in the format `<arg|arg2|arg3>`.
|
||||
///
|
||||
/// **NOTE:** This setting only applies to the current [`Command`] / [`Subcommand`]s, and not
|
||||
/// globally.
|
||||
///
|
||||
/// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with
|
||||
/// `ArgGroup::required(true)` states, "One and *only one* arg must be used from this group.
|
||||
/// Use of more than one arg is an error." Vice setting `ArgGroup::multiple(true)` which
|
||||
/// states, '*At least* one arg from this group must be used. Using multiple is OK."
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .required(true))
|
||||
/// .try_get_matches_from(vec!["myprog"]);
|
||||
/// // Because we didn't use any of the args in the group, it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
|
||||
/// ```
|
||||
///
|
||||
/// [`Subcommand`]: crate::Subcommand
|
||||
/// [`ArgGroup::multiple`]: ArgGroup::multiple()
|
||||
/// [`Command`]: crate::Command
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn required(mut self, yes: bool) -> Self {
|
||||
self.required = yes;
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify an argument or group that must be present when this group is.
|
||||
///
|
||||
/// This is not to be confused with a [required group]. Requirement rules function just like
|
||||
/// [argument requirement rules], you can name other arguments or groups that must be present
|
||||
/// when any one of the arguments from this group is used.
|
||||
///
|
||||
/// **NOTE:** The name provided may be an argument or group name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .short('d')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .requires("debug"))
|
||||
/// .try_get_matches_from(vec!["myprog", "-c"]);
|
||||
/// // because we used an arg from the group, and the group requires "-d" to be used, it's an
|
||||
/// // error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
|
||||
/// ```
|
||||
/// [required group]: ArgGroup::required()
|
||||
/// [argument requirement rules]: crate::Arg::requires()
|
||||
#[must_use]
|
||||
pub fn requires(mut self, id: impl IntoResettable<Id>) -> Self {
|
||||
if let Some(id) = id.into_resettable().into_option() {
|
||||
self.requires.push(id);
|
||||
} else {
|
||||
self.requires.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify arguments or groups that must be present when this group is.
|
||||
///
|
||||
/// This is not to be confused with a [required group]. Requirement rules function just like
|
||||
/// [argument requirement rules], you can name other arguments or groups that must be present
|
||||
/// when one of the arguments from this group is used.
|
||||
///
|
||||
/// **NOTE:** The names provided may be an argument or group name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .short('d')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("verb")
|
||||
/// .short('v')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .requires_all(["debug", "verb"]))
|
||||
/// .try_get_matches_from(vec!["myprog", "-c", "-d"]);
|
||||
/// // because we used an arg from the group, and the group requires "-d" and "-v" to be used,
|
||||
/// // yet we only used "-d" it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
|
||||
/// ```
|
||||
/// [required group]: ArgGroup::required()
|
||||
/// [argument requirement rules]: crate::Arg::requires_ifs()
|
||||
#[must_use]
|
||||
pub fn requires_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self {
|
||||
for n in ns {
|
||||
self = self.requires(n);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify an argument or group that must **not** be present when this group is.
|
||||
///
|
||||
/// Exclusion (aka conflict) rules function just like [argument exclusion rules], you can name
|
||||
/// other arguments or groups that must *not* be present when one of the arguments from this
|
||||
/// group are used.
|
||||
///
|
||||
/// **NOTE:** The name provided may be an argument, or group name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .short('d')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .conflicts_with("debug"))
|
||||
/// .try_get_matches_from(vec!["myprog", "-c", "-d"]);
|
||||
/// // because we used an arg from the group, and the group conflicts with "-d", it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
/// [argument exclusion rules]: crate::Arg::conflicts_with()
|
||||
#[must_use]
|
||||
pub fn conflicts_with(mut self, id: impl IntoResettable<Id>) -> Self {
|
||||
if let Some(id) = id.into_resettable().into_option() {
|
||||
self.conflicts.push(id);
|
||||
} else {
|
||||
self.conflicts.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify arguments or groups that must **not** be present when this group is.
|
||||
///
|
||||
/// Exclusion rules function just like [argument exclusion rules], you can name other arguments
|
||||
/// or groups that must *not* be present when one of the arguments from this group are used.
|
||||
///
|
||||
/// **NOTE:** The names provided may be an argument, or group name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .short('d')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("verb")
|
||||
/// .short('v')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .conflicts_with_all(["debug", "verb"]))
|
||||
/// .try_get_matches_from(vec!["myprog", "-c", "-v"]);
|
||||
/// // because we used an arg from the group, and the group conflicts with either "-v" or "-d"
|
||||
/// // it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
///
|
||||
/// [argument exclusion rules]: crate::Arg::conflicts_with_all()
|
||||
#[must_use]
|
||||
pub fn conflicts_with_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self {
|
||||
for n in ns {
|
||||
self = self.conflicts_with(n);
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// # Reflection
|
||||
impl ArgGroup {
|
||||
/// Get the name of the group
|
||||
#[inline]
|
||||
pub fn get_id(&self) -> &Id {
|
||||
&self.id
|
||||
}
|
||||
|
||||
/// Reports whether [`ArgGroup::required`] is set
|
||||
#[inline]
|
||||
pub fn is_required_set(&self) -> bool {
|
||||
self.required
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ ArgGroup> for ArgGroup {
|
||||
fn from(g: &ArgGroup) -> Self {
|
||||
g.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn groups() {
|
||||
let g = ArgGroup::new("test")
|
||||
.arg("a1")
|
||||
.arg("a4")
|
||||
.args(["a2", "a3"])
|
||||
.required(true)
|
||||
.conflicts_with("c1")
|
||||
.conflicts_with_all(["c2", "c3"])
|
||||
.conflicts_with("c4")
|
||||
.requires("r1")
|
||||
.requires_all(["r2", "r3"])
|
||||
.requires("r4");
|
||||
|
||||
let args: Vec<Id> = vec!["a1".into(), "a4".into(), "a2".into(), "a3".into()];
|
||||
let reqs: Vec<Id> = vec!["r1".into(), "r2".into(), "r3".into(), "r4".into()];
|
||||
let confs: Vec<Id> = vec!["c1".into(), "c2".into(), "c3".into(), "c4".into()];
|
||||
|
||||
assert_eq!(g.args, args);
|
||||
assert_eq!(g.requires, reqs);
|
||||
assert_eq!(g.conflicts, confs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from() {
|
||||
let g = ArgGroup::new("test")
|
||||
.arg("a1")
|
||||
.arg("a4")
|
||||
.args(["a2", "a3"])
|
||||
.required(true)
|
||||
.conflicts_with("c1")
|
||||
.conflicts_with_all(["c2", "c3"])
|
||||
.conflicts_with("c4")
|
||||
.requires("r1")
|
||||
.requires_all(["r2", "r3"])
|
||||
.requires("r4");
|
||||
|
||||
let args: Vec<Id> = vec!["a1".into(), "a4".into(), "a2".into(), "a3".into()];
|
||||
let reqs: Vec<Id> = vec!["r1".into(), "r2".into(), "r3".into(), "r4".into()];
|
||||
let confs: Vec<Id> = vec!["c1".into(), "c2".into(), "c3".into(), "c4".into()];
|
||||
|
||||
let g2 = ArgGroup::from(&g);
|
||||
assert_eq!(g2.args, args);
|
||||
assert_eq!(g2.requires, reqs);
|
||||
assert_eq!(g2.conflicts, confs);
|
||||
}
|
||||
|
||||
// This test will *fail to compile* if ArgGroup is not Send + Sync
|
||||
#[test]
|
||||
fn arg_group_send_sync() {
|
||||
fn foo<T: Send + Sync>(_: T) {}
|
||||
foo(ArgGroup::new("test"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arg_group_expose_is_multiple_helper() {
|
||||
let args: Vec<Id> = vec!["a1".into(), "a4".into()];
|
||||
|
||||
let mut grp_multiple = ArgGroup::new("test_multiple").args(&args).multiple(true);
|
||||
assert!(grp_multiple.is_multiple());
|
||||
|
||||
let mut grp_not_multiple = ArgGroup::new("test_multiple").args(&args).multiple(false);
|
||||
assert!(!grp_not_multiple.is_multiple());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arg_group_expose_get_args_helper() {
|
||||
let args: Vec<Id> = vec!["a1".into(), "a4".into()];
|
||||
let grp = ArgGroup::new("program").args(&args);
|
||||
|
||||
for (pos, arg) in grp.get_args().enumerate() {
|
||||
assert_eq!(*arg, args[pos]);
|
||||
}
|
||||
}
|
||||
}
|
19
vendor/clap_builder/src/builder/arg_predicate.rs
vendored
Normal file
19
vendor/clap_builder/src/builder/arg_predicate.rs
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
use crate::builder::OsStr;
|
||||
|
||||
/// Operations to perform on argument values
|
||||
///
|
||||
/// These do not apply to [`ValueSource::DefaultValue`][crate::parser::ValueSource::DefaultValue]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "unstable-v5", non_exhaustive)]
|
||||
pub enum ArgPredicate {
|
||||
/// Is the argument present?
|
||||
IsPresent,
|
||||
/// Does the argument match the specified value?
|
||||
Equals(OsStr),
|
||||
}
|
||||
|
||||
impl<S: Into<OsStr>> From<S> for ArgPredicate {
|
||||
fn from(other: S) -> Self {
|
||||
Self::Equals(other.into())
|
||||
}
|
||||
}
|
91
vendor/clap_builder/src/builder/arg_settings.rs
vendored
Normal file
91
vendor/clap_builder/src/builder/arg_settings.rs
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
#[allow(unused)]
|
||||
use crate::Arg;
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct ArgFlags(u32);
|
||||
|
||||
impl ArgFlags {
|
||||
pub(crate) fn set(&mut self, setting: ArgSettings) {
|
||||
self.0 |= setting.bit();
|
||||
}
|
||||
|
||||
pub(crate) fn unset(&mut self, setting: ArgSettings) {
|
||||
self.0 &= !setting.bit();
|
||||
}
|
||||
|
||||
pub(crate) fn is_set(&self, setting: ArgSettings) -> bool {
|
||||
self.0 & setting.bit() != 0
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, other: Self) {
|
||||
self.0 |= other.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for ArgFlags {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(mut self, rhs: Self) -> Self::Output {
|
||||
self.insert(rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Various settings that apply to arguments and may be set, unset, and checked via getter/setter
|
||||
/// methods [`Arg::setting`], [`Arg::unset_setting`], and [`Arg::is_set`]. This is what the
|
||||
/// [`Arg`] methods which accept a `bool` use internally.
|
||||
///
|
||||
/// [`Arg`]: crate::Arg
|
||||
/// [`Arg::setting`]: crate::Arg::setting()
|
||||
/// [`Arg::unset_setting`]: crate::Arg::unset_setting()
|
||||
/// [`Arg::is_set`]: crate::Arg::is_set()
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub(crate) enum ArgSettings {
|
||||
Required,
|
||||
Global,
|
||||
Hidden,
|
||||
NextLineHelp,
|
||||
HidePossibleValues,
|
||||
AllowHyphenValues,
|
||||
AllowNegativeNumbers,
|
||||
RequireEquals,
|
||||
Last,
|
||||
TrailingVarArg,
|
||||
HideDefaultValue,
|
||||
IgnoreCase,
|
||||
#[cfg(feature = "env")]
|
||||
HideEnv,
|
||||
#[cfg(feature = "env")]
|
||||
HideEnvValues,
|
||||
HiddenShortHelp,
|
||||
HiddenLongHelp,
|
||||
Exclusive,
|
||||
}
|
||||
|
||||
impl ArgSettings {
|
||||
fn bit(self) -> u32 {
|
||||
1 << (self as u8)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::Arg;
|
||||
|
||||
#[test]
|
||||
fn setting() {
|
||||
let m = Arg::new("setting").setting(ArgSettings::Required);
|
||||
assert!(m.is_required_set());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unset_setting() {
|
||||
let m = Arg::new("unset_setting").setting(ArgSettings::Required);
|
||||
assert!(m.is_required_set());
|
||||
|
||||
let m = m.unset_setting(ArgSettings::Required);
|
||||
assert!(!m.is_required_set(), "{m:#?}");
|
||||
}
|
||||
}
|
4916
vendor/clap_builder/src/builder/command.rs
vendored
Normal file
4916
vendor/clap_builder/src/builder/command.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
840
vendor/clap_builder/src/builder/debug_asserts.rs
vendored
Normal file
840
vendor/clap_builder/src/builder/debug_asserts.rs
vendored
Normal file
@ -0,0 +1,840 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::builder::ValueRange;
|
||||
use crate::mkeymap::KeyType;
|
||||
use crate::util::FlatSet;
|
||||
use crate::util::Id;
|
||||
use crate::ArgAction;
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
use crate::{Arg, Command, ValueHint};
|
||||
|
||||
pub(crate) fn assert_app(cmd: &Command) {
|
||||
debug!("Command::_debug_asserts");
|
||||
|
||||
let mut short_flags = vec![];
|
||||
let mut long_flags = vec![];
|
||||
|
||||
// Invalid version flag settings
|
||||
if cmd.get_version().is_none() && cmd.get_long_version().is_none() {
|
||||
// PropagateVersion is meaningless if there is no version
|
||||
assert!(
|
||||
!cmd.is_propagate_version_set(),
|
||||
"Command {}: No version information via Command::version or Command::long_version to propagate",
|
||||
cmd.get_name(),
|
||||
);
|
||||
|
||||
// Used `Command::mut_arg("version", ..) but did not provide any version information to display
|
||||
let version_needed = cmd
|
||||
.get_arguments()
|
||||
.filter(|x| matches!(x.get_action(), ArgAction::Version))
|
||||
.map(|x| x.get_id())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(version_needed, Vec::<&str>::new(), "Command {}: `ArgAction::Version` used without providing Command::version or Command::long_version"
|
||||
,cmd.get_name()
|
||||
);
|
||||
}
|
||||
|
||||
for sc in cmd.get_subcommands() {
|
||||
if let Some(s) = sc.get_short_flag().as_ref() {
|
||||
short_flags.push(Flag::Command(format!("-{s}"), sc.get_name()));
|
||||
}
|
||||
|
||||
for short_alias in sc.get_all_short_flag_aliases() {
|
||||
short_flags.push(Flag::Command(format!("-{short_alias}"), sc.get_name()));
|
||||
}
|
||||
|
||||
if let Some(l) = sc.get_long_flag().as_ref() {
|
||||
assert!(!l.starts_with('-'), "Command {}: long_flag {:?} must not start with a `-`, that will be handled by the parser", sc.get_name(), l);
|
||||
long_flags.push(Flag::Command(format!("--{l}"), sc.get_name()));
|
||||
}
|
||||
|
||||
for long_alias in sc.get_all_long_flag_aliases() {
|
||||
long_flags.push(Flag::Command(format!("--{long_alias}"), sc.get_name()));
|
||||
}
|
||||
}
|
||||
|
||||
for arg in cmd.get_arguments() {
|
||||
assert_arg(arg);
|
||||
|
||||
assert!(
|
||||
!cmd.is_multicall_set(),
|
||||
"Command {}: Arguments like {} cannot be set on a multicall command",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
if let Some(s) = arg.get_short() {
|
||||
short_flags.push(Flag::Arg(format!("-{s}"), arg.get_id().as_str()));
|
||||
}
|
||||
|
||||
for (short_alias, _) in &arg.short_aliases {
|
||||
short_flags.push(Flag::Arg(format!("-{short_alias}"), arg.get_id().as_str()));
|
||||
}
|
||||
|
||||
if let Some(l) = arg.get_long() {
|
||||
assert!(!l.starts_with('-'), "Argument {}: long {:?} must not start with a `-`, that will be handled by the parser", arg.get_id(), l);
|
||||
long_flags.push(Flag::Arg(format!("--{l}"), arg.get_id().as_str()));
|
||||
}
|
||||
|
||||
for (long_alias, _) in &arg.aliases {
|
||||
long_flags.push(Flag::Arg(format!("--{long_alias}"), arg.get_id().as_str()));
|
||||
}
|
||||
|
||||
// Name conflicts
|
||||
if let Some((first, second)) = cmd.two_args_of(|x| x.get_id() == arg.get_id()) {
|
||||
panic!(
|
||||
"Command {}: Argument names must be unique, but '{}' is in use by more than one argument or group{}",
|
||||
cmd.get_name(),
|
||||
arg.get_id(),
|
||||
duplicate_tip(cmd, first, second),
|
||||
);
|
||||
}
|
||||
|
||||
// Long conflicts
|
||||
if let Some(l) = arg.get_long() {
|
||||
if let Some((first, second)) = cmd.two_args_of(|x| x.get_long() == Some(l)) {
|
||||
panic!(
|
||||
"Command {}: Long option names must be unique for each argument, \
|
||||
but '--{}' is in use by both '{}' and '{}'{}",
|
||||
cmd.get_name(),
|
||||
l,
|
||||
first.get_id(),
|
||||
second.get_id(),
|
||||
duplicate_tip(cmd, first, second)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Short conflicts
|
||||
if let Some(s) = arg.get_short() {
|
||||
if let Some((first, second)) = cmd.two_args_of(|x| x.get_short() == Some(s)) {
|
||||
panic!(
|
||||
"Command {}: Short option names must be unique for each argument, \
|
||||
but '-{}' is in use by both '{}' and '{}'{}",
|
||||
cmd.get_name(),
|
||||
s,
|
||||
first.get_id(),
|
||||
second.get_id(),
|
||||
duplicate_tip(cmd, first, second),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Index conflicts
|
||||
if let Some(idx) = arg.index {
|
||||
if let Some((first, second)) =
|
||||
cmd.two_args_of(|x| x.is_positional() && x.get_index() == Some(idx))
|
||||
{
|
||||
panic!(
|
||||
"Command {}: Argument '{}' has the same index as '{}' \
|
||||
and they are both positional arguments\n\n\t \
|
||||
Use `Arg::num_args(1..)` to allow one \
|
||||
positional argument to take multiple values",
|
||||
cmd.get_name(),
|
||||
first.get_id(),
|
||||
second.get_id()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// requires, r_if, r_unless
|
||||
for req in &arg.requires {
|
||||
assert!(
|
||||
cmd.id_exists(&req.1),
|
||||
"Command {}: Argument or group '{}' specified in 'requires*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req.1,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
for req in &arg.r_ifs {
|
||||
assert!(
|
||||
!arg.is_required_set(),
|
||||
"Argument {}: `required` conflicts with `required_if_eq*`",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
cmd.id_exists(&req.0),
|
||||
"Command {}: Argument or group '{}' specified in 'required_if_eq*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req.0,
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
|
||||
for req in &arg.r_ifs_all {
|
||||
assert!(
|
||||
!arg.is_required_set(),
|
||||
"Argument {}: `required` conflicts with `required_if_eq_all`",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
cmd.id_exists(&req.0),
|
||||
"Command {}: Argument or group '{}' specified in 'required_if_eq_all' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req.0,
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
|
||||
for req in &arg.r_unless {
|
||||
assert!(
|
||||
!arg.is_required_set(),
|
||||
"Argument {}: `required` conflicts with `required_unless*`",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
cmd.id_exists(req),
|
||||
"Command {}: Argument or group '{}' specified in 'required_unless*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
for req in &arg.r_unless_all {
|
||||
assert!(
|
||||
!arg.is_required_set(),
|
||||
"Argument {}: `required` conflicts with `required_unless*`",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
cmd.id_exists(req),
|
||||
"Command {}: Argument or group '{}' specified in 'required_unless*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
// blacklist
|
||||
for req in &arg.blacklist {
|
||||
assert!(
|
||||
cmd.id_exists(req),
|
||||
"Command {}: Argument or group '{}' specified in 'conflicts_with*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
// overrides
|
||||
for req in &arg.overrides {
|
||||
assert!(
|
||||
cmd.id_exists(req),
|
||||
"Command {}: Argument or group '{}' specified in 'overrides_with*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
if arg.is_last_set() {
|
||||
assert!(
|
||||
arg.get_long().is_none(),
|
||||
"Command {}: Flags or Options cannot have last(true) set. '{}' has both a long and last(true) set.",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
arg.get_short().is_none(),
|
||||
"Command {}: Flags or Options cannot have last(true) set. '{}' has both a short and last(true) set.",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
|
||||
assert!(
|
||||
!(arg.is_required_set() && arg.is_global_set()),
|
||||
"Command {}: Global arguments cannot be required.\n\n\t'{}' is marked as both global and required",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
if arg.get_value_hint() == ValueHint::CommandWithArguments {
|
||||
assert!(
|
||||
arg.is_positional(),
|
||||
"Command {}: Argument '{}' has hint CommandWithArguments and must be positional.",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
assert!(
|
||||
arg.is_trailing_var_arg_set() || arg.is_last_set(),
|
||||
"Command {}: Positional argument '{}' has hint CommandWithArguments, so Command must have `trailing_var_arg(true)` or `last(true)` set.",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for group in cmd.get_groups() {
|
||||
// Name conflicts
|
||||
assert!(
|
||||
cmd.get_groups().filter(|x| x.id == group.id).count() < 2,
|
||||
"Command {}: Argument group name must be unique\n\n\t'{}' is already in use",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
);
|
||||
|
||||
// Groups should not have naming conflicts with Args
|
||||
assert!(
|
||||
!cmd.get_arguments().any(|x| x.get_id() == group.get_id()),
|
||||
"Command {}: Argument group name '{}' must not conflict with argument name",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
);
|
||||
|
||||
for arg in &group.args {
|
||||
// Args listed inside groups should exist
|
||||
assert!(
|
||||
cmd.get_arguments().any(|x| x.get_id() == arg),
|
||||
"Command {}: Argument group '{}' contains non-existent argument '{}'",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
arg
|
||||
);
|
||||
}
|
||||
|
||||
for arg in &group.requires {
|
||||
// Args listed inside groups should exist
|
||||
assert!(
|
||||
cmd.id_exists(arg),
|
||||
"Command {}: Argument group '{}' requires non-existent '{}' id",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
arg
|
||||
);
|
||||
}
|
||||
|
||||
for arg in &group.conflicts {
|
||||
// Args listed inside groups should exist
|
||||
assert!(
|
||||
cmd.id_exists(arg),
|
||||
"Command {}: Argument group '{}' conflicts with non-existent '{}' id",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
arg
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Conflicts between flags and subcommands
|
||||
|
||||
long_flags.sort_unstable();
|
||||
short_flags.sort_unstable();
|
||||
|
||||
detect_duplicate_flags(&long_flags, "long");
|
||||
detect_duplicate_flags(&short_flags, "short");
|
||||
|
||||
let mut subs = FlatSet::new();
|
||||
for sc in cmd.get_subcommands() {
|
||||
assert!(
|
||||
subs.insert(sc.get_name()),
|
||||
"Command {}: command name `{}` is duplicated",
|
||||
cmd.get_name(),
|
||||
sc.get_name()
|
||||
);
|
||||
for alias in sc.get_all_aliases() {
|
||||
assert!(
|
||||
subs.insert(alias),
|
||||
"Command {}: command `{}` alias `{}` is duplicated",
|
||||
cmd.get_name(),
|
||||
sc.get_name(),
|
||||
alias
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_verify_positionals(cmd);
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
if let Some(help_template) = cmd.get_help_template() {
|
||||
assert!(
|
||||
!help_template.to_string().contains("{flags}"),
|
||||
"Command {}: {}",
|
||||
cmd.get_name(),
|
||||
"`{flags}` template variable was removed in clap3, they are now included in `{options}`",
|
||||
);
|
||||
assert!(
|
||||
!help_template.to_string().contains("{unified}"),
|
||||
"Command {}: {}",
|
||||
cmd.get_name(),
|
||||
"`{unified}` template variable was removed in clap3, use `{options}` instead"
|
||||
);
|
||||
#[cfg(feature = "unstable-v5")]
|
||||
assert!(
|
||||
!help_template.to_string().contains("{bin}"),
|
||||
"Command {}: {}",
|
||||
cmd.get_name(),
|
||||
"`{bin}` template variable was removed in clap5, use `{name}` instead"
|
||||
)
|
||||
}
|
||||
|
||||
cmd._panic_on_missing_help(cmd.is_help_expected_set());
|
||||
assert_app_flags(cmd);
|
||||
}
|
||||
|
||||
fn duplicate_tip(cmd: &Command, first: &Arg, second: &Arg) -> &'static str {
|
||||
if !cmd.is_disable_help_flag_set()
|
||||
&& (first.get_id() == Id::HELP || second.get_id() == Id::HELP)
|
||||
{
|
||||
" (call `cmd.disable_help_flag(true)` to remove the auto-generated `--help`)"
|
||||
} else if !cmd.is_disable_version_flag_set()
|
||||
&& (first.get_id() == Id::VERSION || second.get_id() == Id::VERSION)
|
||||
{
|
||||
" (call `cmd.disable_version_flag(true)` to remove the auto-generated `--version`)"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq)]
|
||||
enum Flag<'a> {
|
||||
Command(String, &'a str),
|
||||
Arg(String, &'a str),
|
||||
}
|
||||
|
||||
impl PartialEq for Flag<'_> {
|
||||
fn eq(&self, other: &Flag) -> bool {
|
||||
self.cmp(other) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Flag<'_> {
|
||||
fn partial_cmp(&self, other: &Flag) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Flag<'_> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
use Flag::*;
|
||||
|
||||
match (self, other) {
|
||||
(Command(s1, _), Command(s2, _))
|
||||
| (Arg(s1, _), Arg(s2, _))
|
||||
| (Command(s1, _), Arg(s2, _))
|
||||
| (Arg(s1, _), Command(s2, _)) => {
|
||||
if s1 == s2 {
|
||||
Ordering::Equal
|
||||
} else {
|
||||
s1.cmp(s2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_duplicate_flags(flags: &[Flag], short_or_long: &str) {
|
||||
use Flag::*;
|
||||
|
||||
for (one, two) in find_duplicates(flags) {
|
||||
match (one, two) {
|
||||
(Command(flag, one), Command(_, another)) if one != another => panic!(
|
||||
"the '{flag}' {short_or_long} flag is specified for both '{one}' and '{another}' subcommands"
|
||||
),
|
||||
|
||||
(Arg(flag, one), Arg(_, another)) if one != another => panic!(
|
||||
"{short_or_long} option names must be unique, but '{flag}' is in use by both '{one}' and '{another}'"
|
||||
),
|
||||
|
||||
(Arg(flag, arg), Command(_, sub)) | (Command(flag, sub), Arg(_, arg)) => panic!(
|
||||
"the '{flag}' {short_or_long} flag for the '{arg}' argument conflicts with the short flag \
|
||||
for '{sub}' subcommand"
|
||||
),
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Find duplicates in a sorted array.
|
||||
///
|
||||
/// The algorithm is simple: the array is sorted, duplicates
|
||||
/// must be placed next to each other, we can check only adjacent elements.
|
||||
fn find_duplicates<T: PartialEq>(slice: &[T]) -> impl Iterator<Item = (&T, &T)> {
|
||||
slice.windows(2).filter_map(|w| {
|
||||
if w[0] == w[1] {
|
||||
Some((&w[0], &w[1]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn assert_app_flags(cmd: &Command) {
|
||||
macro_rules! checker {
|
||||
($a:ident requires $($b:ident)|+) => {
|
||||
if cmd.$a() {
|
||||
let mut s = String::new();
|
||||
|
||||
$(
|
||||
if !cmd.$b() {
|
||||
use std::fmt::Write;
|
||||
write!(&mut s, " AppSettings::{} is required when AppSettings::{} is set.\n", std::stringify!($b), std::stringify!($a)).unwrap();
|
||||
}
|
||||
)+
|
||||
|
||||
if !s.is_empty() {
|
||||
panic!("{s}")
|
||||
}
|
||||
}
|
||||
};
|
||||
($a:ident conflicts $($b:ident)|+) => {
|
||||
if cmd.$a() {
|
||||
let mut s = String::new();
|
||||
|
||||
$(
|
||||
if cmd.$b() {
|
||||
use std::fmt::Write;
|
||||
write!(&mut s, " AppSettings::{} conflicts with AppSettings::{}.\n", std::stringify!($b), std::stringify!($a)).unwrap();
|
||||
}
|
||||
)+
|
||||
|
||||
if !s.is_empty() {
|
||||
panic!("{}\n{}", cmd.get_name(), s)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
checker!(is_multicall_set conflicts is_no_binary_name_set);
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
fn _verify_positionals(cmd: &Command) -> bool {
|
||||
debug!("Command::_verify_positionals");
|
||||
// Because you must wait until all arguments have been supplied, this is the first chance
|
||||
// to make assertions on positional argument indexes
|
||||
//
|
||||
// First we verify that the index highest supplied index, is equal to the number of
|
||||
// positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
|
||||
// but no 2)
|
||||
|
||||
let highest_idx = cmd
|
||||
.get_keymap()
|
||||
.keys()
|
||||
.filter_map(|x| {
|
||||
if let KeyType::Position(n) = x {
|
||||
Some(*n)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
|
||||
let num_p = cmd.get_keymap().keys().filter(|x| x.is_position()).count();
|
||||
|
||||
assert!(
|
||||
highest_idx == num_p,
|
||||
"Found positional argument whose index is {highest_idx} but there \
|
||||
are only {num_p} positional arguments defined",
|
||||
);
|
||||
|
||||
for arg in cmd.get_arguments() {
|
||||
if arg.index.unwrap_or(0) == highest_idx {
|
||||
assert!(
|
||||
!arg.is_trailing_var_arg_set() || !arg.is_last_set(),
|
||||
"{}:{}: `Arg::trailing_var_arg` and `Arg::last` cannot be used together",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
if arg.is_trailing_var_arg_set() {
|
||||
assert!(
|
||||
arg.is_multiple(),
|
||||
"{}:{}: `Arg::trailing_var_arg` must accept multiple values",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
assert!(
|
||||
!arg.is_trailing_var_arg_set(),
|
||||
"{}:{}: `Arg::trailing_var_arg` can only apply to last positional",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Next we verify that only the highest index has takes multiple arguments (if any)
|
||||
let only_highest = |a: &Arg| a.is_multiple() && (a.get_index().unwrap_or(0) != highest_idx);
|
||||
if cmd.get_positionals().any(only_highest) {
|
||||
// First we make sure if there is a positional that allows multiple values
|
||||
// the one before it (second to last) has one of these:
|
||||
// * a value terminator
|
||||
// * ArgSettings::Last
|
||||
// * The last arg is Required
|
||||
|
||||
// We can't pass the closure (it.next()) to the macro directly because each call to
|
||||
// find() (iterator, not macro) gets called repeatedly.
|
||||
let last = &cmd.get_keymap()[&KeyType::Position(highest_idx)];
|
||||
let second_to_last = &cmd.get_keymap()[&KeyType::Position(highest_idx - 1)];
|
||||
|
||||
// Either the final positional is required
|
||||
// Or the second to last has a terminator or .last(true) set
|
||||
let ok = last.is_required_set()
|
||||
|| (second_to_last.terminator.is_some() || second_to_last.is_last_set())
|
||||
|| last.is_last_set();
|
||||
assert!(
|
||||
ok,
|
||||
"Positional argument `{last}` *must* have `required(true)` or `last(true)` set \
|
||||
because a prior positional argument (`{second_to_last}`) has `num_args(1..)`"
|
||||
);
|
||||
|
||||
// We make sure if the second to last is Multiple the last is ArgSettings::Last
|
||||
let ok = second_to_last.is_multiple() || last.is_last_set();
|
||||
assert!(
|
||||
ok,
|
||||
"Only the last positional argument, or second to last positional \
|
||||
argument may be set to `.num_args(1..)`"
|
||||
);
|
||||
|
||||
// Next we check how many have both Multiple and not a specific number of values set
|
||||
let count = cmd
|
||||
.get_positionals()
|
||||
.filter(|p| {
|
||||
p.is_multiple_values_set()
|
||||
&& p.get_value_terminator().is_none()
|
||||
&& !p.get_num_args().expect(INTERNAL_ERROR_MSG).is_fixed()
|
||||
})
|
||||
.count();
|
||||
let ok = count <= 1
|
||||
|| (last.is_last_set()
|
||||
&& last.is_multiple()
|
||||
&& second_to_last.is_multiple()
|
||||
&& count == 2);
|
||||
assert!(
|
||||
ok,
|
||||
"Only one positional argument with `.num_args(1..)` set is allowed per \
|
||||
command, unless the second one also has .last(true) set"
|
||||
);
|
||||
}
|
||||
|
||||
let mut found = false;
|
||||
|
||||
if cmd.is_allow_missing_positional_set() {
|
||||
// Check that if a required positional argument is found, all positions with a lower
|
||||
// index are also required.
|
||||
let mut foundx2 = false;
|
||||
|
||||
for p in cmd.get_positionals() {
|
||||
if foundx2 && !p.is_required_set() {
|
||||
assert!(
|
||||
p.is_required_set(),
|
||||
"Found non-required positional argument with a lower \
|
||||
index than a required positional argument by two or more: {:?} \
|
||||
index {:?}",
|
||||
p.get_id(),
|
||||
p.get_index()
|
||||
);
|
||||
} else if p.is_required_set() && !p.is_last_set() {
|
||||
// Args that .last(true) don't count since they can be required and have
|
||||
// positionals with a lower index that aren't required
|
||||
// Imagine: prog <req1> [opt1] -- <req2>
|
||||
// Both of these are valid invocations:
|
||||
// $ prog r1 -- r2
|
||||
// $ prog r1 o1 -- r2
|
||||
if found {
|
||||
foundx2 = true;
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
continue;
|
||||
} else {
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check that if a required positional argument is found, all positions with a lower
|
||||
// index are also required
|
||||
for p in (1..=num_p).rev().filter_map(|n| cmd.get_keymap().get(&n)) {
|
||||
if found {
|
||||
assert!(
|
||||
p.is_required_set(),
|
||||
"Found non-required positional argument with a lower \
|
||||
index than a required positional argument: {:?} index {:?}",
|
||||
p.get_id(),
|
||||
p.get_index()
|
||||
);
|
||||
} else if p.is_required_set() && !p.is_last_set() {
|
||||
// Args that .last(true) don't count since they can be required and have
|
||||
// positionals with a lower index that aren't required
|
||||
// Imagine: prog <req1> [opt1] -- <req2>
|
||||
// Both of these are valid invocations:
|
||||
// $ prog r1 -- r2
|
||||
// $ prog r1 o1 -- r2
|
||||
found = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
cmd.get_positionals().filter(|p| p.is_last_set()).count() < 2,
|
||||
"Only one positional argument may have last(true) set. Found two."
|
||||
);
|
||||
if cmd
|
||||
.get_positionals()
|
||||
.any(|p| p.is_last_set() && p.is_required_set())
|
||||
&& cmd.has_subcommands()
|
||||
&& !cmd.is_subcommand_negates_reqs_set()
|
||||
{
|
||||
panic!(
|
||||
"Having a required positional argument with .last(true) set *and* child \
|
||||
subcommands without setting SubcommandsNegateReqs isn't compatible."
|
||||
);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn assert_arg(arg: &Arg) {
|
||||
debug!("Arg::_debug_asserts:{}", arg.get_id());
|
||||
|
||||
// Self conflict
|
||||
// TODO: this check should be recursive
|
||||
assert!(
|
||||
!arg.blacklist.iter().any(|x| x == arg.get_id()),
|
||||
"Argument '{}' cannot conflict with itself",
|
||||
arg.get_id(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
arg.get_action().takes_values(),
|
||||
arg.is_takes_value_set(),
|
||||
"Argument `{}`'s selected action {:?} contradicts `takes_value`",
|
||||
arg.get_id(),
|
||||
arg.get_action()
|
||||
);
|
||||
if let Some(action_type_id) = arg.get_action().value_type_id() {
|
||||
assert_eq!(
|
||||
action_type_id,
|
||||
arg.get_value_parser().type_id(),
|
||||
"Argument `{}`'s selected action {:?} contradicts `value_parser` ({:?})",
|
||||
arg.get_id(),
|
||||
arg.get_action(),
|
||||
arg.get_value_parser()
|
||||
);
|
||||
}
|
||||
|
||||
if arg.get_value_hint() != ValueHint::Unknown {
|
||||
assert!(
|
||||
arg.is_takes_value_set(),
|
||||
"Argument '{}' has value hint but takes no value",
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
if arg.get_value_hint() == ValueHint::CommandWithArguments {
|
||||
assert!(
|
||||
arg.is_multiple_values_set(),
|
||||
"Argument '{}' uses hint CommandWithArguments and must accept multiple values",
|
||||
arg.get_id()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if arg.index.is_some() {
|
||||
assert!(
|
||||
arg.is_positional(),
|
||||
"Argument '{}' is a positional argument and can't have short or long name versions",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
arg.is_takes_value_set(),
|
||||
"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 {
|
||||
" (`mut_arg` no longer works with implicit `--version`)"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let num_vals = arg.get_num_args().expect(INTERNAL_ERROR_MSG);
|
||||
// This can be the cause of later asserts, so put this first
|
||||
if num_vals != ValueRange::EMPTY {
|
||||
// HACK: Don't check for flags to make the derive easier
|
||||
let num_val_names = arg.get_value_names().unwrap_or(&[]).len();
|
||||
if num_vals.max_values() < num_val_names {
|
||||
panic!(
|
||||
"Argument {}: Too many value names ({}) compared to `num_args` ({})",
|
||||
arg.get_id(),
|
||||
num_val_names,
|
||||
num_vals
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
num_vals.takes_values(),
|
||||
arg.is_takes_value_set(),
|
||||
"Argument {}: mismatch between `num_args` ({}) and `takes_value`",
|
||||
arg.get_id(),
|
||||
num_vals,
|
||||
);
|
||||
assert_eq!(
|
||||
num_vals.is_multiple(),
|
||||
arg.is_multiple_values_set(),
|
||||
"Argument {}: mismatch between `num_args` ({}) and `multiple_values`",
|
||||
arg.get_id(),
|
||||
num_vals,
|
||||
);
|
||||
|
||||
if 1 < num_vals.min_values() {
|
||||
assert!(
|
||||
!arg.is_require_equals_set(),
|
||||
"Argument {}: cannot accept more than 1 arg (num_args={}) with require_equals",
|
||||
arg.get_id(),
|
||||
num_vals
|
||||
);
|
||||
}
|
||||
|
||||
if num_vals == ValueRange::SINGLE {
|
||||
assert!(
|
||||
!arg.is_multiple_values_set(),
|
||||
"Argument {}: mismatch between `num_args` and `multiple_values`",
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
|
||||
assert_arg_flags(arg);
|
||||
}
|
||||
|
||||
fn assert_arg_flags(arg: &Arg) {
|
||||
macro_rules! checker {
|
||||
($a:ident requires $($b:ident)|+) => {
|
||||
if arg.$a() {
|
||||
let mut s = String::new();
|
||||
|
||||
$(
|
||||
if !arg.$b() {
|
||||
use std::fmt::Write;
|
||||
write!(&mut s, " Arg::{} is required when Arg::{} is set.\n", std::stringify!($b), std::stringify!($a)).unwrap();
|
||||
}
|
||||
)+
|
||||
|
||||
if !s.is_empty() {
|
||||
panic!("Argument {:?}\n{}", arg.get_id(), s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checker!(is_hide_possible_values_set requires is_takes_value_set);
|
||||
checker!(is_allow_hyphen_values_set requires is_takes_value_set);
|
||||
checker!(is_allow_negative_numbers_set requires is_takes_value_set);
|
||||
checker!(is_require_equals_set requires is_takes_value_set);
|
||||
checker!(is_last_set requires is_takes_value_set);
|
||||
checker!(is_hide_default_value_set requires is_takes_value_set);
|
||||
checker!(is_multiple_values_set requires is_takes_value_set);
|
||||
checker!(is_ignore_case_set requires is_takes_value_set);
|
||||
}
|
216
vendor/clap_builder/src/builder/ext.rs
vendored
Normal file
216
vendor/clap_builder/src/builder/ext.rs
vendored
Normal file
@ -0,0 +1,216 @@
|
||||
use crate::util::AnyValueId;
|
||||
use crate::util::FlatMap;
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub(crate) struct Extensions {
|
||||
extensions: FlatMap<AnyValueId, BoxedExtension>,
|
||||
}
|
||||
|
||||
impl Extensions {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get<T: Extension>(&self) -> Option<&T> {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions.get(&id).map(|e| e.as_ref::<T>())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get_mut<T: Extension>(&mut self) -> Option<&mut T> {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions.get_mut(&id).map(|e| e.as_mut::<T>())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get_or_insert_default<T: Extension + Default>(&mut self) -> &mut T {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions
|
||||
.entry(id)
|
||||
.or_insert_with(|| BoxedExtension::new(T::default()))
|
||||
.as_mut::<T>()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn set<T: Extension + Into<BoxedEntry>>(&mut self, tagged: T) -> bool {
|
||||
let BoxedEntry { id, value } = tagged.into();
|
||||
self.extensions.insert(id, value).is_some()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn remove<T: Extension>(&mut self) -> Option<Box<dyn Extension>> {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions.remove(&id).map(BoxedExtension::into_inner)
|
||||
}
|
||||
|
||||
pub(crate) fn update(&mut self, other: &Self) {
|
||||
for (key, value) in other.extensions.iter() {
|
||||
self.extensions.insert(*key, value.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Supports conversion to `Any`. Traits to be extended by `impl_downcast!` must extend `Extension`.
|
||||
pub(crate) trait Extension: std::fmt::Debug + Send + Sync + 'static {
|
||||
/// Convert `Box<dyn Trait>` (where `Trait: Extension`) to `Box<dyn Any>`.
|
||||
///
|
||||
/// `Box<dyn Any>` can /// then be further `downcast` into
|
||||
/// `Box<ConcreteType>` where `ConcreteType` implements `Trait`.
|
||||
fn into_any(self: Box<Self>) -> Box<dyn std::any::Any>;
|
||||
/// Clone `&Box<dyn Trait>` (where `Trait: Extension`) to `Box<dyn Extension>`.
|
||||
///
|
||||
/// `Box<dyn Any>` can /// then be further `downcast` into
|
||||
// `Box<ConcreteType>` where `ConcreteType` implements `Trait`.
|
||||
fn clone_extension(&self) -> Box<dyn Extension>;
|
||||
/// Convert `&Trait` (where `Trait: Extension`) to `&Any`.
|
||||
///
|
||||
/// This is needed since Rust cannot /// generate `&Any`'s vtable from
|
||||
/// `&Trait`'s.
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
/// Convert `&mut Trait` (where `Trait: Extension`) to `&Any`.
|
||||
///
|
||||
/// This is needed since Rust cannot /// generate `&mut Any`'s vtable from
|
||||
/// `&mut Trait`'s.
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl<T> Extension for T
|
||||
where
|
||||
T: Clone + std::fmt::Debug + Send + Sync + 'static,
|
||||
{
|
||||
fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
|
||||
self
|
||||
}
|
||||
fn clone_extension(&self) -> Box<dyn Extension> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Box<dyn Extension> {
|
||||
fn clone(&self) -> Self {
|
||||
self.as_ref().clone_extension()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(transparent)]
|
||||
struct BoxedExtension(Box<dyn Extension>);
|
||||
|
||||
impl BoxedExtension {
|
||||
fn new<T: Extension>(inner: T) -> Self {
|
||||
Self(Box::new(inner))
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Box<dyn Extension> {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn as_ref<T: Extension>(&self) -> &T {
|
||||
self.0.as_ref().as_any().downcast_ref::<T>().unwrap()
|
||||
}
|
||||
|
||||
fn as_mut<T: Extension>(&mut self) -> &mut T {
|
||||
self.0.as_mut().as_any_mut().downcast_mut::<T>().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for BoxedExtension {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct BoxedEntry {
|
||||
id: AnyValueId,
|
||||
value: BoxedExtension,
|
||||
}
|
||||
|
||||
impl BoxedEntry {
|
||||
pub(crate) fn new(r: impl Extension) -> Self {
|
||||
let id = AnyValueId::from(&r);
|
||||
let value = BoxedExtension::new(r);
|
||||
BoxedEntry { id, value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Extension> From<R> for BoxedEntry {
|
||||
fn from(inner: R) -> Self {
|
||||
BoxedEntry::new(inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
struct Number(usize);
|
||||
|
||||
#[test]
|
||||
fn get() {
|
||||
let mut ext = Extensions::default();
|
||||
ext.set(Number(10));
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(10)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_mut() {
|
||||
let mut ext = Extensions::default();
|
||||
ext.set(Number(10));
|
||||
*ext.get_mut::<Number>().unwrap() = Number(20);
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(20)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_or_insert_default_empty() {
|
||||
let mut ext = Extensions::default();
|
||||
assert_eq!(ext.get_or_insert_default::<Number>(), &Number(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_or_insert_default_full() {
|
||||
let mut ext = Extensions::default();
|
||||
ext.set(Number(10));
|
||||
assert_eq!(ext.get_or_insert_default::<Number>(), &Number(10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set() {
|
||||
let mut ext = Extensions::default();
|
||||
assert!(!ext.set(Number(10)));
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(10)));
|
||||
assert!(ext.set(Number(20)));
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(20)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset() {
|
||||
let mut ext = Extensions::default();
|
||||
assert_eq!(ext.get::<Number>(), None);
|
||||
|
||||
assert!(ext.remove::<Number>().is_none());
|
||||
assert_eq!(ext.get::<Number>(), None);
|
||||
|
||||
assert!(!ext.set(Number(10)));
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(10)));
|
||||
|
||||
assert!(ext.remove::<Number>().is_some());
|
||||
assert_eq!(ext.get::<Number>(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update() {
|
||||
let mut ext = Extensions::default();
|
||||
assert_eq!(ext.get::<Number>(), None);
|
||||
|
||||
let mut new = Extensions::default();
|
||||
assert!(!new.set(Number(10)));
|
||||
|
||||
ext.update(&new);
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(10)));
|
||||
}
|
||||
}
|
67
vendor/clap_builder/src/builder/mod.rs
vendored
Normal file
67
vendor/clap_builder/src/builder/mod.rs
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
//! Define [`Command`] line [arguments][`Arg`]
|
||||
|
||||
mod action;
|
||||
mod app_settings;
|
||||
mod arg;
|
||||
mod arg_group;
|
||||
mod arg_predicate;
|
||||
mod arg_settings;
|
||||
mod command;
|
||||
mod ext;
|
||||
mod os_str;
|
||||
mod possible_value;
|
||||
mod range;
|
||||
mod resettable;
|
||||
mod str;
|
||||
mod styled_str;
|
||||
mod value_hint;
|
||||
mod value_parser;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
mod debug_asserts;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub mod styling;
|
||||
|
||||
pub use self::str::Str;
|
||||
pub use action::ArgAction;
|
||||
pub use arg::Arg;
|
||||
pub use arg_group::ArgGroup;
|
||||
pub use arg_predicate::ArgPredicate;
|
||||
pub use command::Command;
|
||||
pub use os_str::OsStr;
|
||||
pub use possible_value::PossibleValue;
|
||||
pub use range::ValueRange;
|
||||
pub use resettable::IntoResettable;
|
||||
pub use resettable::Resettable;
|
||||
pub use styled_str::StyledStr;
|
||||
pub use styling::Styles;
|
||||
pub use value_hint::ValueHint;
|
||||
pub use value_parser::_AutoValueParser;
|
||||
pub use value_parser::via_prelude;
|
||||
pub use value_parser::BoolValueParser;
|
||||
pub use value_parser::BoolishValueParser;
|
||||
pub use value_parser::EnumValueParser;
|
||||
pub use value_parser::FalseyValueParser;
|
||||
pub use value_parser::MapValueParser;
|
||||
pub use value_parser::NonEmptyStringValueParser;
|
||||
pub use value_parser::OsStringValueParser;
|
||||
pub use value_parser::PathBufValueParser;
|
||||
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;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
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;
|
336
vendor/clap_builder/src/builder/os_str.rs
vendored
Normal file
336
vendor/clap_builder/src/builder/os_str.rs
vendored
Normal file
@ -0,0 +1,336 @@
|
||||
use crate::builder::Str;
|
||||
|
||||
/// A UTF-8-encoded fixed string
|
||||
///
|
||||
/// **NOTE:** To support dynamic values (i.e. `OsString`), enable the `string`
|
||||
/// feature
|
||||
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct OsStr {
|
||||
name: Inner,
|
||||
}
|
||||
|
||||
impl OsStr {
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_string(name: std::ffi::OsString) -> Self {
|
||||
Self {
|
||||
name: Inner::from_string(name),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_ref(name: &std::ffi::OsStr) -> Self {
|
||||
Self {
|
||||
name: Inner::from_ref(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
|
||||
Self {
|
||||
name: Inner::from_static_ref(name),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the raw string as an `std::ffi::OsStr`
|
||||
pub fn as_os_str(&self) -> &std::ffi::OsStr {
|
||||
self.name.as_os_str()
|
||||
}
|
||||
|
||||
/// Get the raw string as an `OsString`
|
||||
pub fn to_os_string(&self) -> std::ffi::OsString {
|
||||
self.as_os_str().to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ OsStr> for OsStr {
|
||||
fn from(id: &'_ OsStr) -> Self {
|
||||
id.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<Str> for OsStr {
|
||||
fn from(id: Str) -> Self {
|
||||
match id.into_inner() {
|
||||
crate::builder::StrInner::Static(s) => Self::from_static_ref(std::ffi::OsStr::new(s)),
|
||||
crate::builder::StrInner::Owned(s) => Self::from_ref(std::ffi::OsStr::new(s.as_ref())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "string"))]
|
||||
impl From<Str> for OsStr {
|
||||
fn from(id: Str) -> Self {
|
||||
Self::from_static_ref(std::ffi::OsStr::new(id.into_inner().0))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "perf")]
|
||||
impl From<&'_ Str> for OsStr {
|
||||
fn from(id: &'_ Str) -> Self {
|
||||
match id.clone().into_inner() {
|
||||
crate::builder::StrInner::Static(s) => Self::from_static_ref(std::ffi::OsStr::new(s)),
|
||||
crate::builder::StrInner::Owned(s) => Self::from_ref(std::ffi::OsStr::new(s.as_ref())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Str> for OsStr {
|
||||
fn from(id: &'_ Str) -> Self {
|
||||
id.clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<std::ffi::OsString> for OsStr {
|
||||
fn from(name: std::ffi::OsString) -> Self {
|
||||
Self::from_string(name)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ std::ffi::OsString> for OsStr {
|
||||
fn from(name: &'_ std::ffi::OsString) -> Self {
|
||||
Self::from_ref(name.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<std::string::String> for OsStr {
|
||||
fn from(name: std::string::String) -> Self {
|
||||
Self::from_string(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ std::string::String> for OsStr {
|
||||
fn from(name: &'_ std::string::String) -> Self {
|
||||
Self::from_ref(name.as_str().as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static std::ffi::OsStr> for OsStr {
|
||||
fn from(name: &'static std::ffi::OsStr) -> Self {
|
||||
Self::from_static_ref(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static std::ffi::OsStr> for OsStr {
|
||||
fn from(name: &'_ &'static std::ffi::OsStr) -> Self {
|
||||
Self::from_static_ref(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for OsStr {
|
||||
fn from(name: &'static str) -> Self {
|
||||
Self::from_static_ref(name.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static str> for OsStr {
|
||||
fn from(name: &'_ &'static str) -> Self {
|
||||
Self::from_static_ref((*name).as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OsStr> for std::ffi::OsString {
|
||||
fn from(name: OsStr) -> Self {
|
||||
name.name.into_os_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OsStr> for std::path::PathBuf {
|
||||
fn from(name: OsStr) -> Self {
|
||||
std::ffi::OsString::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for OsStr {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self.as_os_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for OsStr {
|
||||
type Target = std::ffi::OsStr;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &std::ffi::OsStr {
|
||||
self.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<std::ffi::OsStr> for OsStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &std::ffi::OsStr {
|
||||
self.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<std::path::Path> for OsStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &std::path::Path {
|
||||
std::path::Path::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::borrow::Borrow<std::ffi::OsStr> for OsStr {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &std::ffi::OsStr {
|
||||
self.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(self, other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ str> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for &'_ str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(*self, other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ std::ffi::OsStr> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&std::ffi::OsStr) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for &'_ std::ffi::OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(*self, other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::string::String> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::string::String) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for std::string::String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::ffi::OsString> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::ffi::OsString) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other.as_os_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for std::ffi::OsString {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) mod inner {
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum Inner {
|
||||
Static(&'static std::ffi::OsStr),
|
||||
Owned(Box<std::ffi::OsStr>),
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_string(name: std::ffi::OsString) -> Self {
|
||||
Self::Owned(name.into_boxed_os_str())
|
||||
}
|
||||
|
||||
pub(crate) fn from_ref(name: &std::ffi::OsStr) -> Self {
|
||||
Self::Owned(Box::from(name))
|
||||
}
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
|
||||
Self::Static(name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_os_str(&self) -> &std::ffi::OsStr {
|
||||
match self {
|
||||
Self::Static(s) => s,
|
||||
Self::Owned(s) => s.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_os_string(self) -> std::ffi::OsString {
|
||||
self.as_os_str().to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "string"))]
|
||||
pub(crate) mod inner {
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Inner(&'static std::ffi::OsStr);
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
|
||||
Self(name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_os_str(&self) -> &std::ffi::OsStr {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub(crate) fn into_os_string(self) -> std::ffi::OsString {
|
||||
self.as_os_str().to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use inner::Inner;
|
||||
|
||||
impl Default for Inner {
|
||||
fn default() -> Self {
|
||||
Self::from_static_ref(std::ffi::OsStr::new(""))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Inner {
|
||||
fn eq(&self, other: &Inner) -> bool {
|
||||
self.as_os_str() == other.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Inner {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Inner {
|
||||
fn cmp(&self, other: &Inner) -> std::cmp::Ordering {
|
||||
self.as_os_str().cmp(other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Inner {}
|
||||
|
||||
impl std::hash::Hash for Inner {
|
||||
#[inline]
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.as_os_str().hash(state);
|
||||
}
|
||||
}
|
229
vendor/clap_builder/src/builder/possible_value.rs
vendored
Normal file
229
vendor/clap_builder/src/builder/possible_value.rs
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
use crate::builder::IntoResettable;
|
||||
use crate::builder::Str;
|
||||
use crate::builder::StyledStr;
|
||||
use crate::util::eq_ignore_case;
|
||||
|
||||
/// A possible value of an argument.
|
||||
///
|
||||
/// This is used for specifying [possible values] of [Args].
|
||||
///
|
||||
/// See also [`PossibleValuesParser`][crate::builder::PossibleValuesParser]
|
||||
///
|
||||
/// **NOTE:** Most likely you can use strings, rather than `PossibleValue` as it is only required
|
||||
/// to [hide] single values from help messages and shell completions or to attach [help] to
|
||||
/// possible values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Arg, builder::PossibleValue, ArgAction};
|
||||
/// let cfg = Arg::new("config")
|
||||
/// .action(ArgAction::Set)
|
||||
/// .value_name("FILE")
|
||||
/// .value_parser([
|
||||
/// PossibleValue::new("fast"),
|
||||
/// PossibleValue::new("slow").help("slower than fast"),
|
||||
/// PossibleValue::new("secret speed").hide(true)
|
||||
/// ]);
|
||||
/// ```
|
||||
///
|
||||
/// [Args]: crate::Arg
|
||||
/// [possible values]: crate::builder::ValueParser::possible_values
|
||||
/// [hide]: PossibleValue::hide()
|
||||
/// [help]: PossibleValue::help()
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct PossibleValue {
|
||||
name: Str,
|
||||
help: Option<StyledStr>,
|
||||
aliases: Vec<Str>, // (name, visible)
|
||||
hide: bool,
|
||||
}
|
||||
|
||||
impl PossibleValue {
|
||||
/// Create a [`PossibleValue`] with its name.
|
||||
///
|
||||
/// The name will be used to decide whether this value was provided by the user to an argument.
|
||||
///
|
||||
/// **NOTE:** In case it is not [hidden] it will also be shown in help messages for arguments
|
||||
/// that use it as a [possible value] and have not hidden them through [`Arg::hide_possible_values(true)`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("fast")
|
||||
/// # ;
|
||||
/// ```
|
||||
/// [hidden]: PossibleValue::hide
|
||||
/// [possible value]: crate::builder::PossibleValuesParser
|
||||
/// [`Arg::hide_possible_values(true)`]: crate::Arg::hide_possible_values()
|
||||
pub fn new(name: impl Into<Str>) -> Self {
|
||||
PossibleValue {
|
||||
name: name.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the help description of the value.
|
||||
///
|
||||
/// This is typically displayed in completions (where supported) and should be a short, one-line
|
||||
/// description.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("slow")
|
||||
/// .help("not fast")
|
||||
/// # ;
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn help(mut self, help: impl IntoResettable<StyledStr>) -> Self {
|
||||
self.help = help.into_resettable().into_option();
|
||||
self
|
||||
}
|
||||
|
||||
/// Hides this value from help and shell completions.
|
||||
///
|
||||
/// This is an alternative to hiding through [`Arg::hide_possible_values(true)`], if you only
|
||||
/// want to hide some values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("secret")
|
||||
/// .hide(true)
|
||||
/// # ;
|
||||
/// ```
|
||||
/// [`Arg::hide_possible_values(true)`]: crate::Arg::hide_possible_values()
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn hide(mut self, yes: bool) -> Self {
|
||||
self.hide = yes;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a *hidden* alias for this argument value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("slow")
|
||||
/// .alias("not-fast")
|
||||
/// # ;
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn alias(mut self, name: impl IntoResettable<Str>) -> Self {
|
||||
if let Some(name) = name.into_resettable().into_option() {
|
||||
self.aliases.push(name);
|
||||
} else {
|
||||
self.aliases.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets multiple *hidden* aliases for this argument value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("slow")
|
||||
/// .aliases(["not-fast", "snake-like"])
|
||||
/// # ;
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn aliases(mut self, names: impl IntoIterator<Item = impl Into<Str>>) -> Self {
|
||||
self.aliases.extend(names.into_iter().map(|a| a.into()));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Reflection
|
||||
impl PossibleValue {
|
||||
/// Get the name of the argument value
|
||||
#[inline]
|
||||
pub fn get_name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
/// Get the help specified for this argument, if any
|
||||
#[inline]
|
||||
pub fn get_help(&self) -> Option<&StyledStr> {
|
||||
self.help.as_ref()
|
||||
}
|
||||
|
||||
/// Report if [`PossibleValue::hide`] is set
|
||||
#[inline]
|
||||
pub fn is_hide_set(&self) -> bool {
|
||||
self.hide
|
||||
}
|
||||
|
||||
/// Report if PossibleValue is not hidden and has a help message
|
||||
pub(crate) fn should_show_help(&self) -> bool {
|
||||
!self.hide && self.help.is_some()
|
||||
}
|
||||
|
||||
/// Get the name if argument value is not hidden, `None` otherwise,
|
||||
/// but wrapped in quotes if it contains whitespace
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn get_visible_quoted_name(&self) -> Option<std::borrow::Cow<'_, str>> {
|
||||
if !self.hide {
|
||||
Some(if self.name.contains(char::is_whitespace) {
|
||||
format!("{:?}", self.name).into()
|
||||
} else {
|
||||
self.name.as_str().into()
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns all valid values of the argument value.
|
||||
///
|
||||
/// Namely the name and all aliases.
|
||||
pub fn get_name_and_aliases(&self) -> impl Iterator<Item = &str> + '_ {
|
||||
std::iter::once(self.get_name()).chain(self.aliases.iter().map(|s| s.as_str()))
|
||||
}
|
||||
|
||||
/// Tests if the value is valid for this argument value
|
||||
///
|
||||
/// The value is valid if it is either the name or one of the aliases.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// let arg_value = PossibleValue::new("fast").alias("not-slow");
|
||||
///
|
||||
/// assert!(arg_value.matches("fast", false));
|
||||
/// assert!(arg_value.matches("not-slow", false));
|
||||
///
|
||||
/// assert!(arg_value.matches("FAST", true));
|
||||
/// assert!(!arg_value.matches("FAST", false));
|
||||
/// ```
|
||||
pub fn matches(&self, value: &str, ignore_case: bool) -> bool {
|
||||
if ignore_case {
|
||||
self.get_name_and_aliases()
|
||||
.any(|name| eq_ignore_case(name, value))
|
||||
} else {
|
||||
self.get_name_and_aliases().any(|name| name == value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Into<Str>> From<S> for PossibleValue {
|
||||
fn from(s: S) -> Self {
|
||||
Self::new(s)
|
||||
}
|
||||
}
|
286
vendor/clap_builder/src/builder/range.rs
vendored
Normal file
286
vendor/clap_builder/src/builder/range.rs
vendored
Normal file
@ -0,0 +1,286 @@
|
||||
/// Values per occurrence for an argument
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ValueRange {
|
||||
start_inclusive: usize,
|
||||
end_inclusive: usize,
|
||||
}
|
||||
|
||||
impl ValueRange {
|
||||
/// Nor argument values, or a flag
|
||||
pub const EMPTY: Self = Self {
|
||||
start_inclusive: 0,
|
||||
end_inclusive: 0,
|
||||
};
|
||||
|
||||
/// A single argument value, the most common case for options
|
||||
pub const SINGLE: Self = Self {
|
||||
start_inclusive: 1,
|
||||
end_inclusive: 1,
|
||||
};
|
||||
|
||||
/// Create a range
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the end is less than the start (debug builds)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::ValueRange;
|
||||
/// let range = ValueRange::new(5);
|
||||
/// let range = ValueRange::new(5..10);
|
||||
/// let range = ValueRange::new(5..=10);
|
||||
/// let range = ValueRange::new(5..);
|
||||
/// let range = ValueRange::new(..10);
|
||||
/// let range = ValueRange::new(..=10);
|
||||
/// ```
|
||||
///
|
||||
/// While this will panic:
|
||||
/// ```should_panic
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::ValueRange;
|
||||
/// let range = ValueRange::new(10..5); // Panics!
|
||||
/// ```
|
||||
pub fn new(range: impl Into<Self>) -> Self {
|
||||
range.into()
|
||||
}
|
||||
|
||||
pub(crate) fn raw(start_inclusive: usize, end_inclusive: usize) -> Self {
|
||||
debug_assert!(start_inclusive <= end_inclusive);
|
||||
Self {
|
||||
start_inclusive,
|
||||
end_inclusive,
|
||||
}
|
||||
}
|
||||
|
||||
/// Fewest number of values the argument accepts
|
||||
pub fn min_values(&self) -> usize {
|
||||
self.start_inclusive
|
||||
}
|
||||
|
||||
/// Most number of values the argument accepts
|
||||
pub fn max_values(&self) -> usize {
|
||||
self.end_inclusive
|
||||
}
|
||||
|
||||
/// Report whether the argument takes any values (ie is a flag)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::ValueRange;
|
||||
/// let range = ValueRange::new(5);
|
||||
/// assert!(range.takes_values());
|
||||
///
|
||||
/// let range = ValueRange::new(0);
|
||||
/// assert!(!range.takes_values());
|
||||
/// ```
|
||||
pub fn takes_values(&self) -> bool {
|
||||
self.end_inclusive != 0
|
||||
}
|
||||
|
||||
pub(crate) fn is_unbounded(&self) -> bool {
|
||||
self.end_inclusive == usize::MAX
|
||||
}
|
||||
|
||||
pub(crate) fn is_fixed(&self) -> bool {
|
||||
self.start_inclusive == self.end_inclusive
|
||||
}
|
||||
|
||||
pub(crate) fn is_multiple(&self) -> bool {
|
||||
self.start_inclusive != self.end_inclusive || 1 < self.start_inclusive
|
||||
}
|
||||
|
||||
pub(crate) fn num_values(&self) -> Option<usize> {
|
||||
self.is_fixed().then_some(self.start_inclusive)
|
||||
}
|
||||
|
||||
pub(crate) fn accepts_more(&self, current: usize) -> bool {
|
||||
current < self.end_inclusive
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::RangeBounds<usize> for ValueRange {
|
||||
fn start_bound(&self) -> std::ops::Bound<&usize> {
|
||||
std::ops::Bound::Included(&self.start_inclusive)
|
||||
}
|
||||
|
||||
fn end_bound(&self) -> std::ops::Bound<&usize> {
|
||||
std::ops::Bound::Included(&self.end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ValueRange {
|
||||
fn default() -> Self {
|
||||
Self::SINGLE
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for ValueRange {
|
||||
fn from(fixed: usize) -> Self {
|
||||
(fixed..=fixed).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::Range<usize>> for ValueRange {
|
||||
fn from(range: std::ops::Range<usize>) -> Self {
|
||||
let start_inclusive = range.start;
|
||||
let end_inclusive = range.end.saturating_sub(1);
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeFull> for ValueRange {
|
||||
fn from(_: std::ops::RangeFull) -> Self {
|
||||
let start_inclusive = 0;
|
||||
let end_inclusive = usize::MAX;
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeFrom<usize>> for ValueRange {
|
||||
fn from(range: std::ops::RangeFrom<usize>) -> Self {
|
||||
let start_inclusive = range.start;
|
||||
let end_inclusive = usize::MAX;
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeTo<usize>> for ValueRange {
|
||||
fn from(range: std::ops::RangeTo<usize>) -> Self {
|
||||
let start_inclusive = 0;
|
||||
let end_inclusive = range.end.saturating_sub(1);
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeInclusive<usize>> for ValueRange {
|
||||
fn from(range: std::ops::RangeInclusive<usize>) -> Self {
|
||||
let start_inclusive = *range.start();
|
||||
let end_inclusive = *range.end();
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeToInclusive<usize>> for ValueRange {
|
||||
fn from(range: std::ops::RangeToInclusive<usize>) -> Self {
|
||||
let start_inclusive = 0;
|
||||
let end_inclusive = range.end;
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ValueRange {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
ok!(self.start_inclusive.fmt(f));
|
||||
if !self.is_fixed() {
|
||||
ok!("..=".fmt(f));
|
||||
ok!(self.end_inclusive.fmt(f));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ValueRange {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{self}")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
use std::ops::RangeBounds;
|
||||
|
||||
#[test]
|
||||
fn from_fixed() {
|
||||
let range: ValueRange = 5.into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&5));
|
||||
assert!(range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), Some(5));
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_fixed_empty() {
|
||||
let range: ValueRange = 0.into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&0));
|
||||
assert!(range.is_fixed());
|
||||
assert!(!range.is_multiple());
|
||||
assert_eq!(range.num_values(), Some(0));
|
||||
assert!(!range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range() {
|
||||
let range: ValueRange = (5..10).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&9));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_inclusive() {
|
||||
let range: ValueRange = (5..=10).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&10));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_full() {
|
||||
let range: ValueRange = (..).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&usize::MAX));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_from() {
|
||||
let range: ValueRange = (5..).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&usize::MAX));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_to() {
|
||||
let range: ValueRange = (..10).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&9));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_to_inclusive() {
|
||||
let range: ValueRange = (..=10).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&10));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
}
|
212
vendor/clap_builder/src/builder/resettable.rs
vendored
Normal file
212
vendor/clap_builder/src/builder/resettable.rs
vendored
Normal file
@ -0,0 +1,212 @@
|
||||
// Unlike `impl Into<Option<T>>` or `Option<impl Into<T>>`, this isn't ambiguous for the `None`
|
||||
// case.
|
||||
|
||||
use crate::builder::ArgAction;
|
||||
use crate::builder::OsStr;
|
||||
use crate::builder::Str;
|
||||
use crate::builder::StyledStr;
|
||||
use crate::builder::ValueHint;
|
||||
use crate::builder::ValueParser;
|
||||
use crate::builder::ValueRange;
|
||||
|
||||
/// Clearable builder value
|
||||
///
|
||||
/// This allows a builder function to both accept any value that can [`Into::into`] `T` (like
|
||||
/// `&str` into `OsStr`) as well as `None` to reset it to the default. This is needed to
|
||||
/// workaround a limitation where you can't have a function argument that is `impl Into<Option<T>>`
|
||||
/// where `T` is `impl Into<S>` accept `None` as its type is ambiguous.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// fn common() -> Command {
|
||||
/// Command::new("cli")
|
||||
/// .arg(Arg::new("input").short('i').long("input"))
|
||||
/// }
|
||||
/// let mut command = common();
|
||||
/// command.mut_arg("input", |arg| arg.short(None));
|
||||
/// ```
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Resettable<T> {
|
||||
/// Overwrite builder value
|
||||
Value(T),
|
||||
/// Reset builder value
|
||||
Reset,
|
||||
}
|
||||
|
||||
impl<T> Resettable<T> {
|
||||
pub(crate) fn into_option(self) -> Option<T> {
|
||||
match self {
|
||||
Self::Value(t) => Some(t),
|
||||
Self::Reset => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Resettable<T> {
|
||||
fn from(other: T) -> Self {
|
||||
Self::Value(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Option<T>> for Resettable<T> {
|
||||
fn from(other: Option<T>) -> Self {
|
||||
match other {
|
||||
Some(inner) => Self::Value(inner),
|
||||
None => Self::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert to the intended resettable type
|
||||
pub trait IntoResettable<T> {
|
||||
/// Convert to the intended resettable type
|
||||
fn into_resettable(self) -> Resettable<T>;
|
||||
}
|
||||
|
||||
impl IntoResettable<char> for Option<char> {
|
||||
fn into_resettable(self) -> Resettable<char> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<usize> for Option<usize> {
|
||||
fn into_resettable(self) -> Resettable<usize> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ArgAction> for Option<ArgAction> {
|
||||
fn into_resettable(self) -> Resettable<ArgAction> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ValueHint> for Option<ValueHint> {
|
||||
fn into_resettable(self) -> Resettable<ValueHint> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ValueParser> for Option<ValueParser> {
|
||||
fn into_resettable(self) -> Resettable<ValueParser> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<StyledStr> for Option<&'static str> {
|
||||
fn into_resettable(self) -> Resettable<StyledStr> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s.into()),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<OsStr> for Option<&'static str> {
|
||||
fn into_resettable(self) -> Resettable<OsStr> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s.into()),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<Str> for Option<&'static str> {
|
||||
fn into_resettable(self) -> Resettable<Str> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s.into()),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoResettable<T> for Resettable<T> {
|
||||
fn into_resettable(self) -> Resettable<T> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<char> for char {
|
||||
fn into_resettable(self) -> Resettable<char> {
|
||||
Resettable::Value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<usize> for usize {
|
||||
fn into_resettable(self) -> Resettable<usize> {
|
||||
Resettable::Value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ArgAction> for ArgAction {
|
||||
fn into_resettable(self) -> Resettable<ArgAction> {
|
||||
Resettable::Value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ValueHint> for ValueHint {
|
||||
fn into_resettable(self) -> Resettable<ValueHint> {
|
||||
Resettable::Value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<ValueRange>> IntoResettable<ValueRange> for I {
|
||||
fn into_resettable(self) -> Resettable<ValueRange> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<ValueParser>> IntoResettable<ValueParser> for I {
|
||||
fn into_resettable(self) -> Resettable<ValueParser> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<String>> IntoResettable<String> for I {
|
||||
fn into_resettable(self) -> Resettable<String> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<StyledStr>> IntoResettable<StyledStr> for I {
|
||||
fn into_resettable(self) -> Resettable<StyledStr> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<OsStr>> IntoResettable<OsStr> for I {
|
||||
fn into_resettable(self) -> Resettable<OsStr> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<Str>> IntoResettable<Str> for I {
|
||||
fn into_resettable(self) -> Resettable<Str> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<crate::Id>> IntoResettable<crate::Id> for I {
|
||||
fn into_resettable(self) -> Resettable<crate::Id> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
310
vendor/clap_builder/src/builder/str.rs
vendored
Normal file
310
vendor/clap_builder/src/builder/str.rs
vendored
Normal file
@ -0,0 +1,310 @@
|
||||
/// A UTF-8-encoded fixed string
|
||||
///
|
||||
/// **NOTE:** To support dynamic values (i.e. `String`), enable the `string`
|
||||
/// feature
|
||||
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct Str {
|
||||
name: Inner,
|
||||
}
|
||||
|
||||
impl Str {
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_string(name: std::string::String) -> Self {
|
||||
Self {
|
||||
name: Inner::from_string(name),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_ref(name: &str) -> Self {
|
||||
Self {
|
||||
name: Inner::from_ref(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static str) -> Self {
|
||||
Self {
|
||||
name: Inner::from_static_ref(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_inner(self) -> Inner {
|
||||
self.name
|
||||
}
|
||||
|
||||
/// Get the raw string of the `Str`
|
||||
pub fn as_str(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Str> for Str {
|
||||
fn from(id: &'_ Str) -> Self {
|
||||
id.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<std::string::String> for Str {
|
||||
fn from(name: std::string::String) -> Self {
|
||||
Self::from_string(name)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ std::string::String> for Str {
|
||||
fn from(name: &'_ std::string::String) -> Self {
|
||||
Self::from_ref(name.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Str {
|
||||
fn from(name: &'static str) -> Self {
|
||||
Self::from_static_ref(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static str> for Str {
|
||||
fn from(name: &'_ &'static str) -> Self {
|
||||
Self::from_static_ref(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for String {
|
||||
fn from(name: Str) -> Self {
|
||||
name.name.into_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for Vec<u8> {
|
||||
fn from(name: Str) -> Self {
|
||||
String::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for std::ffi::OsString {
|
||||
fn from(name: Str) -> Self {
|
||||
String::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for std::path::PathBuf {
|
||||
fn from(name: Str) -> Self {
|
||||
String::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Str {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Str {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Str {
|
||||
type Target = str;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<std::ffi::OsStr> for Str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &std::ffi::OsStr {
|
||||
(**self).as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<std::path::Path> for Str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &std::path::Path {
|
||||
std::path::Path::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::borrow::Borrow<str> for Str {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
PartialEq::eq(self.as_str(), other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ str> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
PartialEq::eq(self.as_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for &'_ str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(*self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::ffi::OsStr> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::ffi::OsStr) -> bool {
|
||||
PartialEq::eq(self.as_str(), other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for std::ffi::OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ std::ffi::OsStr> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&std::ffi::OsStr) -> bool {
|
||||
PartialEq::eq(self.as_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for &'_ std::ffi::OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(*self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::string::String> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::string::String) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for std::string::String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) mod inner {
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum Inner {
|
||||
Static(&'static str),
|
||||
Owned(Box<str>),
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_string(name: std::string::String) -> Self {
|
||||
Self::Owned(name.into_boxed_str())
|
||||
}
|
||||
|
||||
pub(crate) fn from_ref(name: &str) -> Self {
|
||||
Self::Owned(Box::from(name))
|
||||
}
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static str) -> Self {
|
||||
Self::Static(name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_str(&self) -> &str {
|
||||
match self {
|
||||
Self::Static(s) => s,
|
||||
Self::Owned(s) => s.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_string(self) -> String {
|
||||
match self {
|
||||
Self::Static(s) => s.to_owned(),
|
||||
Self::Owned(s) => s.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "string"))]
|
||||
pub(crate) mod inner {
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Inner(pub(crate) &'static str);
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_static_ref(name: &'static str) -> Self {
|
||||
Self(name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_str(&self) -> &str {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub(crate) fn into_string(self) -> String {
|
||||
self.as_str().to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use inner::Inner;
|
||||
|
||||
impl Default for Inner {
|
||||
fn default() -> Self {
|
||||
Self::from_static_ref("")
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Inner {
|
||||
fn eq(&self, other: &Inner) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Inner {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Inner {
|
||||
fn cmp(&self, other: &Inner) -> std::cmp::Ordering {
|
||||
self.as_str().cmp(other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Inner {}
|
||||
|
||||
impl std::hash::Hash for Inner {
|
||||
#[inline]
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.as_str().hash(state);
|
||||
}
|
||||
}
|
210
vendor/clap_builder/src/builder/styled_str.rs
vendored
Normal file
210
vendor/clap_builder/src/builder/styled_str.rs
vendored
Normal file
@ -0,0 +1,210 @@
|
||||
#![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)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// // `cstr!` converts tags to ANSI codes
|
||||
/// let after_help: &'static str = color_print::cstr!(
|
||||
/// r#"<bold><underline>Examples</underline></bold>
|
||||
///
|
||||
/// <dim>$</dim> <bold>mybin --input file.toml</bold>
|
||||
/// "#);
|
||||
///
|
||||
/// let cmd = clap::Command::new("mybin")
|
||||
/// .after_help(after_help) // The `&str` gets converted into a `StyledStr`
|
||||
/// // ...
|
||||
/// # ;
|
||||
/// ```
|
||||
#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct StyledStr(String);
|
||||
|
||||
impl StyledStr {
|
||||
/// Create an empty buffer
|
||||
pub const fn new() -> Self {
|
||||
Self(String::new())
|
||||
}
|
||||
|
||||
/// Display using [ANSI Escape Code](https://en.wikipedia.org/wiki/ANSI_escape_code) styling
|
||||
#[cfg(feature = "color")]
|
||||
pub fn ansi(&self) -> impl std::fmt::Display + '_ {
|
||||
self.0.as_str()
|
||||
}
|
||||
|
||||
/// May allow the compiler to consolidate the `Drop`s for `msg`, reducing code size compared to
|
||||
/// `styled.push_str(&msg)`
|
||||
pub(crate) fn push_string(&mut self, msg: String) {
|
||||
self.0.push_str(&msg);
|
||||
}
|
||||
|
||||
pub(crate) fn push_str(&mut self, msg: &str) {
|
||||
self.0.push_str(msg);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn indent(&mut self, initial: &str, trailing: &str) {
|
||||
self.0.insert_str(0, initial);
|
||||
|
||||
let mut line_sep = "\n".to_owned();
|
||||
line_sep.push_str(trailing);
|
||||
self.0 = self.0.replace('\n', &line_sep);
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "wrap_help"), feature = "help"))]
|
||||
pub(crate) fn wrap(&mut self, _hard_width: usize) {}
|
||||
|
||||
#[cfg(feature = "wrap_help")]
|
||||
pub(crate) fn wrap(&mut self, hard_width: usize) {
|
||||
let mut new = String::with_capacity(self.0.len());
|
||||
|
||||
let mut last = 0;
|
||||
let mut wrapper = crate::output::textwrap::wrap_algorithms::LineWrapper::new(hard_width);
|
||||
for content in self.iter_text() {
|
||||
// Preserve styling
|
||||
let current = content.as_ptr() as usize - self.0.as_str().as_ptr() as usize;
|
||||
if last != current {
|
||||
new.push_str(&self.0.as_str()[last..current]);
|
||||
}
|
||||
last = current + content.len();
|
||||
|
||||
for (i, line) in content.split_inclusive('\n').enumerate() {
|
||||
if 0 < i {
|
||||
// reset char count on newline, skipping the start as we might have carried
|
||||
// over from a prior block of styled text
|
||||
wrapper.reset();
|
||||
}
|
||||
let line = crate::output::textwrap::word_separators::find_words_ascii_space(line)
|
||||
.collect::<Vec<_>>();
|
||||
new.extend(wrapper.wrap(line));
|
||||
}
|
||||
}
|
||||
if last != self.0.len() {
|
||||
new.push_str(&self.0.as_str()[last..]);
|
||||
}
|
||||
new = new.trim_end().to_owned();
|
||||
|
||||
self.0 = new;
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn display_width(&self) -> usize {
|
||||
let mut width = 0;
|
||||
for c in self.iter_text() {
|
||||
width += crate::output::display_width(c);
|
||||
}
|
||||
width
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn as_styled_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
pub(crate) fn iter_text(&self) -> impl Iterator<Item = &str> {
|
||||
anstream::adapter::strip_str(&self.0)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "color"))]
|
||||
pub(crate) fn iter_text(&self) -> impl Iterator<Item = &str> {
|
||||
[self.0.as_str()].into_iter()
|
||||
}
|
||||
|
||||
pub(crate) fn push_styled(&mut self, other: &Self) {
|
||||
self.0.push_str(&other.0);
|
||||
}
|
||||
|
||||
pub(crate) fn write_to(&self, buffer: &mut dyn std::io::Write) -> std::io::Result<()> {
|
||||
ok!(buffer.write_all(self.0.as_bytes()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for &'_ StyledStr {
|
||||
fn default() -> Self {
|
||||
static DEFAULT: StyledStr = StyledStr::new();
|
||||
&DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::string::String> for StyledStr {
|
||||
fn from(name: std::string::String) -> Self {
|
||||
StyledStr(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ std::string::String> for StyledStr {
|
||||
fn from(name: &'_ std::string::String) -> Self {
|
||||
let mut styled = StyledStr::new();
|
||||
styled.push_str(name);
|
||||
styled
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for StyledStr {
|
||||
fn from(name: &'static str) -> Self {
|
||||
let mut styled = StyledStr::new();
|
||||
styled.push_str(name);
|
||||
styled
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static str> for StyledStr {
|
||||
fn from(name: &'_ &'static str) -> Self {
|
||||
StyledStr::from(*name)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Write for StyledStr {
|
||||
#[inline]
|
||||
fn write_str(&mut self, s: &str) -> Result<(), std::fmt::Error> {
|
||||
self.0.push_str(s);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_char(&mut self, c: char) -> Result<(), std::fmt::Error> {
|
||||
self.0.push(c);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Color-unaware printing. Never uses coloring.
|
||||
impl std::fmt::Display for StyledStr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
for part in self.iter_text() {
|
||||
part.fmt(f)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
179
vendor/clap_builder/src/builder/styling.rs
vendored
Normal file
179
vendor/clap_builder/src/builder/styling.rs
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
//! Terminal [`Styles`] for help and error output
|
||||
|
||||
pub use anstyle::*;
|
||||
|
||||
/// Terminal styling definitions
|
||||
///
|
||||
/// See also [`Command::styles`][crate::Command::styles].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// clap v3 styling
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::styling::*;
|
||||
/// let styles = Styles::styled()
|
||||
/// .header(AnsiColor::Yellow.on_default())
|
||||
/// .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
|
||||
pub struct Styles {
|
||||
header: anstyle::Style,
|
||||
error: anstyle::Style,
|
||||
usage: anstyle::Style,
|
||||
literal: anstyle::Style,
|
||||
placeholder: anstyle::Style,
|
||||
valid: anstyle::Style,
|
||||
invalid: anstyle::Style,
|
||||
}
|
||||
|
||||
impl Styles {
|
||||
/// No terminal styling
|
||||
pub const fn plain() -> Self {
|
||||
Self {
|
||||
header: anstyle::Style::new(),
|
||||
error: anstyle::Style::new(),
|
||||
usage: anstyle::Style::new(),
|
||||
literal: anstyle::Style::new(),
|
||||
placeholder: anstyle::Style::new(),
|
||||
valid: anstyle::Style::new(),
|
||||
invalid: anstyle::Style::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Default terminal styling
|
||||
pub const fn styled() -> Self {
|
||||
#[cfg(feature = "color")]
|
||||
{
|
||||
Self {
|
||||
header: anstyle::Style::new().bold().underline(),
|
||||
error: anstyle::Style::new()
|
||||
.fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Red)))
|
||||
.bold(),
|
||||
usage: anstyle::Style::new().bold().underline(),
|
||||
literal: anstyle::Style::new().bold(),
|
||||
placeholder: anstyle::Style::new(),
|
||||
valid: anstyle::Style::new()
|
||||
.fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Green))),
|
||||
invalid: anstyle::Style::new()
|
||||
.fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Yellow))),
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "color"))]
|
||||
{
|
||||
Self::plain()
|
||||
}
|
||||
}
|
||||
|
||||
/// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading]
|
||||
#[inline]
|
||||
pub const fn header(mut self, style: anstyle::Style) -> Self {
|
||||
self.header = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Error heading
|
||||
#[inline]
|
||||
pub const fn error(mut self, style: anstyle::Style) -> Self {
|
||||
self.error = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Usage heading
|
||||
#[inline]
|
||||
pub const fn usage(mut self, style: anstyle::Style) -> Self {
|
||||
self.usage = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Literal command-line syntax, e.g. `--help`
|
||||
#[inline]
|
||||
pub const fn literal(mut self, style: anstyle::Style) -> Self {
|
||||
self.literal = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Descriptions within command-line syntax, e.g. [`value_name`][crate::Arg::value_name]
|
||||
#[inline]
|
||||
pub const fn placeholder(mut self, style: anstyle::Style) -> Self {
|
||||
self.placeholder = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Highlight suggested usage
|
||||
#[inline]
|
||||
pub const fn valid(mut self, style: anstyle::Style) -> Self {
|
||||
self.valid = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Highlight invalid usage
|
||||
#[inline]
|
||||
pub const fn invalid(mut self, style: anstyle::Style) -> Self {
|
||||
self.invalid = style;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Reflection
|
||||
impl Styles {
|
||||
/// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading]
|
||||
#[inline(always)]
|
||||
pub const fn get_header(&self) -> &anstyle::Style {
|
||||
&self.header
|
||||
}
|
||||
|
||||
/// Error heading
|
||||
#[inline(always)]
|
||||
pub const fn get_error(&self) -> &anstyle::Style {
|
||||
&self.error
|
||||
}
|
||||
|
||||
/// Usage heading
|
||||
#[inline(always)]
|
||||
pub const fn get_usage(&self) -> &anstyle::Style {
|
||||
&self.usage
|
||||
}
|
||||
|
||||
/// Literal command-line syntax, e.g. `--help`
|
||||
#[inline(always)]
|
||||
pub const fn get_literal(&self) -> &anstyle::Style {
|
||||
&self.literal
|
||||
}
|
||||
|
||||
/// Descriptions within command-line syntax, e.g. [`value_name`][crate::Arg::value_name]
|
||||
#[inline(always)]
|
||||
pub const fn get_placeholder(&self) -> &anstyle::Style {
|
||||
&self.placeholder
|
||||
}
|
||||
|
||||
/// Highlight suggested usage
|
||||
#[inline(always)]
|
||||
pub const fn get_valid(&self) -> &anstyle::Style {
|
||||
&self.valid
|
||||
}
|
||||
|
||||
/// Highlight invalid usage
|
||||
#[inline(always)]
|
||||
pub const fn get_invalid(&self) -> &anstyle::Style {
|
||||
&self.invalid
|
||||
}
|
||||
}
|
||||
|
||||
impl super::AppTag for Styles {}
|
||||
|
||||
impl Default for Styles {
|
||||
fn default() -> Self {
|
||||
Self::styled()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for &'_ Styles {
|
||||
fn default() -> Self {
|
||||
const STYLES: Styles = Styles::styled();
|
||||
&STYLES
|
||||
}
|
||||
}
|
56
vendor/clap_builder/src/builder/tests.rs
vendored
Normal file
56
vendor/clap_builder/src/builder/tests.rs
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
use crate::Arg;
|
||||
use crate::Command;
|
||||
|
||||
#[test]
|
||||
fn propagate_version() {
|
||||
let mut cmd = Command::new("test")
|
||||
.propagate_version(true)
|
||||
.version("1.1")
|
||||
.subcommand(Command::new("sub1"));
|
||||
cmd._propagate();
|
||||
assert_eq!(
|
||||
cmd.get_subcommands().next().unwrap().get_version(),
|
||||
Some("1.1")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn global_setting() {
|
||||
let mut cmd = Command::new("test")
|
||||
.disable_version_flag(true)
|
||||
.subcommand(Command::new("subcmd"));
|
||||
cmd._propagate();
|
||||
assert!(cmd
|
||||
.get_subcommands()
|
||||
.find(|s| s.get_name() == "subcmd")
|
||||
.unwrap()
|
||||
.is_disable_version_flag_set());
|
||||
}
|
||||
|
||||
// This test will *fail to compile* if Command is not Send + Sync
|
||||
#[test]
|
||||
fn app_send_sync() {
|
||||
fn foo<T: Send + Sync>(_: T) {}
|
||||
foo(Command::new("test"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_2090() {
|
||||
let mut cmd = Command::new("cmd")
|
||||
.disable_version_flag(true)
|
||||
.subcommand(Command::new("sub"));
|
||||
cmd._build_self(false);
|
||||
|
||||
assert!(cmd
|
||||
.get_subcommands()
|
||||
.next()
|
||||
.unwrap()
|
||||
.is_disable_version_flag_set());
|
||||
}
|
||||
|
||||
// This test will *fail to compile* if Arg is not Send + Sync
|
||||
#[test]
|
||||
fn arg_send_sync() {
|
||||
fn foo<T: Send + Sync>(_: T) {}
|
||||
foo(Arg::new("test"))
|
||||
}
|
90
vendor/clap_builder/src/builder/value_hint.rs
vendored
Normal file
90
vendor/clap_builder/src/builder/value_hint.rs
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Provide shell with hint on how to complete an argument.
|
||||
///
|
||||
/// See [Arg::value_hint][crate::Arg::value_hint] to set this on an argument.
|
||||
///
|
||||
/// See the `clap_complete` crate for completion script generation.
|
||||
///
|
||||
/// Overview of which hints are supported by which shell:
|
||||
///
|
||||
/// | Hint | zsh | fish[^1]|
|
||||
/// | ---------------------- | --- | ------- |
|
||||
/// | `AnyPath` | Yes | Yes |
|
||||
/// | `FilePath` | Yes | Yes |
|
||||
/// | `DirPath` | Yes | Yes |
|
||||
/// | `ExecutablePath` | Yes | Partial |
|
||||
/// | `CommandName` | Yes | Yes |
|
||||
/// | `CommandString` | Yes | Partial |
|
||||
/// | `CommandWithArguments` | Yes | |
|
||||
/// | `Username` | Yes | Yes |
|
||||
/// | `Hostname` | Yes | Yes |
|
||||
/// | `Url` | Yes | |
|
||||
/// | `EmailAddress` | Yes | |
|
||||
///
|
||||
/// [^1]: fish completions currently only support named arguments (e.g. -o or --opt), not
|
||||
/// positional arguments.
|
||||
#[derive(Debug, Default, PartialEq, Eq, Hash, Copy, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub enum ValueHint {
|
||||
/// Default value if hint is not specified. Follows shell default behavior, which is usually
|
||||
/// auto-completing filenames.
|
||||
#[default]
|
||||
Unknown,
|
||||
/// None of the hints below apply. Disables shell completion for this argument.
|
||||
Other,
|
||||
/// Any existing path.
|
||||
AnyPath,
|
||||
/// Path to a file.
|
||||
FilePath,
|
||||
/// Path to a directory.
|
||||
DirPath,
|
||||
/// Path to an executable file.
|
||||
ExecutablePath,
|
||||
/// Name of a command, without arguments. May be relative to PATH, or full path to executable.
|
||||
CommandName,
|
||||
/// A single string containing a command and its arguments.
|
||||
CommandString,
|
||||
/// Capture the remaining arguments as a command name and arguments for that command. This is
|
||||
/// common when writing shell wrappers that execute anther command, for example `sudo` or `env`.
|
||||
///
|
||||
/// This hint is special, the argument must be a positional argument and have
|
||||
/// [`.num_args(1..)`] and Command must use [`Command::trailing_var_arg(true)`]. The result is that the
|
||||
/// command line `my_app ls -la /` will be parsed as `["ls", "-la", "/"]` and clap won't try to
|
||||
/// parse the `-la` argument itself.
|
||||
///
|
||||
/// [`Command::trailing_var_arg(true)`]: crate::Command::trailing_var_arg
|
||||
/// [`.num_args(1..)`]: crate::Arg::num_args()
|
||||
CommandWithArguments,
|
||||
/// Name of a local operating system user.
|
||||
Username,
|
||||
/// Host name of a computer.
|
||||
/// Shells usually parse `/etc/hosts` and `.ssh/known_hosts` to complete hostnames.
|
||||
Hostname,
|
||||
/// Complete web address.
|
||||
Url,
|
||||
/// Email address.
|
||||
EmailAddress,
|
||||
}
|
||||
|
||||
impl FromStr for ValueHint {
|
||||
type Err = String;
|
||||
fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
|
||||
Ok(match &*s.to_ascii_lowercase() {
|
||||
"unknown" => ValueHint::Unknown,
|
||||
"other" => ValueHint::Other,
|
||||
"anypath" => ValueHint::AnyPath,
|
||||
"filepath" => ValueHint::FilePath,
|
||||
"dirpath" => ValueHint::DirPath,
|
||||
"executablepath" => ValueHint::ExecutablePath,
|
||||
"commandname" => ValueHint::CommandName,
|
||||
"commandstring" => ValueHint::CommandString,
|
||||
"commandwitharguments" => ValueHint::CommandWithArguments,
|
||||
"username" => ValueHint::Username,
|
||||
"hostname" => ValueHint::Hostname,
|
||||
"url" => ValueHint::Url,
|
||||
"emailaddress" => ValueHint::EmailAddress,
|
||||
_ => return Err(format!("unknown ValueHint: `{s}`")),
|
||||
})
|
||||
}
|
||||
}
|
2712
vendor/clap_builder/src/builder/value_parser.rs
vendored
Normal file
2712
vendor/clap_builder/src/builder/value_parser.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user