clap_builder/
macros.rs

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