Initial vendor packages

Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
2024-01-08 01:21:28 +04:00
parent 5ecd8cf2cb
commit 1b6a04ca55
7309 changed files with 2160054 additions and 0 deletions

View 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;

View 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

File diff suppressed because it is too large Load Diff

View 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]);
}
}
}

View 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())
}
}

View 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

File diff suppressed because it is too large Load Diff

View 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
View 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
View 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;

View 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);
}
}

View 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
View 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());
}
}

View 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
View 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);
}
}

View 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(())
}
}

View 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
}
}

View 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"))
}

View 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}`")),
})
}
}

File diff suppressed because it is too large Load Diff