]>
Commit | Line | Data |
---|---|---|
8bb4bdeb XL |
1 | /// A convenience macro for loading the YAML file at compile time (relative to the current file, |
2 | /// like modules work). That YAML object can then be passed to this function. | |
3 | /// | |
4 | /// # Panics | |
5 | /// | |
6 | /// The YAML file must be properly formatted or this function will panic!(). A good way to | |
7 | /// ensure this doesn't happen is to run your program with the `--help` switch. If this passes | |
8 | /// without error, you needn't worry because the YAML is properly formatted. | |
9 | /// | |
10 | /// # Examples | |
11 | /// | |
12 | /// The following example shows how to load a properly formatted YAML file to build an instnace | |
13 | /// of an `App` struct. | |
14 | /// | |
15 | /// ```ignore | |
16 | /// # #[macro_use] | |
17 | /// # extern crate clap; | |
18 | /// # use clap::App; | |
19 | /// # fn main() { | |
20 | /// let yml = load_yaml!("app.yml"); | |
21 | /// let app = App::from_yaml(yml); | |
22 | /// | |
23 | /// // continued logic goes here, such as `app.get_matches()` etc. | |
24 | /// # } | |
25 | /// ``` | |
26 | #[cfg(feature = "yaml")] | |
27 | #[macro_export] | |
28 | macro_rules! load_yaml { | |
29 | ($yml:expr) => ( | |
30 | &::clap::YamlLoader::load_from_str(include_str!($yml)).expect("failed to load YAML file")[0] | |
31 | ); | |
32 | } | |
33 | ||
34 | /// Convenience macro getting a typed value `T` where `T` implements [`std::str::FromStr`] from an | |
35 | /// argument value. This macro returns a `Result<T,String>` which allows you as the developer to | |
36 | /// decide what you'd like to do on a failed parse. There are two types of errors, parse failures | |
37 | /// and those where the argument wasn't present (such as a non-required argument). You can use | |
38 | /// it to get a single value, or a iterator as with the [`ArgMatches::values_of`] | |
39 | /// | |
40 | /// # Examples | |
41 | /// | |
42 | /// ```no_run | |
43 | /// # #[macro_use] | |
44 | /// # extern crate clap; | |
45 | /// # use clap::App; | |
46 | /// # fn main() { | |
47 | /// let matches = App::new("myapp") | |
48 | /// .arg_from_usage("[length] 'Set the length to use as a pos whole num, i.e. 20'") | |
49 | /// .get_matches(); | |
50 | /// | |
51 | /// let len = value_t!(matches.value_of("length"), u32).unwrap_or_else(|e| e.exit()); | |
52 | /// let also_len = value_t!(matches, "length", u32).unwrap_or_else(|e| e.exit()); | |
53 | /// | |
54 | /// println!("{} + 2: {}", len, len + 2); | |
55 | /// # } | |
56 | /// ``` | |
57 | /// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html | |
58 | /// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of | |
59 | /// [`Result<T,String>`]: https://doc.rust-lang.org/std/result/enum.Result.html | |
60 | #[macro_export] | |
61 | macro_rules! value_t { | |
62 | ($m:ident, $v:expr, $t:ty) => { | |
63 | value_t!($m.value_of($v), $t) | |
64 | }; | |
65 | ($m:ident.value_of($v:expr), $t:ty) => { | |
66 | if let Some(v) = $m.value_of($v) { | |
67 | match v.parse::<$t>() { | |
68 | Ok(val) => Ok(val), | |
69 | Err(_) => | |
70 | Err(::clap::Error::value_validation_auto( | |
71 | format!("The argument '{}' isn't a valid value", v))), | |
72 | } | |
73 | } else { | |
74 | Err(::clap::Error::argument_not_found_auto($v)) | |
75 | } | |
76 | }; | |
77 | } | |
78 | ||
79 | /// Convenience macro getting a typed value `T` where `T` implements [`std::str::FromStr`] or | |
80 | /// exiting upon error, instead of returning a [`Result`] type. | |
81 | /// | |
82 | /// **NOTE:** This macro is for backwards compatibility sake. Prefer | |
83 | /// [`value_t!(/* ... */).unwrap_or_else(|e| e.exit())`] | |
84 | /// | |
85 | /// # Examples | |
86 | /// | |
87 | /// ```no_run | |
88 | /// # #[macro_use] | |
89 | /// # extern crate clap; | |
90 | /// # use clap::App; | |
91 | /// # fn main() { | |
92 | /// let matches = App::new("myapp") | |
93 | /// .arg_from_usage("[length] 'Set the length to use as a pos whole num, i.e. 20'") | |
94 | /// .get_matches(); | |
95 | /// | |
96 | /// let len = value_t_or_exit!(matches.value_of("length"), u32); | |
97 | /// let also_len = value_t_or_exit!(matches, "length", u32); | |
98 | /// | |
99 | /// println!("{} + 2: {}", len, len + 2); | |
100 | /// # } | |
101 | /// ``` | |
102 | /// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html | |
103 | /// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html | |
104 | /// [`value_t!(/* ... */).unwrap_or_else(|e| e.exit())`]: ./macro.value_t!.html | |
105 | #[macro_export] | |
106 | macro_rules! value_t_or_exit { | |
107 | ($m:ident, $v:expr, $t:ty) => { | |
108 | value_t_or_exit!($m.value_of($v), $t) | |
109 | }; | |
110 | ($m:ident.value_of($v:expr), $t:ty) => { | |
111 | if let Some(v) = $m.value_of($v) { | |
112 | match v.parse::<$t>() { | |
113 | Ok(val) => val, | |
114 | Err(_) => | |
115 | ::clap::Error::value_validation_auto( | |
116 | format!("The argument '{}' isn't a valid value", v)).exit(), | |
117 | } | |
118 | } else { | |
119 | ::clap::Error::argument_not_found_auto($v).exit() | |
120 | } | |
121 | }; | |
122 | } | |
123 | ||
124 | /// Convenience macro getting a typed value [`Vec<T>`] where `T` implements [`std::str::FromStr`] | |
125 | /// This macro returns a [`clap::Result<Vec<T>>`] which allows you as the developer to decide | |
126 | /// what you'd like to do on a failed parse. | |
127 | /// | |
128 | /// # Examples | |
129 | /// | |
130 | /// ```no_run | |
131 | /// # #[macro_use] | |
132 | /// # extern crate clap; | |
133 | /// # use clap::App; | |
134 | /// # fn main() { | |
135 | /// let matches = App::new("myapp") | |
136 | /// .arg_from_usage("[seq]... 'A sequence of pos whole nums, i.e. 20 45'") | |
137 | /// .get_matches(); | |
138 | /// | |
139 | /// let vals = values_t!(matches.values_of("seq"), u32).unwrap_or_else(|e| e.exit()); | |
140 | /// for v in &vals { | |
141 | /// println!("{} + 2: {}", v, v + 2); | |
142 | /// } | |
143 | /// | |
144 | /// let vals = values_t!(matches, "seq", u32).unwrap_or_else(|e| e.exit()); | |
145 | /// for v in &vals { | |
146 | /// println!("{} + 2: {}", v, v + 2); | |
147 | /// } | |
148 | /// # } | |
149 | /// ``` | |
150 | /// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html | |
151 | /// [`Vec<T>`]: https://doc.rust-lang.org/std/vec/struct.Vec.html | |
152 | /// [`clap::Result<Vec<T>>`]: ./type.Result.html | |
153 | #[macro_export] | |
154 | macro_rules! values_t { | |
155 | ($m:ident, $v:expr, $t:ty) => { | |
156 | values_t!($m.values_of($v), $t) | |
157 | }; | |
158 | ($m:ident.values_of($v:expr), $t:ty) => { | |
159 | if let Some(vals) = $m.values_of($v) { | |
160 | let mut tmp = vec![]; | |
161 | let mut err = None; | |
162 | for pv in vals { | |
163 | match pv.parse::<$t>() { | |
164 | Ok(rv) => tmp.push(rv), | |
165 | Err(..) => { | |
166 | err = Some(::clap::Error::value_validation_auto( | |
167 | format!("The argument '{}' isn't a valid value", pv))); | |
168 | break | |
169 | } | |
170 | } | |
171 | } | |
172 | match err { | |
173 | Some(e) => Err(e), | |
174 | None => Ok(tmp), | |
175 | } | |
176 | } else { | |
177 | Err(::clap::Error::argument_not_found_auto($v)) | |
178 | } | |
179 | }; | |
180 | } | |
181 | ||
182 | /// Convenience macro getting a typed value [`Vec<T>`] where `T` implements [`std::str::FromStr`] | |
183 | /// or exiting upon error. | |
184 | /// | |
185 | /// **NOTE:** This macro is for backwards compatibility sake. Prefer | |
186 | /// [`values_t!(/* ... */).unwrap_or_else(|e| e.exit())`] | |
187 | /// | |
188 | /// # Examples | |
189 | /// | |
190 | /// ```no_run | |
191 | /// # #[macro_use] | |
192 | /// # extern crate clap; | |
193 | /// # use clap::App; | |
194 | /// # fn main() { | |
195 | /// let matches = App::new("myapp") | |
196 | /// .arg_from_usage("[seq]... 'A sequence of pos whole nums, i.e. 20 45'") | |
197 | /// .get_matches(); | |
198 | /// | |
199 | /// let vals = values_t_or_exit!(matches.values_of("seq"), u32); | |
200 | /// for v in &vals { | |
201 | /// println!("{} + 2: {}", v, v + 2); | |
202 | /// } | |
203 | /// | |
204 | /// // type for example only | |
205 | /// let vals: Vec<u32> = values_t_or_exit!(matches, "seq", u32); | |
206 | /// for v in &vals { | |
207 | /// println!("{} + 2: {}", v, v + 2); | |
208 | /// } | |
209 | /// # } | |
210 | /// ``` | |
211 | /// [`values_t!(/* ... */).unwrap_or_else(|e| e.exit())`]: ./macro.values_t!.html | |
212 | /// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html | |
213 | /// [`Vec<T>`]: https://doc.rust-lang.org/std/vec/struct.Vec.html | |
214 | #[macro_export] | |
215 | macro_rules! values_t_or_exit { | |
216 | ($m:ident, $v:expr, $t:ty) => { | |
217 | values_t_or_exit!($m.values_of($v), $t) | |
218 | }; | |
219 | ($m:ident.values_of($v:expr), $t:ty) => { | |
220 | if let Some(vals) = $m.values_of($v) { | |
221 | vals.map(|v| v.parse::<$t>().unwrap_or_else(|_|{ | |
222 | ::clap::Error::value_validation_auto( | |
223 | format!("One or more arguments aren't valid values")).exit() | |
224 | })).collect::<Vec<$t>>() | |
225 | } else { | |
226 | ::clap::Error::argument_not_found_auto($v).exit() | |
227 | } | |
228 | }; | |
229 | } | |
230 | ||
231 | // _clap_count_exprs! is derived from https://github.com/DanielKeep/rust-grabbag | |
232 | // commit: 82a35ca5d9a04c3b920622d542104e3310ee5b07 | |
233 | // License: MIT | |
234 | // Copyright â“’ 2015 grabbag contributors. | |
235 | // Licensed under the MIT license (see LICENSE or <http://opensource.org | |
236 | // /licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of | |
237 | // <http://www.apache.org/licenses/LICENSE-2.0>), at your option. All | |
238 | // files in the project carrying such notice may not be copied, modified, | |
239 | // or distributed except according to those terms. | |
240 | // | |
241 | /// Counts the number of comma-delimited expressions passed to it. The result is a compile-time | |
242 | /// evaluable expression, suitable for use as a static array size, or the value of a `const`. | |
243 | /// | |
244 | /// # Examples | |
245 | /// | |
246 | /// ``` | |
247 | /// # #[macro_use] extern crate clap; | |
248 | /// # fn main() { | |
249 | /// const COUNT: usize = _clap_count_exprs!(a, 5+1, "hi there!".into_string()); | |
250 | /// assert_eq!(COUNT, 3); | |
251 | /// # } | |
252 | /// ``` | |
253 | #[macro_export] | |
254 | macro_rules! _clap_count_exprs { | |
255 | () => { 0 }; | |
256 | ($e:expr) => { 1 }; | |
257 | ($e:expr, $($es:expr),+) => { 1 + _clap_count_exprs!($($es),*) }; | |
258 | } | |
259 | ||
260 | /// Convenience macro to generate more complete enums with variants to be used as a type when | |
261 | /// parsing arguments. This enum also provides a `variants()` function which can be used to | |
262 | /// retrieve a `Vec<&'static str>` of the variant names, as well as implementing [`FromStr`] and | |
263 | /// [`Display`] automatically. | |
264 | /// | |
265 | /// **NOTE:** Case insensitivity is supported for ASCII characters only | |
266 | /// | |
267 | /// **NOTE:** This macro automatically implements [`std::str::FromStr`] and [`std::fmt::Display`] | |
268 | /// | |
269 | /// **NOTE:** These enums support pub (or not) and uses of the #[derive()] traits | |
270 | /// | |
271 | /// # Examples | |
272 | /// | |
273 | /// ```no_run | |
274 | /// # #[macro_use] | |
275 | /// # extern crate clap; | |
276 | /// # use clap::{App, Arg}; | |
277 | /// arg_enum!{ | |
278 | /// #[derive(Debug)] | |
279 | /// pub enum Foo { | |
280 | /// Bar, | |
281 | /// Baz, | |
282 | /// Qux | |
283 | /// } | |
284 | /// } | |
285 | /// // Foo enum can now be used via Foo::Bar, or Foo::Baz, etc | |
286 | /// // and implements std::str::FromStr to use with the value_t! macros | |
287 | /// fn main() { | |
288 | /// let m = App::new("app") | |
289 | /// .arg_from_usage("<foo> 'the foo'") | |
290 | /// .get_matches(); | |
291 | /// let f = value_t!(m, "foo", Foo).unwrap_or_else(|e| e.exit()); | |
292 | /// | |
293 | /// // Use f like any other Foo variant... | |
294 | /// } | |
295 | /// ``` | |
296 | /// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html | |
297 | /// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html | |
298 | /// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html | |
299 | /// [`std::fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html | |
300 | #[macro_export] | |
301 | macro_rules! arg_enum { | |
302 | (@as_item $($i:item)*) => ($($i)*); | |
303 | (@impls ( $($tts:tt)* ) -> ($e:ident, $($v:ident),+)) => { | |
304 | arg_enum!(@as_item | |
305 | $($tts)* | |
306 | ||
307 | impl ::std::str::FromStr for $e { | |
308 | type Err = String; | |
309 | ||
310 | fn from_str(s: &str) -> ::std::result::Result<Self,Self::Err> { | |
311 | use ::std::ascii::AsciiExt; | |
312 | match s { | |
313 | $(stringify!($v) | | |
314 | _ if s.eq_ignore_ascii_case(stringify!($v)) => Ok($e::$v)),+, | |
315 | _ => Err({ | |
316 | let v = vec![ | |
317 | $(stringify!($v),)+ | |
318 | ]; | |
319 | format!("valid values: {}", | |
320 | v.join(" ,")) | |
321 | }), | |
322 | } | |
323 | } | |
324 | } | |
325 | impl ::std::fmt::Display for $e { | |
326 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | |
327 | match *self { | |
328 | $($e::$v => write!(f, stringify!($v)),)+ | |
329 | } | |
330 | } | |
331 | } | |
332 | impl $e { | |
333 | #[allow(dead_code)] | |
334 | pub fn variants() -> [&'static str; _clap_count_exprs!($(stringify!($v)),+)] { | |
335 | [ | |
336 | $(stringify!($v),)+ | |
337 | ] | |
338 | } | |
339 | }); | |
340 | }; | |
341 | ($(#[$($m:meta),+])+ pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => { | |
342 | arg_enum!(@impls | |
343 | ($(#[$($m),+])+ | |
344 | pub enum $e { | |
345 | $($v$(=$val)*),+ | |
346 | }) -> ($e, $($v),+) | |
347 | ); | |
348 | }; | |
349 | ($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => { | |
350 | arg_enum!(@impls | |
351 | ($(#[$($m),+])+ | |
352 | enum $e { | |
353 | $($v$(=$val)*),+ | |
354 | }) -> ($e, $($v),+) | |
355 | ); | |
356 | }; | |
357 | (pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => { | |
358 | arg_enum!(@impls | |
359 | (pub enum $e { | |
360 | $($v$(=$val)*),+ | |
361 | }) -> ($e, $($v),+) | |
362 | ); | |
363 | }; | |
364 | (enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => { | |
365 | arg_enum!(@impls | |
366 | (enum $e { | |
367 | $($v$(=$val)*),+ | |
368 | }) -> ($e, $($v),+) | |
369 | ); | |
370 | }; | |
371 | } | |
372 | ||
373 | /// Allows you to pull the version from your Cargo.toml at compile time as | |
374 | /// MAJOR.MINOR.PATCH_PKGVERSION_PRE | |
375 | /// | |
376 | /// # Examples | |
377 | /// | |
378 | /// ```no_run | |
379 | /// # #[macro_use] | |
380 | /// # extern crate clap; | |
381 | /// # use clap::App; | |
382 | /// # fn main() { | |
7cac9316 XL |
383 | /// let m = App::new("app") |
384 | /// .version(crate_version!()) | |
385 | /// .get_matches(); | |
8bb4bdeb XL |
386 | /// # } |
387 | /// ``` | |
8bb4bdeb XL |
388 | #[macro_export] |
389 | macro_rules! crate_version { | |
390 | () => { | |
391 | env!("CARGO_PKG_VERSION") | |
392 | }; | |
393 | } | |
394 | ||
395 | /// Allows you to pull the authors for the app from your Cargo.toml at | |
7cac9316 XL |
396 | /// compile time as |
397 | /// "author1 lastname. <author1@example.com>", | |
398 | /// "author2 lastname. <author2@example.com>" | |
8bb4bdeb XL |
399 | /// |
400 | /// # Examples | |
401 | /// | |
402 | /// ```no_run | |
403 | /// # #[macro_use] | |
404 | /// # extern crate clap; | |
405 | /// # use clap::App; | |
406 | /// # fn main() { | |
7cac9316 XL |
407 | /// let m = App::new("app") |
408 | /// .author(crate_authors!()) | |
409 | /// .get_matches(); | |
8bb4bdeb XL |
410 | /// # } |
411 | /// ``` | |
8bb4bdeb XL |
412 | #[macro_export] |
413 | macro_rules! crate_authors { | |
8bb4bdeb XL |
414 | () => { |
415 | env!("CARGO_PKG_AUTHORS") | |
416 | }; | |
417 | } | |
418 | ||
8bb4bdeb | 419 | /// Build `App`, `Arg`s, `SubCommand`s and `Group`s with Usage-string like input |
7cac9316 | 420 | /// but without the parsing. |
8bb4bdeb XL |
421 | #[macro_export] |
422 | macro_rules! clap_app { | |
423 | (@app ($builder:expr)) => { $builder }; | |
424 | (@app ($builder:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => { | |
425 | clap_app!{ @app | |
426 | ($builder.arg( | |
427 | clap_app!{ @arg ($crate::Arg::with_name(stringify!($name))) (-) $($tail)* })) | |
428 | $($tt)* | |
429 | } | |
430 | }; | |
431 | (@app ($builder:expr) (@setting $setting:ident) $($tt:tt)*) => { | |
432 | clap_app!{ @app | |
433 | ($builder.setting($crate::AppSettings::$setting)) | |
434 | $($tt)* | |
435 | } | |
436 | }; | |
437 | // Treat the application builder as an argument to set it's attributes | |
438 | (@app ($builder:expr) (@attributes $($attr:tt)*) $($tt:tt)*) => { | |
439 | clap_app!{ @app (clap_app!{ @arg ($builder) $($attr)* }) $($tt)* } | |
440 | }; | |
441 | (@app ($builder:expr) (@group $name:ident => $($tail:tt)*) $($tt:tt)*) => { | |
442 | clap_app!{ @app | |
443 | (clap_app!{ @group ($builder, $crate::ArgGroup::with_name(stringify!($name))) $($tail)* }) | |
444 | $($tt)* | |
445 | } | |
446 | }; | |
447 | // Handle subcommand creation | |
448 | (@app ($builder:expr) (@subcommand $name:ident => $($tail:tt)*) $($tt:tt)*) => { | |
449 | clap_app!{ @app | |
450 | ($builder.subcommand( | |
451 | clap_app!{ @app ($crate::SubCommand::with_name(stringify!($name))) $($tail)* } | |
452 | )) | |
453 | $($tt)* | |
454 | } | |
455 | }; | |
456 | // Yaml like function calls - used for setting various meta directly against the app | |
457 | (@app ($builder:expr) ($ident:ident: $($v:expr),*) $($tt:tt)*) => { | |
458 | // clap_app!{ @app ($builder.$ident($($v),*)) $($tt)* } | |
459 | clap_app!{ @app | |
460 | ($builder.$ident($($v),*)) | |
461 | $($tt)* | |
462 | } | |
463 | }; | |
464 | ||
465 | // Add members to group and continue argument handling with the parent builder | |
466 | (@group ($builder:expr, $group:expr)) => { $builder.group($group) }; | |
467 | (@group ($builder:expr, $group:expr) (@attributes $($attr:tt)*) $($tt:tt)*) => { | |
468 | clap_app!{ @group ($builder, clap_app!{ @arg ($group) (-) $($attr)* }) $($tt)* } | |
469 | }; | |
470 | (@group ($builder:expr, $group:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => { | |
471 | clap_app!{ @group | |
472 | (clap_app!{ @app ($builder) (@arg $name: $($tail)*) }, | |
473 | $group.arg(stringify!($name))) | |
474 | $($tt)* | |
475 | } | |
476 | }; | |
477 | ||
478 | // No more tokens to munch | |
479 | (@arg ($arg:expr) $modes:tt) => { $arg }; | |
480 | // Shorthand tokens influenced by the usage_string | |
8bb4bdeb XL |
481 | (@arg ($arg:expr) $modes:tt --$long:ident $($tail:tt)*) => { |
482 | clap_app!{ @arg ($arg.long(stringify!($long))) $modes $($tail)* } | |
483 | }; | |
484 | (@arg ($arg:expr) $modes:tt -$short:ident $($tail:tt)*) => { | |
485 | clap_app!{ @arg ($arg.short(stringify!($short))) $modes $($tail)* } | |
486 | }; | |
487 | (@arg ($arg:expr) (-) <$var:ident> $($tail:tt)*) => { | |
488 | clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) +takes_value +required $($tail)* } | |
489 | }; | |
490 | (@arg ($arg:expr) (+) <$var:ident> $($tail:tt)*) => { | |
491 | clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) $($tail)* } | |
492 | }; | |
493 | (@arg ($arg:expr) (-) [$var:ident] $($tail:tt)*) => { | |
494 | clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) +takes_value $($tail)* } | |
495 | }; | |
496 | (@arg ($arg:expr) (+) [$var:ident] $($tail:tt)*) => { | |
497 | clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) $($tail)* } | |
498 | }; | |
499 | (@arg ($arg:expr) $modes:tt ... $($tail:tt)*) => { | |
500 | clap_app!{ @arg ($arg) $modes +multiple $($tail)* } | |
501 | }; | |
502 | // Shorthand magic | |
503 | (@arg ($arg:expr) $modes:tt #{$n:expr, $m:expr} $($tail:tt)*) => { | |
504 | clap_app!{ @arg ($arg) $modes min_values($n) max_values($m) $($tail)* } | |
505 | }; | |
506 | (@arg ($arg:expr) $modes:tt * $($tail:tt)*) => { | |
507 | clap_app!{ @arg ($arg) $modes +required $($tail)* } | |
508 | }; | |
509 | // !foo -> .foo(false) | |
7cac9316 | 510 | (@arg ($arg:expr) $modes:tt !$ident $($tail:tt)*) => { |
8bb4bdeb XL |
511 | clap_app!{ @arg ($arg.$ident(false)) $modes $($tail)* } |
512 | }; | |
7cac9316 | 513 | // foo -> .foo(true) |
8bb4bdeb XL |
514 | (@arg ($arg:expr) $modes:tt +$ident:ident $($tail:tt)*) => { |
515 | clap_app!{ @arg ($arg.$ident(true)) $modes $($tail)* } | |
516 | }; | |
517 | // Validator | |
518 | (@arg ($arg:expr) $modes:tt {$fn_:expr} $($tail:tt)*) => { | |
519 | clap_app!{ @arg ($arg.validator($fn_)) $modes $($tail)* } | |
520 | }; | |
521 | (@as_expr $expr:expr) => { $expr }; | |
522 | // Help | |
523 | (@arg ($arg:expr) $modes:tt $desc:tt) => { $arg.help(clap_app!{ @as_expr $desc }) }; | |
524 | // Handle functions that need to be called multiple times for each argument | |
525 | (@arg ($arg:expr) $modes:tt $ident:ident[$($target:ident)*] $($tail:tt)*) => { | |
526 | clap_app!{ @arg ($arg $( .$ident(stringify!($target)) )*) $modes $($tail)* } | |
527 | }; | |
528 | // Inherit builder's functions | |
529 | (@arg ($arg:expr) $modes:tt $ident:ident($($expr:expr)*) $($tail:tt)*) => { | |
530 | clap_app!{ @arg ($arg.$ident($($expr)*)) $modes $($tail)* } | |
531 | }; | |
532 | ||
533 | // Build a subcommand outside of an app. | |
534 | (@subcommand $name:ident => $($tail:tt)*) => { | |
535 | clap_app!{ @app ($crate::SubCommand::with_name(stringify!($name))) $($tail)* } | |
536 | }; | |
537 | // Start the magic | |
8bb4bdeb XL |
538 | ($name:ident => $($tail:tt)*) => {{ |
539 | clap_app!{ @app ($crate::App::new(stringify!($name))) $($tail)*} | |
540 | }}; | |
541 | } | |
542 | ||
543 | macro_rules! impl_settings { | |
544 | ($n:ident, $($v:ident => $c:ident),+) => { | |
545 | pub fn set(&mut self, s: $n) { | |
546 | match s { | |
547 | $($n::$v => self.0.insert($c)),+ | |
548 | } | |
549 | } | |
550 | ||
551 | pub fn unset(&mut self, s: $n) { | |
552 | match s { | |
553 | $($n::$v => self.0.remove($c)),+ | |
554 | } | |
555 | } | |
556 | ||
557 | pub fn is_set(&self, s: $n) -> bool { | |
558 | match s { | |
559 | $($n::$v => self.0.contains($c)),+ | |
560 | } | |
561 | } | |
562 | }; | |
563 | } | |
564 | ||
565 | // Convenience for writing to stderr thanks to https://github.com/BurntSushi | |
566 | macro_rules! wlnerr( | |
567 | ($($arg:tt)*) => ({ | |
568 | use std::io::{Write, stderr}; | |
569 | writeln!(&mut stderr(), $($arg)*).ok(); | |
570 | }) | |
571 | ); | |
572 | macro_rules! werr( | |
573 | ($($arg:tt)*) => ({ | |
574 | use std::io::{Write, stderr}; | |
575 | write!(&mut stderr(), $($arg)*).ok(); | |
576 | }) | |
577 | ); | |
578 | ||
579 | #[cfg(feature = "debug")] | |
580 | #[cfg_attr(feature = "debug", macro_use)] | |
581 | mod debug_macros { | |
582 | macro_rules! debugln { | |
7cac9316 XL |
583 | ($fmt:expr) => (println!(concat!("*DEBUG:clap: ", $fmt))); |
584 | ($fmt:expr, $($arg:tt)*) => (println!(concat!("*DEBUG:clap: ",$fmt), $($arg)*)); | |
8bb4bdeb XL |
585 | } |
586 | macro_rules! sdebugln { | |
587 | ($fmt:expr) => (println!($fmt)); | |
588 | ($fmt:expr, $($arg:tt)*) => (println!($fmt, $($arg)*)); | |
589 | } | |
590 | macro_rules! debug { | |
7cac9316 XL |
591 | ($fmt:expr) => (print!(concat!("*DEBUG:clap: ", $fmt))); |
592 | ($fmt:expr, $($arg:tt)*) => (print!(concat!("*DEBUG:clap: ",$fmt), $($arg)*)); | |
8bb4bdeb XL |
593 | } |
594 | macro_rules! sdebug { | |
595 | ($fmt:expr) => (print!($fmt)); | |
596 | ($fmt:expr, $($arg:tt)*) => (print!($fmt, $($arg)*)); | |
597 | } | |
598 | } | |
599 | ||
600 | #[cfg(not(feature = "debug"))] | |
601 | #[cfg_attr(not(feature = "debug"), macro_use)] | |
602 | mod debug_macros { | |
603 | macro_rules! debugln { | |
604 | ($fmt:expr) => (); | |
605 | ($fmt:expr, $($arg:tt)*) => (); | |
606 | } | |
607 | macro_rules! sdebugln { | |
608 | ($fmt:expr) => (); | |
609 | ($fmt:expr, $($arg:tt)*) => (); | |
610 | } | |
611 | macro_rules! sdebug { | |
612 | ($fmt:expr) => (); | |
613 | ($fmt:expr, $($arg:tt)*) => (); | |
614 | } | |
615 | macro_rules! debug { | |
616 | ($fmt:expr) => (); | |
617 | ($fmt:expr, $($arg:tt)*) => (); | |
618 | } | |
619 | } | |
620 | ||
621 | // Helper/deduplication macro for printing the correct number of spaces in help messages | |
622 | // used in: | |
623 | // src/args/arg_builder/*.rs | |
624 | // src/app/mod.rs | |
625 | macro_rules! write_spaces { | |
626 | ($num:expr, $w:ident) => ({ | |
7cac9316 | 627 | debugln!("macro=write_spaces!;"); |
8bb4bdeb XL |
628 | for _ in 0..$num { |
629 | try!(write!($w, " ")); | |
630 | } | |
631 | }) | |
632 | } | |
633 | ||
634 | // Helper/deduplication macro for printing the correct number of spaces in help messages | |
635 | // used in: | |
636 | // src/args/arg_builder/*.rs | |
637 | // src/app/mod.rs | |
638 | macro_rules! write_nspaces { | |
639 | ($dst:expr, $num:expr) => ({ | |
7cac9316 | 640 | debugln!("macro=write_spaces!;num={}", $num); |
8bb4bdeb | 641 | for _ in 0..$num { |
7cac9316 | 642 | try!($dst.write(b" ")); |
8bb4bdeb XL |
643 | } |
644 | }) | |
645 | } | |
646 | ||
647 | // convenience macro for remove an item from a vec | |
648 | macro_rules! vec_remove { | |
649 | ($vec:expr, $to_rem:expr) => { | |
7cac9316 | 650 | debugln!("macro=vec_remove!;to_rem={:?}", $to_rem); |
8bb4bdeb XL |
651 | for i in (0 .. $vec.len()).rev() { |
652 | let should_remove = &$vec[i] == $to_rem; | |
653 | if should_remove { $vec.swap_remove(i); } | |
654 | } | |
655 | }; | |
656 | } | |
657 | ||
658 | // convenience macro for remove an item from a vec | |
659 | macro_rules! vec_remove_all { | |
660 | ($vec:expr, $to_rem:expr) => { | |
7cac9316 | 661 | debugln!("macro=vec_remove_all!;to_rem={:?}", $to_rem); |
8bb4bdeb | 662 | for i in (0 .. $vec.len()).rev() { |
7cac9316 | 663 | let should_remove = $to_rem.contains(&$vec[i]); |
8bb4bdeb XL |
664 | if should_remove { $vec.swap_remove(i); } |
665 | } | |
666 | }; | |
667 | } |