mirror of
https://github.com/clap-rs/clap
synced 2024-11-14 16:47:21 +00:00
685 lines
19 KiB
Rust
685 lines
19 KiB
Rust
/// Allows you to pull the version from your Cargo.toml at compile time as
|
|
/// `MAJOR.MINOR.PATCH_PKGVERSION_PRE`
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// # #[macro_use]
|
|
/// # extern crate clap;
|
|
/// # use clap::Command;
|
|
/// # fn main() {
|
|
/// let m = Command::new("cmd")
|
|
/// .version(crate_version!())
|
|
/// .get_matches();
|
|
/// # }
|
|
/// ```
|
|
#[cfg(feature = "cargo")]
|
|
#[macro_export]
|
|
macro_rules! crate_version {
|
|
() => {
|
|
env!("CARGO_PKG_VERSION")
|
|
};
|
|
}
|
|
|
|
/// Allows you to pull the authors for the command from your Cargo.toml at
|
|
/// compile time in the form:
|
|
/// `"author1 lastname <author1@example.com>:author2 lastname <author2@example.com>"`
|
|
///
|
|
/// You can replace the colons with a custom separator by supplying a
|
|
/// replacement string, so, for example,
|
|
/// `crate_authors!(",\n")` would become
|
|
/// `"author1 lastname <author1@example.com>,\nauthor2 lastname <author2@example.com>,\nauthor3 lastname <author3@example.com>"`
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// # #[macro_use]
|
|
/// # extern crate clap;
|
|
/// # use clap::Command;
|
|
/// # fn main() {
|
|
/// let m = Command::new("cmd")
|
|
/// .author(crate_authors!("\n"))
|
|
/// .get_matches();
|
|
/// # }
|
|
/// ```
|
|
#[cfg(feature = "cargo")]
|
|
#[macro_export]
|
|
macro_rules! crate_authors {
|
|
($sep:expr) => {{
|
|
static authors: &str = env!("CARGO_PKG_AUTHORS");
|
|
if authors.contains(':') {
|
|
static CACHED: clap::__macro_refs::once_cell::sync::Lazy<String> =
|
|
clap::__macro_refs::once_cell::sync::Lazy::new(|| authors.replace(':', $sep));
|
|
let s: &'static str = &*CACHED;
|
|
s
|
|
} else {
|
|
authors
|
|
}
|
|
}};
|
|
() => {
|
|
env!("CARGO_PKG_AUTHORS")
|
|
};
|
|
}
|
|
|
|
/// Allows you to pull the description from your Cargo.toml at compile time.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// # #[macro_use]
|
|
/// # extern crate clap;
|
|
/// # use clap::Command;
|
|
/// # fn main() {
|
|
/// let m = Command::new("cmd")
|
|
/// .about(crate_description!())
|
|
/// .get_matches();
|
|
/// # }
|
|
/// ```
|
|
#[cfg(feature = "cargo")]
|
|
#[macro_export]
|
|
macro_rules! crate_description {
|
|
() => {
|
|
env!("CARGO_PKG_DESCRIPTION")
|
|
};
|
|
}
|
|
|
|
/// Allows you to pull the name from your Cargo.toml at compile time.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// # #[macro_use]
|
|
/// # extern crate clap;
|
|
/// # use clap::Command;
|
|
/// # fn main() {
|
|
/// let m = Command::new(crate_name!())
|
|
/// .get_matches();
|
|
/// # }
|
|
/// ```
|
|
#[cfg(feature = "cargo")]
|
|
#[macro_export]
|
|
macro_rules! crate_name {
|
|
() => {
|
|
env!("CARGO_PKG_NAME")
|
|
};
|
|
}
|
|
|
|
/// Allows you to build the `Command` instance from your Cargo.toml at compile time.
|
|
///
|
|
/// **NOTE:** Changing the values in your `Cargo.toml` does not trigger a re-build automatically,
|
|
/// and therefore won't change the generated output until you recompile.
|
|
///
|
|
/// In some cases you can "trick" the compiler into triggering a rebuild when your
|
|
/// `Cargo.toml` is changed by including this in your `src/main.rs` file
|
|
/// `include_str!("../Cargo.toml");`
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// # #[macro_use]
|
|
/// # extern crate clap;
|
|
/// # fn main() {
|
|
/// let m = command!().get_matches();
|
|
/// # }
|
|
/// ```
|
|
#[cfg(feature = "cargo")]
|
|
#[macro_export]
|
|
macro_rules! command {
|
|
() => {{
|
|
$crate::command!($crate::crate_name!())
|
|
}};
|
|
($name:expr) => {{
|
|
let mut cmd = $crate::Command::new($name).version($crate::crate_version!());
|
|
|
|
let author = $crate::crate_authors!();
|
|
if !author.is_empty() {
|
|
cmd = cmd.author(author)
|
|
}
|
|
|
|
let about = $crate::crate_description!();
|
|
if !about.is_empty() {
|
|
cmd = cmd.about(about)
|
|
}
|
|
|
|
cmd
|
|
}};
|
|
}
|
|
|
|
/// Requires `cargo` feature flag to be enabled.
|
|
#[cfg(not(feature = "cargo"))]
|
|
#[macro_export]
|
|
macro_rules! command {
|
|
() => {{
|
|
compile_error!("`cargo` feature flag is required");
|
|
}};
|
|
($name:expr) => {{
|
|
compile_error!("`cargo` feature flag is required");
|
|
}};
|
|
}
|
|
|
|
#[doc(hidden)]
|
|
#[macro_export]
|
|
macro_rules! arg_impl {
|
|
( @string $val:ident ) => {
|
|
stringify!($val)
|
|
};
|
|
( @string $val:literal ) => {{
|
|
let ident_or_string_literal: &str = $val;
|
|
ident_or_string_literal
|
|
}};
|
|
( @string $val:tt ) => {
|
|
::std::compile_error!("Only identifiers or string literals supported");
|
|
};
|
|
( @string ) => {
|
|
None
|
|
};
|
|
|
|
( @char $val:ident ) => {{
|
|
let ident_or_char_literal = stringify!($val);
|
|
debug_assert_eq!(
|
|
ident_or_char_literal.len(),
|
|
1,
|
|
"Single-letter identifier expected, got {}",
|
|
ident_or_char_literal
|
|
);
|
|
ident_or_char_literal.chars().next().unwrap()
|
|
}};
|
|
( @char $val:literal ) => {{
|
|
let ident_or_char_literal: char = $val;
|
|
ident_or_char_literal
|
|
}};
|
|
( @char ) => {{
|
|
None
|
|
}};
|
|
|
|
(
|
|
@arg
|
|
($arg:expr)
|
|
--$long:ident
|
|
$($tail:tt)*
|
|
) => {
|
|
$crate::arg_impl! {
|
|
@arg
|
|
({
|
|
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
|
|
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
|
|
|
let mut arg = $arg;
|
|
let long = $crate::arg_impl! { @string $long };
|
|
if arg.get_id() == "" {
|
|
arg = arg.id(long);
|
|
}
|
|
let action = $crate::ArgAction::SetTrue;
|
|
arg
|
|
.long(long)
|
|
.action(action)
|
|
})
|
|
$($tail)*
|
|
}
|
|
};
|
|
(
|
|
@arg
|
|
($arg:expr)
|
|
--$long:literal
|
|
$($tail:tt)*
|
|
) => {
|
|
$crate::arg_impl! {
|
|
@arg
|
|
({
|
|
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
|
|
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
|
|
|
let mut arg = $arg;
|
|
let long = $crate::arg_impl! { @string $long };
|
|
if arg.get_id() == "" {
|
|
arg = arg.id(long);
|
|
}
|
|
let action = $crate::ArgAction::SetTrue;
|
|
arg
|
|
.long(long)
|
|
.action(action)
|
|
})
|
|
$($tail)*
|
|
}
|
|
};
|
|
(
|
|
@arg
|
|
($arg:expr)
|
|
-$short:ident
|
|
$($tail:tt)*
|
|
) => {
|
|
$crate::arg_impl! {
|
|
@arg
|
|
({
|
|
debug_assert_eq!($arg.get_long(), None, "Short flags should precede long flags");
|
|
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
|
|
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
|
|
|
let action = $crate::ArgAction::SetTrue;
|
|
$arg
|
|
.short($crate::arg_impl! { @char $short })
|
|
.action(action)
|
|
})
|
|
$($tail)*
|
|
}
|
|
};
|
|
(
|
|
@arg
|
|
($arg:expr)
|
|
-$short:literal
|
|
$($tail:tt)*
|
|
) => {
|
|
$crate::arg_impl! {
|
|
@arg
|
|
({
|
|
debug_assert_eq!($arg.get_long(), None, "Short flags should precede long flags");
|
|
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
|
|
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
|
|
|
let action = $crate::ArgAction::SetTrue;
|
|
$arg
|
|
.short($crate::arg_impl! { @char $short })
|
|
.action(action)
|
|
})
|
|
$($tail)*
|
|
}
|
|
};
|
|
(
|
|
@arg
|
|
($arg:expr)
|
|
<$value_name:ident>
|
|
$($tail:tt)*
|
|
) => {
|
|
$crate::arg_impl! {
|
|
@arg
|
|
({
|
|
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
|
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
|
|
|
|
let mut arg = $arg;
|
|
|
|
if arg.get_long().is_none() && arg.get_short().is_none() {
|
|
arg = arg.required(true);
|
|
}
|
|
|
|
let value_name = $crate::arg_impl! { @string $value_name };
|
|
if arg.get_id() == "" {
|
|
arg = arg.id(value_name);
|
|
}
|
|
arg
|
|
.value_name(value_name)
|
|
.action($crate::ArgAction::Set)
|
|
})
|
|
$($tail)*
|
|
}
|
|
};
|
|
(
|
|
@arg
|
|
($arg:expr)
|
|
<$value_name:literal>
|
|
$($tail:tt)*
|
|
) => {
|
|
$crate::arg_impl! {
|
|
@arg
|
|
({
|
|
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
|
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
|
|
|
|
let mut arg = $arg;
|
|
|
|
if arg.get_long().is_none() && arg.get_short().is_none() {
|
|
arg = arg.required(true);
|
|
}
|
|
|
|
let value_name = $crate::arg_impl! { @string $value_name };
|
|
if arg.get_id() == "" {
|
|
arg = arg.id(value_name);
|
|
}
|
|
arg
|
|
.value_name(value_name)
|
|
.action($crate::ArgAction::Set)
|
|
})
|
|
$($tail)*
|
|
}
|
|
};
|
|
(
|
|
@arg
|
|
($arg:expr)
|
|
[$value_name:ident]
|
|
$($tail:tt)*
|
|
) => {
|
|
$crate::arg_impl! {
|
|
@arg
|
|
({
|
|
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
|
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
|
|
|
|
let mut arg = $arg;
|
|
|
|
if arg.get_long().is_none() && arg.get_short().is_none() {
|
|
arg = arg.required(false);
|
|
} else {
|
|
arg = arg.num_args(0..=1);
|
|
}
|
|
|
|
let value_name = $crate::arg_impl! { @string $value_name };
|
|
if arg.get_id() == "" {
|
|
arg = arg.id(value_name);
|
|
}
|
|
arg
|
|
.value_name(value_name)
|
|
.action($crate::ArgAction::Set)
|
|
})
|
|
$($tail)*
|
|
}
|
|
};
|
|
(
|
|
@arg
|
|
($arg:expr)
|
|
[$value_name:literal]
|
|
$($tail:tt)*
|
|
) => {
|
|
$crate::arg_impl! {
|
|
@arg
|
|
({
|
|
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
|
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
|
|
|
|
let mut arg = $arg;
|
|
|
|
if arg.get_long().is_none() && arg.get_short().is_none() {
|
|
arg = arg.required(false);
|
|
} else {
|
|
arg = arg.num_args(0..=1);
|
|
}
|
|
|
|
let value_name = $crate::arg_impl! { @string $value_name };
|
|
if arg.get_id() == "" {
|
|
arg = arg.id(value_name);
|
|
}
|
|
arg
|
|
.value_name(value_name)
|
|
.action($crate::ArgAction::Set)
|
|
})
|
|
$($tail)*
|
|
}
|
|
};
|
|
(
|
|
@arg
|
|
($arg:expr)
|
|
...
|
|
$($tail:tt)*
|
|
) => {
|
|
$crate::arg_impl! {
|
|
@arg
|
|
({
|
|
match $arg.get_action() {
|
|
$crate::ArgAction::Set => {
|
|
if $arg.get_long().is_none() && $arg.get_short().is_none() {
|
|
$arg.num_args(1..)
|
|
// Allow collecting arguments interleaved with flags
|
|
.action($crate::ArgAction::Append)
|
|
} else {
|
|
$arg.action($crate::ArgAction::Append)
|
|
}
|
|
},
|
|
$crate::ArgAction::SetTrue | $crate::ArgAction::Help | $crate::ArgAction::Version => {
|
|
$arg.action($crate::ArgAction::Count)
|
|
}
|
|
action => {
|
|
panic!("Unexpected action {:?}", action)
|
|
}
|
|
}
|
|
})
|
|
$($tail)*
|
|
}
|
|
};
|
|
(
|
|
@arg
|
|
($arg:expr)
|
|
$help:literal
|
|
) => {
|
|
$arg.help($help)
|
|
};
|
|
(
|
|
@arg
|
|
($arg:expr)
|
|
) => {
|
|
$arg
|
|
};
|
|
}
|
|
|
|
/// Create an [`Arg`] from a usage string.
|
|
///
|
|
/// Allows creation of basic settings for the [`Arg`].
|
|
///
|
|
/// **NOTE**: Not all settings may be set using the usage string method. Some properties are
|
|
/// only available via the builder pattern.
|
|
///
|
|
/// # Syntax
|
|
///
|
|
/// Usage strings typically following the form:
|
|
///
|
|
/// ```notrust
|
|
/// [explicit name] [short] [long] [value names] [...] [help string]
|
|
/// ```
|
|
///
|
|
/// ### Explicit Name
|
|
///
|
|
/// The name may be either a bare-word or a string, followed by a `:`, like `name:` or
|
|
/// `"name":`.
|
|
///
|
|
/// *Note:* This is an optional field, if it's omitted the argument will use one of the additional
|
|
/// fields as the name using the following priority order:
|
|
///
|
|
/// 1. Explicit Name
|
|
/// 2. Long
|
|
/// 3. Value Name
|
|
///
|
|
/// See [`Arg::id`][crate::Arg::id].
|
|
///
|
|
/// ### Short
|
|
///
|
|
/// A short flag is a `-` followed by either a bare-character or quoted character, like `-f` or
|
|
/// `-'f'`.
|
|
///
|
|
/// See [`Arg::short`][crate::Arg::short].
|
|
///
|
|
/// ### Long
|
|
///
|
|
/// A long flag is a `--` followed by either a bare-word or a string, like `--foo` or
|
|
/// `--"foo"`.
|
|
///
|
|
/// **NOTE:** Dashes in the long name (e.g. `--foo-bar`) is not supported and quoting is required
|
|
/// (e.g. `--"foo-bar"`).
|
|
///
|
|
/// See [`Arg::long`][crate::Arg::long].
|
|
///
|
|
/// ### Values (Value Notation)
|
|
///
|
|
/// This is set by placing bare-word between:
|
|
/// - `[]` like `[FOO]`
|
|
/// - Positional argument: optional
|
|
/// - Named argument: optional value
|
|
/// - `<>` like `<FOO>`: required
|
|
///
|
|
/// See [`Arg::value_name`][crate::Arg::value_name].
|
|
///
|
|
/// ### `...`
|
|
///
|
|
/// `...` (three consecutive dots/periods) specifies that this argument may occur multiple
|
|
/// times (not to be confused with multiple values per occurrence).
|
|
///
|
|
/// See [`ArgAction::Count`][crate::ArgAction::Count] and [`ArgAction::Append`][crate::ArgAction::Append].
|
|
///
|
|
/// ### Help String
|
|
///
|
|
/// The help string is denoted between a pair of double quotes `""` and may contain any
|
|
/// characters.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```rust
|
|
/// # use clap::{Command, Arg, arg};
|
|
/// let cmd = Command::new("prog")
|
|
/// .args(&[
|
|
/// arg!(--config <FILE> "a required file for the configuration and no short"),
|
|
/// arg!(-d --debug ... "turns on debugging information and allows multiples"),
|
|
/// arg!([input] "an optional input file to use")
|
|
/// ]);
|
|
///
|
|
/// let m = cmd.try_get_matches_from(["prog", "--config", "file.toml"]).unwrap();
|
|
/// assert_eq!(m.get_one::<String>("config").unwrap(), "file.toml");
|
|
/// assert_eq!(*m.get_one::<u8>("debug").unwrap(), 0);
|
|
/// assert_eq!(m.get_one::<String>("input"), None);
|
|
/// ```
|
|
/// [`Arg`]: crate::Arg
|
|
#[macro_export]
|
|
macro_rules! arg {
|
|
( $name:ident: $($tail:tt)+ ) => {
|
|
$crate::arg_impl! {
|
|
@arg ($crate::Arg::new($crate::arg_impl! { @string $name })) $($tail)+
|
|
}
|
|
};
|
|
( $($tail:tt)+ ) => {{
|
|
let arg = $crate::arg_impl! {
|
|
@arg ($crate::Arg::default()) $($tail)+
|
|
};
|
|
debug_assert_ne!(arg.get_id(), "", "Without a value or long flag, the `name:` prefix is required");
|
|
arg
|
|
}};
|
|
}
|
|
|
|
macro_rules! impl_settings {
|
|
($settings:ident, $flags:ident,
|
|
$(
|
|
$(#[$inner:ident $($args:tt)*])*
|
|
$setting:ident => $flag:path
|
|
),+
|
|
) => {
|
|
impl $flags {
|
|
#[allow(dead_code)]
|
|
pub(crate) fn empty() -> Self {
|
|
$flags(Flags::empty())
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub(crate) fn insert(&mut self, rhs: Self) {
|
|
self.0.insert(rhs.0);
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub(crate) fn remove(&mut self, rhs: Self) {
|
|
self.0.remove(rhs.0);
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub(crate) fn set(&mut self, s: $settings) {
|
|
match s {
|
|
$(
|
|
$(#[$inner $($args)*])*
|
|
$settings::$setting => self.0.insert($flag),
|
|
)*
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub(crate) fn unset(&mut self, s: $settings) {
|
|
match s {
|
|
$(
|
|
$(#[$inner $($args)*])*
|
|
$settings::$setting => self.0.remove($flag),
|
|
)*
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub(crate) fn is_set(&self, s: $settings) -> bool {
|
|
match s {
|
|
$(
|
|
$(#[$inner $($args)*])*
|
|
$settings::$setting => self.0.contains($flag),
|
|
)*
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BitOr for $flags {
|
|
type Output = Self;
|
|
|
|
fn bitor(mut self, rhs: Self) -> Self::Output {
|
|
self.0.insert(rhs.0);
|
|
self
|
|
}
|
|
}
|
|
|
|
impl From<$settings> for $flags {
|
|
fn from(setting: $settings) -> Self {
|
|
let mut flags = $flags::empty();
|
|
flags.set(setting);
|
|
flags
|
|
}
|
|
}
|
|
|
|
impl BitOr<$settings> for $flags {
|
|
type Output = Self;
|
|
|
|
fn bitor(mut self, rhs: $settings) -> Self::Output {
|
|
self.set(rhs);
|
|
self
|
|
}
|
|
}
|
|
|
|
impl BitOr for $settings {
|
|
type Output = $flags;
|
|
|
|
fn bitor(self, rhs: Self) -> Self::Output {
|
|
let mut flags = $flags::empty();
|
|
flags.set(self);
|
|
flags.set(rhs);
|
|
flags
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "debug")]
|
|
macro_rules! debug {
|
|
($($arg:tt)*) => ({
|
|
let prefix = format!("[{:>w$}] \t", module_path!(), w = 28);
|
|
let body = format!($($arg)*);
|
|
let mut styled = $crate::builder::StyledStr::new();
|
|
styled.hint(prefix);
|
|
styled.hint(body);
|
|
styled.none("\n");
|
|
let color = $crate::output::fmt::Colorizer::new($crate::output::fmt::Stream::Stderr, $crate::ColorChoice::Auto).with_content(styled);
|
|
let _ = color.print();
|
|
})
|
|
}
|
|
|
|
#[cfg(not(feature = "debug"))]
|
|
macro_rules! debug {
|
|
($($arg:tt)*) => {};
|
|
}
|
|
|
|
macro_rules! ok {
|
|
($expr:expr) => {
|
|
match $expr {
|
|
Ok(val) => val,
|
|
Err(err) => {
|
|
return Err(err);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
macro_rules! some {
|
|
($expr:expr) => {
|
|
match $expr {
|
|
Some(val) => val,
|
|
None => {
|
|
return None;
|
|
}
|
|
}
|
|
};
|
|
}
|