xref: /third_party/rust/crates/clap/src/macros.rs (revision 19625d8c)
1/// Allows you to pull the version from your Cargo.toml at compile time as
2/// `MAJOR.MINOR.PATCH_PKGVERSION_PRE`
3///
4/// # Examples
5///
6/// ```no_run
7/// # #[macro_use]
8/// # extern crate clap;
9/// # use clap::Command;
10/// # fn main() {
11/// let m = Command::new("cmd")
12///             .version(crate_version!())
13///             .get_matches();
14/// # }
15/// ```
16#[cfg(feature = "cargo")]
17#[macro_export]
18macro_rules! crate_version {
19    () => {
20        env!("CARGO_PKG_VERSION")
21    };
22}
23
24/// Allows you to pull the authors for the command from your Cargo.toml at
25/// compile time in the form:
26/// `"author1 lastname <author1@example.com>:author2 lastname <author2@example.com>"`
27///
28/// You can replace the colons with a custom separator by supplying a
29/// replacement string, so, for example,
30/// `crate_authors!(",\n")` would become
31/// `"author1 lastname <author1@example.com>,\nauthor2 lastname <author2@example.com>,\nauthor3 lastname <author3@example.com>"`
32///
33/// # Examples
34///
35/// ```no_run
36/// # #[macro_use]
37/// # extern crate clap;
38/// # use clap::Command;
39/// # fn main() {
40/// let m = Command::new("cmd")
41///             .author(crate_authors!("\n"))
42///             .get_matches();
43/// # }
44/// ```
45#[cfg(feature = "cargo")]
46#[macro_export]
47macro_rules! crate_authors {
48    ($sep:expr) => {{
49        static authors: &str = env!("CARGO_PKG_AUTHORS");
50        if authors.contains(':') {
51            static CACHED: clap::__macro_refs::once_cell::sync::Lazy<String> =
52                clap::__macro_refs::once_cell::sync::Lazy::new(|| authors.replace(':', $sep));
53            let s: &'static str = &*CACHED;
54            s
55        } else {
56            authors
57        }
58    }};
59    () => {
60        env!("CARGO_PKG_AUTHORS")
61    };
62}
63
64/// Allows you to pull the description from your Cargo.toml at compile time.
65///
66/// # Examples
67///
68/// ```no_run
69/// # #[macro_use]
70/// # extern crate clap;
71/// # use clap::Command;
72/// # fn main() {
73/// let m = Command::new("cmd")
74///             .about(crate_description!())
75///             .get_matches();
76/// # }
77/// ```
78#[cfg(feature = "cargo")]
79#[macro_export]
80macro_rules! crate_description {
81    () => {
82        env!("CARGO_PKG_DESCRIPTION")
83    };
84}
85
86/// Allows you to pull the name from your Cargo.toml at compile time.
87///
88/// **NOTE:** This macro extracts the name from an environment variable `CARGO_PKG_NAME`.
89/// When the crate name is set to something different from the package name,
90/// use environment variables `CARGO_CRATE_NAME` or `CARGO_BIN_NAME`.
91/// See [the Cargo Book](https://doc.rust-lang.org/cargo/reference/environment-variables.html)
92/// for more information.
93///
94/// # Examples
95///
96/// ```no_run
97/// # #[macro_use]
98/// # extern crate clap;
99/// # use clap::Command;
100/// # fn main() {
101/// let m = Command::new(crate_name!())
102///             .get_matches();
103/// # }
104/// ```
105#[cfg(feature = "cargo")]
106#[macro_export]
107macro_rules! crate_name {
108    () => {
109        env!("CARGO_PKG_NAME")
110    };
111}
112
113/// Allows you to build the `Command` instance from your Cargo.toml at compile time.
114///
115/// **NOTE:** Changing the values in your `Cargo.toml` does not trigger a re-build automatically,
116/// and therefore won't change the generated output until you recompile.
117///
118/// In some cases you can "trick" the compiler into triggering a rebuild when your
119/// `Cargo.toml` is changed by including this in your `src/main.rs` file
120/// `include_str!("../Cargo.toml");`
121///
122/// # Examples
123///
124/// ```no_run
125/// # #[macro_use]
126/// # extern crate clap;
127/// # fn main() {
128/// let m = command!().get_matches();
129/// # }
130/// ```
131#[cfg(feature = "cargo")]
132#[macro_export]
133macro_rules! command {
134    () => {{
135        $crate::command!($crate::crate_name!())
136    }};
137    ($name:expr) => {{
138        let mut cmd = $crate::Command::new($name).version($crate::crate_version!());
139
140        let author = $crate::crate_authors!();
141        if !author.is_empty() {
142            cmd = cmd.author(author)
143        }
144
145        let about = $crate::crate_description!();
146        if !about.is_empty() {
147            cmd = cmd.about(about)
148        }
149
150        cmd
151    }};
152}
153
154/// Requires `cargo` feature flag to be enabled.
155#[cfg(not(feature = "cargo"))]
156#[macro_export]
157macro_rules! command {
158    () => {{
159        compile_error!("`cargo` feature flag is required");
160    }};
161    ($name:expr) => {{
162        compile_error!("`cargo` feature flag is required");
163    }};
164}
165
166#[doc(hidden)]
167#[macro_export]
168macro_rules! arg_impl {
169    ( @string $val:ident ) => {
170        stringify!($val)
171    };
172    ( @string $val:literal ) => {{
173        let ident_or_string_literal: &str = $val;
174        ident_or_string_literal
175    }};
176    ( @string $val:tt ) => {
177        ::std::compile_error!("Only identifiers or string literals supported");
178    };
179    ( @string ) => {
180        None
181    };
182
183    ( @char $val:ident ) => {{
184        let ident_or_char_literal = stringify!($val);
185        debug_assert_eq!(
186            ident_or_char_literal.len(),
187            1,
188            "Single-letter identifier expected, got {}",
189            ident_or_char_literal
190        );
191        ident_or_char_literal.chars().next().unwrap()
192    }};
193    ( @char $val:literal ) => {{
194        let ident_or_char_literal: char = $val;
195        ident_or_char_literal
196    }};
197    ( @char ) => {{
198        None
199    }};
200
201    (
202        @arg
203        ($arg:expr)
204        --$long:ident
205        $($tail:tt)*
206    ) => {{
207        debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
208        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
209
210        let mut arg = $arg;
211        let long = $crate::arg_impl! { @string $long };
212        if arg.get_id() == "" {
213            arg = arg.id(long);
214        }
215        let action = $crate::ArgAction::SetTrue;
216        let arg = arg
217            .long(long)
218            .action(action);
219        let arg = $crate::arg_impl! {
220            @arg (arg) $($tail)*
221        };
222        arg
223    }};
224    (
225        @arg
226        ($arg:expr)
227        --$long:literal
228        $($tail:tt)*
229    ) => {{
230        debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
231        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
232
233        let mut arg = $arg;
234        let long = $crate::arg_impl! { @string $long };
235        if arg.get_id() == "" {
236            arg = arg.id(long);
237        }
238        let action = $crate::ArgAction::SetTrue;
239        let arg = arg
240            .long(long)
241            .action(action);
242        let arg = $crate::arg_impl! {
243            @arg (arg) $($tail)*
244        };
245        arg
246    }};
247    (
248        @arg
249        ($arg:expr)
250        -$short:ident
251        $($tail:tt)*
252    ) => {{
253        debug_assert_eq!($arg.get_long(), None, "Short flags should precede long flags");
254        debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
255        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
256
257        let action = $crate::ArgAction::SetTrue;
258        let arg = $arg
259            .short($crate::arg_impl! { @char $short })
260            .action(action);
261        let arg = $crate::arg_impl! {
262            @arg (arg) $($tail)*
263        };
264        arg
265    }};
266    (
267        @arg
268        ($arg:expr)
269        -$short:literal
270        $($tail:tt)*
271    ) => {{
272        debug_assert_eq!($arg.get_long(), None, "Short flags should precede long flags");
273        debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
274        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
275
276        let action = $crate::ArgAction::SetTrue;
277        let arg = $arg
278            .short($crate::arg_impl! { @char $short })
279            .action(action);
280        let arg = $crate::arg_impl! {
281            @arg (arg) $($tail)*
282        };
283        arg
284    }};
285    (
286        @arg
287        ($arg:expr)
288        <$value_name:ident>
289        $($tail:tt)*
290    ) => {{
291        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
292        debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
293
294        let mut arg = $arg;
295
296        if arg.get_long().is_none() && arg.get_short().is_none() {
297            arg = arg.required(true);
298        }
299
300        let value_name = $crate::arg_impl! { @string $value_name };
301        if arg.get_id() == "" {
302            arg = arg.id(value_name);
303        }
304        let arg = arg
305            .value_name(value_name)
306            .action($crate::ArgAction::Set);
307        let arg = $crate::arg_impl! {
308            @arg (arg) $($tail)*
309        };
310        arg
311    }};
312    (
313        @arg
314        ($arg:expr)
315        <$value_name:literal>
316        $($tail:tt)*
317    ) => {{
318        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
319        debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
320
321        let mut arg = $arg;
322
323        if arg.get_long().is_none() && arg.get_short().is_none() {
324            arg = arg.required(true);
325        }
326
327        let value_name = $crate::arg_impl! { @string $value_name };
328        if arg.get_id() == "" {
329            arg = arg.id(value_name);
330        }
331        let arg = arg
332            .value_name(value_name)
333            .action($crate::ArgAction::Set);
334        let arg = $crate::arg_impl! {
335            @arg (arg) $($tail)*
336        };
337        arg
338    }};
339    (
340        @arg
341        ($arg:expr)
342        [$value_name:ident]
343        $($tail:tt)*
344    ) => {{
345        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
346        debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
347
348        let mut arg = $arg;
349
350        if arg.get_long().is_none() && arg.get_short().is_none() {
351            arg = arg.required(false);
352        } else {
353            arg = arg.num_args(0..=1);
354        }
355
356        let value_name = $crate::arg_impl! { @string $value_name };
357        if arg.get_id() == "" {
358            arg = arg.id(value_name);
359        }
360        let arg = arg
361            .value_name(value_name)
362            .action($crate::ArgAction::Set);
363        let arg = $crate::arg_impl! {
364            @arg (arg) $($tail)*
365        };
366        arg
367    }};
368    (
369        @arg
370        ($arg:expr)
371        [$value_name:literal]
372        $($tail:tt)*
373    ) => {{
374        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
375        debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
376
377        let mut arg = $arg;
378
379        if arg.get_long().is_none() && arg.get_short().is_none() {
380            arg = arg.required(false);
381        } else {
382            arg = arg.num_args(0..=1);
383        }
384
385        let value_name = $crate::arg_impl! { @string $value_name };
386        if arg.get_id() == "" {
387            arg = arg.id(value_name);
388        }
389        let arg = arg
390            .value_name(value_name)
391            .action($crate::ArgAction::Set);
392        let arg = $crate::arg_impl! {
393            @arg (arg) $($tail)*
394        };
395        arg
396    }};
397    (
398        @arg
399        ($arg:expr)
400        ...
401        $($tail:tt)*
402    ) => {{
403        let arg = match $arg.get_action() {
404            $crate::ArgAction::Set => {
405                if $arg.get_long().is_none() && $arg.get_short().is_none() {
406                    $arg.num_args(1..)
407                        // Allow collecting arguments interleaved with flags
408                        .action($crate::ArgAction::Append)
409                } else {
410                    $arg.action($crate::ArgAction::Append)
411                }
412            },
413            $crate::ArgAction::SetTrue | $crate::ArgAction::Help | $crate::ArgAction::Version => {
414                $arg.action($crate::ArgAction::Count)
415            }
416            action => {
417                panic!("Unexpected action {:?}", action)
418            }
419        };
420        let arg = $crate::arg_impl! {
421            @arg (arg) $($tail)*
422        };
423        arg
424    }};
425    (
426        @arg
427        ($arg:expr)
428        $help:literal
429    ) => {{
430        $arg.help($help)
431    }};
432    (
433        @arg
434        ($arg:expr)
435    ) => {{
436        $arg
437    }};
438}
439
440/// Create an [`Arg`] from a usage string.
441///
442/// Allows creation of basic settings for the [`Arg`].
443///
444/// **NOTE**: Not all settings may be set using the usage string method. Some properties are
445/// only available via the builder pattern.
446///
447/// # Syntax
448///
449/// Usage strings typically following the form:
450///
451/// ```notrust
452/// [explicit name] [short] [long] [value names] [...] [help string]
453/// ```
454///
455/// ### Explicit Name
456///
457/// The name may be either a bare-word or a string, followed by a `:`, like `name:` or
458/// `"name":`.
459///
460/// *Note:* This is an optional field, if it's omitted the argument will use one of the additional
461/// fields as the name using the following priority order:
462///
463///  1. Explicit Name
464///  2. Long
465///  3. Value Name
466///
467/// See [`Arg::id`][crate::Arg::id].
468///
469/// ### Short
470///
471/// A short flag is a `-` followed by either a bare-character or quoted character, like `-f` or
472/// `-'f'`.
473///
474/// See [`Arg::short`][crate::Arg::short].
475///
476/// ### Long
477///
478/// A long flag is a `--` followed by either a bare-word or a string, like `--foo` or
479/// `--"foo"`.
480///
481/// **NOTE:** Dashes in the long name (e.g. `--foo-bar`) is not supported and quoting is required
482/// (e.g. `--"foo-bar"`).
483///
484/// See [`Arg::long`][crate::Arg::long].
485///
486/// ### Values (Value Notation)
487///
488/// This is set by placing bare-word between:
489/// - `[]` like `[FOO]`
490///   - Positional argument: optional
491///   - Named argument: optional value
492/// - `<>` like `<FOO>`: required
493///
494/// See [`Arg::value_name`][crate::Arg::value_name].
495///
496/// ### `...`
497///
498/// `...` (three consecutive dots/periods) specifies that this argument may occur multiple
499/// times (not to be confused with multiple values per occurrence).
500///
501/// See [`ArgAction::Count`][crate::ArgAction::Count] and [`ArgAction::Append`][crate::ArgAction::Append].
502///
503/// ### Help String
504///
505/// The help string is denoted between a pair of double quotes `""` and may contain any
506/// characters.
507///
508/// # Examples
509///
510/// ```rust
511/// # use clap::{Command, Arg, arg};
512/// let cmd = Command::new("prog")
513///     .args(&[
514///         arg!(--config <FILE> "a required file for the configuration and no short"),
515///         arg!(-d --debug ... "turns on debugging information and allows multiples"),
516///         arg!([input] "an optional input file to use")
517///     ]);
518///
519/// let m = cmd.try_get_matches_from(["prog", "--config", "file.toml"]).unwrap();
520/// assert_eq!(m.get_one::<String>("config").unwrap(), "file.toml");
521/// assert_eq!(*m.get_one::<u8>("debug").unwrap(), 0);
522/// assert_eq!(m.get_one::<String>("input"), None);
523/// ```
524/// [`Arg`]: crate::Arg
525#[macro_export]
526macro_rules! arg {
527    ( $name:ident: $($tail:tt)+ ) => {{
528        let arg = $crate::Arg::new($crate::arg_impl! { @string $name });
529        let arg = $crate::arg_impl! {
530            @arg (arg) $($tail)+
531        };
532        arg
533    }};
534    ( $($tail:tt)+ ) => {{
535        let arg = $crate::Arg::default();
536        let arg = $crate::arg_impl! {
537            @arg (arg) $($tail)+
538        };
539        debug_assert_ne!(arg.get_id(), "", "Without a value or long flag, the `name:` prefix is required");
540        arg
541    }};
542}
543
544macro_rules! impl_settings {
545    ($settings:ident, $flags:ident,
546        $(
547            $(#[$inner:ident $($args:tt)*])*
548            $setting:ident => $flag:path
549        ),+
550    ) => {
551        impl $flags {
552            #[allow(dead_code)]
553            pub(crate) fn empty() -> Self {
554                $flags(Flags::empty())
555            }
556
557            #[allow(dead_code)]
558            pub(crate) fn insert(&mut self, rhs: Self) {
559                self.0.insert(rhs.0);
560            }
561
562            #[allow(dead_code)]
563            pub(crate) fn remove(&mut self, rhs: Self) {
564                self.0.remove(rhs.0);
565            }
566
567            #[allow(dead_code)]
568            pub(crate) fn set(&mut self, s: $settings) {
569                match s {
570                    $(
571                        $(#[$inner $($args)*])*
572                        $settings::$setting => self.0.insert($flag),
573                    )*
574                }
575            }
576
577            #[allow(dead_code)]
578            pub(crate) fn unset(&mut self, s: $settings) {
579                match s {
580                    $(
581                        $(#[$inner $($args)*])*
582                        $settings::$setting => self.0.remove($flag),
583                    )*
584                }
585            }
586
587            #[allow(dead_code)]
588            pub(crate) fn is_set(&self, s: $settings) -> bool {
589                match s {
590                    $(
591                        $(#[$inner $($args)*])*
592                        $settings::$setting => self.0.contains($flag),
593                    )*
594                }
595            }
596        }
597
598        impl BitOr for $flags {
599            type Output = Self;
600
601            fn bitor(mut self, rhs: Self) -> Self::Output {
602                self.0.insert(rhs.0);
603                self
604            }
605        }
606
607        impl From<$settings> for $flags {
608            fn from(setting: $settings) -> Self {
609                let mut flags = $flags::empty();
610                flags.set(setting);
611                flags
612            }
613        }
614
615        impl BitOr<$settings> for $flags {
616            type Output = Self;
617
618            fn bitor(mut self, rhs: $settings) -> Self::Output {
619                self.set(rhs);
620                self
621            }
622        }
623
624        impl BitOr for $settings {
625            type Output = $flags;
626
627            fn bitor(self, rhs: Self) -> Self::Output {
628                let mut flags = $flags::empty();
629                flags.set(self);
630                flags.set(rhs);
631                flags
632            }
633        }
634    }
635}
636
637#[cfg(feature = "debug")]
638macro_rules! debug {
639    ($($arg:tt)*) => ({
640        let prefix = format!("[{:>w$}] \t", module_path!(), w = 28);
641        let body = format!($($arg)*);
642        let mut styled = $crate::builder::StyledStr::new();
643        styled.hint(prefix);
644        styled.hint(body);
645        styled.none("\n");
646        let color = $crate::output::fmt::Colorizer::new($crate::output::fmt::Stream::Stderr, $crate::ColorChoice::Auto).with_content(styled);
647        let _ = color.print();
648    })
649}
650
651#[cfg(not(feature = "debug"))]
652macro_rules! debug {
653    ($($arg:tt)*) => {};
654}
655
656macro_rules! ok {
657    ($expr:expr) => {
658        match $expr {
659            Ok(val) => val,
660            Err(err) => {
661                return Err(err);
662            }
663        }
664    };
665}
666
667macro_rules! some {
668    ($expr:expr) => {
669        match $expr {
670            Some(val) => val,
671            None => {
672                return None;
673            }
674        }
675    };
676}
677