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