Skip to main content

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    () => {{ $crate::command!($crate::crate_name!()) }};
133    ($name:expr) => {{
134        let mut cmd = $crate::Command::new($name).version($crate::crate_version!());
135
136        let author = $crate::crate_authors!();
137        if !author.is_empty() {
138            cmd = cmd.author(author)
139        }
140
141        let about = $crate::crate_description!();
142        if !about.is_empty() {
143            cmd = cmd.about(about)
144        }
145
146        cmd
147    }};
148}
149
150/// Requires `cargo` feature flag to be enabled.
151#[cfg(not(feature = "cargo"))]
152#[macro_export]
153macro_rules! command {
154    () => {{
155        compile_error!("`cargo` feature flag is required");
156    }};
157    ($name:expr) => {{
158        compile_error!("`cargo` feature flag is required");
159    }};
160}
161
162#[doc(hidden)]
163#[macro_export]
164macro_rules! arg_impl {
165    ( @string $val:ident ) => {
166        stringify!($val)
167    };
168    ( @string $val:literal ) => {{
169        let ident_or_string_literal: &str = $val;
170        ident_or_string_literal
171    }};
172    ( @string $val:tt ) => {
173        ::std::compile_error!("Only identifiers or string literals supported");
174    };
175    ( @string ) => {
176        None
177    };
178
179    ( @char $val:ident ) => {{
180        let ident_or_char_literal = stringify!($val);
181        debug_assert_eq!(
182            ident_or_char_literal.len(),
183            1,
184            "Single-letter identifier expected, got {ident_or_char_literal}",
185        );
186        ident_or_char_literal.chars().next().unwrap()
187    }};
188    ( @char $val:literal ) => {{
189        let ident_or_char_literal: char = $val;
190        ident_or_char_literal
191    }};
192    ( @char ) => {{
193        None
194    }};
195
196    (
197        @arg
198        ($arg:expr)
199        --$long:ident
200        $($tail:tt)*
201    ) => {{
202        debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
203        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
204
205        let mut arg = $arg;
206        let long = $crate::arg_impl! { @string $long };
207        if arg.get_id() == "" {
208            arg = arg.id(long);
209        }
210        let action = $crate::ArgAction::SetTrue;
211        let arg = arg
212            .long(long)
213            .action(action);
214        let arg = $crate::arg_impl! {
215            @arg (arg) $($tail)*
216        };
217        arg
218    }};
219    (
220        @arg
221        ($arg:expr)
222        --$long:literal
223        $($tail:tt)*
224    ) => {{
225        debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
226        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
227
228        let mut arg = $arg;
229        let long = $crate::arg_impl! { @string $long };
230        if arg.get_id() == "" {
231            arg = arg.id(long);
232        }
233        let action = $crate::ArgAction::SetTrue;
234        let arg = arg
235            .long(long)
236            .action(action);
237        let arg = $crate::arg_impl! {
238            @arg (arg) $($tail)*
239        };
240        arg
241    }};
242    (
243        @arg
244        ($arg:expr)
245        -$short:ident
246        $($tail:tt)*
247    ) => {{
248        debug_assert_eq!($arg.get_long(), None, "Short flags should precede long flags");
249        debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
250        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
251
252        let action = $crate::ArgAction::SetTrue;
253        let arg = $arg
254            .short($crate::arg_impl! { @char $short })
255            .action(action);
256        let arg = $crate::arg_impl! {
257            @arg (arg) $($tail)*
258        };
259        arg
260    }};
261    (
262        @arg
263        ($arg:expr)
264        -$short:literal
265        $($tail:tt)*
266    ) => {{
267        debug_assert_eq!($arg.get_long(), None, "Short flags should precede long flags");
268        debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
269        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
270
271        let action = $crate::ArgAction::SetTrue;
272        let arg = $arg
273            .short($crate::arg_impl! { @char $short })
274            .action(action);
275        let arg = $crate::arg_impl! {
276            @arg (arg) $($tail)*
277        };
278        arg
279    }};
280    (
281        @arg
282        ($arg:expr)
283        <$value_name:ident>
284        $($tail:tt)*
285    ) => {{
286        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
287        debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
288
289        let mut arg = $arg;
290
291        if arg.get_long().is_none() && arg.get_short().is_none() {
292            arg = arg.required(true);
293        }
294
295        let value_name = $crate::arg_impl! { @string $value_name };
296        if arg.get_id() == "" {
297            arg = arg.id(value_name);
298        }
299        let arg = arg
300            .value_name(value_name)
301            .action($crate::ArgAction::Set);
302        let arg = $crate::arg_impl! {
303            @arg (arg) $($tail)*
304        };
305        arg
306    }};
307    (
308        @arg
309        ($arg:expr)
310        <$value_name:literal>
311        $($tail:tt)*
312    ) => {{
313        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
314        debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
315
316        let mut arg = $arg;
317
318        if arg.get_long().is_none() && arg.get_short().is_none() {
319            arg = arg.required(true);
320        }
321
322        let value_name = $crate::arg_impl! { @string $value_name };
323        if arg.get_id() == "" {
324            arg = arg.id(value_name);
325        }
326        let arg = arg
327            .value_name(value_name)
328            .action($crate::ArgAction::Set);
329        let arg = $crate::arg_impl! {
330            @arg (arg) $($tail)*
331        };
332        arg
333    }};
334    (
335        @arg
336        ($arg:expr)
337        [$value_name:ident]
338        $($tail:tt)*
339    ) => {{
340        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
341        debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
342
343        let mut arg = $arg;
344
345        if arg.get_long().is_none() && arg.get_short().is_none() {
346            arg = arg.required(false);
347        } else {
348            arg = arg.num_args(0..=1);
349        }
350
351        let value_name = $crate::arg_impl! { @string $value_name };
352        if arg.get_id() == "" {
353            arg = arg.id(value_name);
354        }
355        let arg = arg
356            .value_name(value_name)
357            .action($crate::ArgAction::Set);
358        let arg = $crate::arg_impl! {
359            @arg (arg) $($tail)*
360        };
361        arg
362    }};
363    (
364        @arg
365        ($arg:expr)
366        [$value_name:literal]
367        $($tail:tt)*
368    ) => {{
369        debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
370        debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
371
372        let mut arg = $arg;
373
374        if arg.get_long().is_none() && arg.get_short().is_none() {
375            arg = arg.required(false);
376        } else {
377            arg = arg.num_args(0..=1);
378        }
379
380        let value_name = $crate::arg_impl! { @string $value_name };
381        if arg.get_id() == "" {
382            arg = arg.id(value_name);
383        }
384        let arg = arg
385            .value_name(value_name)
386            .action($crate::ArgAction::Set);
387        let arg = $crate::arg_impl! {
388            @arg (arg) $($tail)*
389        };
390        arg
391    }};
392    (
393        @arg
394        ($arg:expr)
395        ...
396        $($tail:tt)*
397    ) => {{
398        let arg = match $arg.get_action() {
399            $crate::ArgAction::Set => {
400                if $arg.get_long().is_none() && $arg.get_short().is_none() {
401                    $arg.num_args(1..)
402                        // Allow collecting arguments interleaved with flags
403                        .action($crate::ArgAction::Append)
404                } else {
405                    $arg.action($crate::ArgAction::Append)
406                }
407            },
408            $crate::ArgAction::SetTrue | $crate::ArgAction::Help | $crate::ArgAction::Version => {
409                $arg.action($crate::ArgAction::Count)
410            }
411            action => {
412                panic!("Unexpected action {action:?}")
413            }
414        };
415        let arg = $crate::arg_impl! {
416            @arg (arg) $($tail)*
417        };
418        arg
419    }};
420    (
421        @arg
422        ($arg:expr)
423        $help:literal
424    ) => {{
425        $arg.help($help)
426    }};
427    (
428        @arg
429        ($arg:expr)
430    ) => {{
431        $arg
432    }};
433}
434
435/// Create an [`Arg`] from a usage string.
436///
437/// Allows creation of basic settings for the [`Arg`].
438///
439/// <div class="warning">
440///
441/// **NOTE**: Not all settings may be set using the usage string method. Some properties are
442/// only available via the builder pattern.
443///
444/// </div>
445///
446/// # Syntax
447///
448/// Usage strings typically following the form:
449///
450/// ```notrust
451/// [explicit name] [short] [long] [value names] [...] [help string]
452/// ```
453///
454/// ### Explicit Name
455///
456/// The name may be either a bare-word or a string, followed by a `:`, like `name:` or
457/// `"name":`.
458///
459/// *Note:* This is an optional field, if it's omitted the argument will use one of the additional
460/// fields as the name using the following priority order:
461///
462///  1. Explicit Name
463///  2. Long
464///  3. Value Name
465///
466/// See [`Arg::id`][crate::Arg::id].
467///
468/// ### Short
469///
470/// A short flag is a `-` followed by either a bare-character or quoted character, like `-f` or
471/// `-'f'`.
472///
473/// See [`Arg::short`][crate::Arg::short].
474///
475/// ### Long
476///
477/// A long flag is a `--` followed by either a bare-word or a string, like `--foo` or
478/// `--"foo"`.
479///
480/// <div class="warning">
481///
482/// **NOTE:** Dashes in the long name (e.g. `--foo-bar`) is not supported and quoting is required
483/// (e.g. `--"foo-bar"`).
484///
485/// </div>
486///
487/// See [`Arg::long`][crate::Arg::long].
488///
489/// ### Values (Value Notation)
490///
491/// This is set by placing bare-word between:
492/// - `[]` like `[FOO]`
493///   - Positional argument: optional
494///   - Named argument: optional value
495/// - `<>` like `<FOO>`: required
496///
497/// See [`Arg::value_name`][crate::Arg::value_name].
498///
499/// ### `...`
500///
501/// `...` (three consecutive dots/periods) specifies that this argument may occur multiple
502/// times (not to be confused with multiple values per occurrence).
503///
504/// See [`ArgAction::Count`][crate::ArgAction::Count] and [`ArgAction::Append`][crate::ArgAction::Append].
505///
506/// ### Help String
507///
508/// The help string is denoted between a pair of double quotes `""` and may contain any
509/// characters.
510///
511/// # Examples
512///
513/// ```rust
514/// # use clap_builder as clap;
515/// # use clap::{Command, Arg, arg};
516/// let cmd = Command::new("prog")
517///     .args(&[
518///         arg!(--config <FILE> "a required file for the configuration and no short"),
519///         arg!(-d --debug ... "turns on debugging information and allows multiples"),
520///         arg!([input] "an optional input file to use")
521///     ]);
522///
523/// let m = cmd.try_get_matches_from(["prog", "--config", "file.toml"]).unwrap();
524/// assert_eq!(m.get_one::<String>("config").unwrap(), "file.toml");
525/// assert_eq!(*m.get_one::<u8>("debug").unwrap(), 0);
526/// assert_eq!(m.get_one::<String>("input"), None);
527/// ```
528/// [`Arg`]: crate::Arg
529#[macro_export]
530macro_rules! arg {
531    ( -$($tail:tt)+ ) => {{
532        let arg = $crate::Arg::default();
533        let arg = $crate::arg_impl! {
534            @arg (arg) -$($tail)+
535        };
536        debug_assert_ne!(arg.get_id(), "", "Without a value or long flag, the `name:` prefix is required");
537        arg
538    }};
539    ( $name:ident: $($tail:tt)+ ) => {{
540        let arg = $crate::Arg::new($crate::arg_impl! { @string $name });
541        let arg = $crate::arg_impl! {
542            @arg (arg) $($tail)+
543        };
544        arg
545    }};
546    ( $name:literal: $($tail:tt)+ ) => {{
547        let arg = $crate::Arg::new($crate::arg_impl! { @string $name });
548        let arg = $crate::arg_impl! {
549            @arg (arg) $($tail)+
550        };
551        arg
552    }};
553    ( $($tail:tt)+ ) => {{
554        let arg = $crate::Arg::default();
555        let arg = $crate::arg_impl! {
556            @arg (arg) $($tail)+
557        };
558        debug_assert_ne!(arg.get_id(), "", "Without a value or long flag, the `name:` prefix is required");
559        arg
560    }};
561}
562
563#[cfg(feature = "debug")]
564macro_rules! debug {
565    ($($arg:tt)*) => ({
566        use std::fmt::Write as _;
567        let hint = anstyle::Style::new().dimmed();
568
569        let module_path = module_path!();
570        let body = format!($($arg)*);
571        let mut styled = $crate::builder::StyledStr::new();
572        let _ = write!(styled, "{hint}[{module_path:>28}]{body}{hint:#}\n");
573        let color = $crate::output::fmt::Colorizer::new($crate::output::fmt::Stream::Stderr, $crate::ColorChoice::Auto).with_content(styled);
574        let _ = color.print();
575    })
576}
577
578#[cfg(not(feature = "debug"))]
579macro_rules! debug {
580    ($($arg:tt)*) => {};
581}
582
583macro_rules! ok {
584    ($expr:expr) => {
585        match $expr {
586            Ok(val) => val,
587            Err(err) => {
588                return Err(err);
589            }
590        }
591    };
592}
593
594macro_rules! some {
595    ($expr:expr) => {
596        match $expr {
597            Some(val) => val,
598            None => {
599                return None;
600            }
601        }
602    };
603}