mirror of
https://github.com/clap-rs/clap
synced 2024-12-14 23:02:31 +00:00
Merge branch 'master' into issue-231
This commit is contained in:
commit
c0c1613188
3 changed files with 201 additions and 0 deletions
|
@ -4,6 +4,7 @@ The following is a list of contributors to the [clap](https://github.com/kbknapp
|
|||
* [Ivan Dmitrievsky](https://github.com/idmit) <<ivan.dmitrievsky@gmail.com>>
|
||||
* [J/A](https://github.com/archer884)
|
||||
* [Jacob Helwig](https://github.com/jhelwig) <<jacob@technosorcery.net>>
|
||||
* [James McGlashan](https://github.com/james-darkfox)
|
||||
* [Kevin K.](https://github.com/kbknapp) <<kbknapp@gmail.com>>
|
||||
* [Markus Unterwaditzer](https://github.com/untitaker) <<markus@Unterwaditzer.net>>
|
||||
* [Sebastian Thiel](https://github.com/Byron) <<byronimo@gmail.com>>
|
||||
|
|
82
examples/18_builder_macro.rs
Normal file
82
examples/18_builder_macro.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
#[macro_use] extern crate clap;
|
||||
|
||||
// No use imports from clap. #[macro_use] gives us `clap_app!` which internally uses `$crate::`
|
||||
|
||||
fn main() {
|
||||
|
||||
// Validation example testing that a file exists
|
||||
let file_exists = |path| {
|
||||
if std::fs::metadata(path).is_ok() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(String::from("File doesn't exist"))
|
||||
}
|
||||
};
|
||||
|
||||
// External module may contain this subcommand. If this exists in another module, a function is
|
||||
// required to access it. Recommend `fn clap() -> Clap::SubCommand`.
|
||||
let external_sub_command = clap_app!( @subcommand foo =>
|
||||
(@arg bar: -b "Bar")
|
||||
);
|
||||
|
||||
let matches = clap_app!(MyApp =>
|
||||
(@setting SubcommandRequiredElseHelp)
|
||||
(version: "1.0")
|
||||
(author: "Alice")
|
||||
(about: "Does awesome things")
|
||||
(@arg config: -c --config <conf> #{1, 2} {file_exists} "Sets a custom config file")
|
||||
(@arg input: * "Input file")
|
||||
(@group test =>
|
||||
(@attributes +required)
|
||||
(@arg output: "Sets an optional output file")
|
||||
(@arg debug: -d ... "Turn debugging information on")
|
||||
)
|
||||
(subcommand: external_sub_command)
|
||||
(@subcommand test =>
|
||||
(about: "does testing things")
|
||||
(version: "2.5")
|
||||
(@arg list: -l "Lists test values")
|
||||
(@arg test_req: -r requires[list] "Tests requirement for listing")
|
||||
(@arg aaaa: --aaaa +takes_value {
|
||||
|a| if a.contains("a") {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(String::from("string does not contain at least one a"))
|
||||
}
|
||||
} "Test if the argument contains an a")
|
||||
)
|
||||
).get_matches();
|
||||
|
||||
// You can check the value provided by positional arguments, or option arguments
|
||||
if let Some(o) = matches.value_of("output") {
|
||||
println!("Value for output: {}", o);
|
||||
}
|
||||
|
||||
if let Some(c) = matches.value_of("config") {
|
||||
println!("Value for config: {}", c);
|
||||
}
|
||||
|
||||
// You can see how many times a particular flag or argument occurred
|
||||
// Note, only flags can have multiple occurrences
|
||||
match matches.occurrences_of("debug") {
|
||||
0 => println!("Debug mode is off"),
|
||||
1 => println!("Debug mode is kind of on"),
|
||||
2 => println!("Debug mode is on"),
|
||||
3 | _ => println!("Don't be crazy"),
|
||||
}
|
||||
|
||||
// You can check for the existence of subcommands, and if found use their
|
||||
// matches just as you would the top level app
|
||||
if let Some(ref matches) = matches.subcommand_matches("test") {
|
||||
// "$ myapp test" was run
|
||||
if matches.is_present("list") {
|
||||
// "$ myapp test -l" was run
|
||||
println!("Printing testing lists...");
|
||||
} else {
|
||||
println!("Not printing testing lists...");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Continued program logic goes here...
|
||||
}
|
118
src/macros.rs
118
src/macros.rs
|
@ -739,3 +739,121 @@ macro_rules! crate_version {
|
|||
option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
|
||||
}
|
||||
}
|
||||
|
||||
/// App, Arg, SubCommand and Group builder macro (Usage-string like input)
|
||||
#[macro_export]
|
||||
macro_rules! clap_app {
|
||||
(@app ($builder:expr)) => { $builder };
|
||||
(@app ($builder:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => {
|
||||
clap_app!{ @app
|
||||
($builder.arg(clap_app!{ @arg ($crate::Arg::with_name(stringify!($name))) (-) $($tail)* }))
|
||||
$($tt)*
|
||||
}
|
||||
};
|
||||
(@app ($builder:expr) (@setting $setting:ident) $($tt:tt)*) => {
|
||||
clap_app!{ @app
|
||||
($builder.setting($crate::AppSettings::$setting))
|
||||
$($tt)*
|
||||
}
|
||||
};
|
||||
// Treat the application builder as an argument to set it's attributes
|
||||
(@app ($builder:expr) (@attributes $($attr:tt)*) $($tt:tt)*) => {
|
||||
clap_app!{ @app (clap_app!{ @arg ($builder) $($attr)* }) $($tt)* }
|
||||
};
|
||||
(@app ($builder:expr) (@group $name:ident => $($tail:tt)*) $($tt:tt)*) => {
|
||||
clap_app!{ @app
|
||||
(clap_app!{ @group ($builder, $crate::ArgGroup::with_name(stringify!($name))) $($tail)* })
|
||||
$($tt)*
|
||||
}
|
||||
};
|
||||
// Handle subcommand creation
|
||||
(@app ($builder:expr) (@subcommand $name:ident => $($tail:tt)*) $($tt:tt)*) => {
|
||||
clap_app!{ @app
|
||||
($builder.subcommand(
|
||||
clap_app!{ @app ($crate::SubCommand::with_name(stringify!($name))) $($tail)* }
|
||||
))
|
||||
$($tt)*
|
||||
}
|
||||
};
|
||||
// Yaml like function calls - used for setting varous meta directly against the app
|
||||
(@app ($builder:expr) ($ident:ident: $($v:expr),*) $($tt:tt)*) => {
|
||||
clap_app!{ @app ($builder.$ident($($v),*)) $($tt)* }
|
||||
};
|
||||
|
||||
// Add members to group and continue argument handling with the parent builder
|
||||
(@group ($builder:expr, $group:expr)) => { $builder.arg_group($group) };
|
||||
(@group ($builder:expr, $group:expr) (@attributes $($attr:tt)*) $($tt:tt)*) => {
|
||||
clap_app!{ @group ($builder, clap_app!{ @arg ($group) (-) $($attr)* }) $($tt)* }
|
||||
};
|
||||
(@group ($builder:expr, $group:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => {
|
||||
clap_app!{ @group
|
||||
(clap_app!{ @app ($builder) (@arg $name: $($tail)*) },
|
||||
$group.add(stringify!($name)))
|
||||
$($tt)*
|
||||
}
|
||||
};
|
||||
|
||||
// No more tokens to munch
|
||||
(@arg ($arg:expr) $modes:tt) => { $arg };
|
||||
// Shorthand tokens influenced by the usage_string
|
||||
(@arg ($arg:expr) $modes:tt --$long:ident $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg.long(stringify!($long))) $modes $($tail)* }
|
||||
};
|
||||
(@arg ($arg:expr) $modes:tt -$short:ident $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg.short(stringify!($short))) $modes $($tail)* }
|
||||
};
|
||||
(@arg ($arg:expr) (-) <$var:ident> $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) +takes_value +required $($tail)* }
|
||||
};
|
||||
(@arg ($arg:expr) (+) <$var:ident> $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) $($tail)* }
|
||||
};
|
||||
(@arg ($arg:expr) (-) [$var:ident] $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg.value_name(stringify!($var))) +takes_value (+) $($tail)* }
|
||||
};
|
||||
(@arg ($arg:expr) (+) [$var:ident] $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) $($tail)* }
|
||||
};
|
||||
(@arg ($arg:expr) $modes:tt ... $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg) $modes +multiple $($tail)* }
|
||||
};
|
||||
// Shorthand magic
|
||||
(@arg ($arg:expr) $modes:tt #{$n:expr, $m:expr} $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg) $modes min_values($n) max_values($m) $($tail)* }
|
||||
};
|
||||
(@arg ($arg:expr) $modes:tt * $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg) $modes +required $($tail)* }
|
||||
};
|
||||
// !foo -> .foo(false)
|
||||
(@arg ($arg:expr) $modes:tt !$ident $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg.$ident(false)) $modes $($tail)* }
|
||||
};
|
||||
// foo -> .foo(true)
|
||||
(@arg ($arg:expr) $modes:tt +$ident:ident $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg.$ident(true)) $modes $($tail)* }
|
||||
};
|
||||
// Validator
|
||||
(@arg ($arg:expr) $modes:tt {$fn_:expr} $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg.validator($fn_)) $modes $($tail)* }
|
||||
};
|
||||
(@as_expr $expr:expr) => { $expr };
|
||||
// Help
|
||||
(@arg ($arg:expr) $modes:tt $desc:tt) => { $arg.help(clap_app!{ @as_expr $desc }) };
|
||||
// Handle functions that need to be called multiple times for each argument
|
||||
(@arg ($arg:expr) $modes:tt $ident:ident[$($target:ident)*] $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg $( .$ident(stringify!($target)) )*) $modes $($tail)* }
|
||||
};
|
||||
// Inherit builder's functions
|
||||
(@arg ($arg:expr) $modes:tt $ident:ident($($expr:expr)*) $($tail:tt)*) => {
|
||||
clap_app!{ @arg ($arg.$ident($($expr)*)) $modes $($tail)* }
|
||||
};
|
||||
|
||||
// Build a subcommand outside of an app.
|
||||
(@subcommand $name:ident => $($tail:tt)*) => {
|
||||
clap_app!{ @app ($crate::SubCommand::with_name(stringify!($name))) $($tail)* }
|
||||
};
|
||||
// Start the magic
|
||||
($name:ident => $($tail:tt)*) => {{
|
||||
clap_app!{ @app ($crate::App::new(stringify!($name))) $($tail)*}
|
||||
}};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue