diff options
Diffstat (limited to 'third_party/rust/clap/examples/tutorial_derive')
18 files changed, 1157 insertions, 0 deletions
diff --git a/third_party/rust/clap/examples/tutorial_derive/01_quick.rs b/third_party/rust/clap/examples/tutorial_derive/01_quick.rs new file mode 100644 index 0000000000..f840b8a9b2 --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/01_quick.rs @@ -0,0 +1,68 @@ +use std::path::PathBuf; + +use clap::{Parser, Subcommand}; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + /// Optional name to operate on + name: Option<String>, + + /// Sets a custom config file + #[clap(short, long, parse(from_os_str), value_name = "FILE")] + config: Option<PathBuf>, + + /// Turn debugging information on + #[clap(short, long, parse(from_occurrences))] + debug: usize, + + #[clap(subcommand)] + command: Option<Commands>, +} + +#[derive(Subcommand)] +enum Commands { + /// does testing things + Test { + /// lists test values + #[clap(short, long)] + list: bool, + }, +} + +fn main() { + let cli = Cli::parse(); + + // You can check the value provided by positional arguments, or option arguments + if let Some(name) = cli.name.as_deref() { + println!("Value for name: {}", name); + } + + if let Some(config_path) = cli.config.as_deref() { + println!("Value for config: {}", config_path.display()); + } + + // You can see how many times a particular flag or argument occurred + // Note, only flags can have multiple occurrences + match cli.debug { + 0 => println!("Debug mode is off"), + 1 => println!("Debug mode is kind of on"), + 2 => println!("Debug mode is on"), + _ => 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 cmd + match &cli.command { + Some(Commands::Test { list }) => { + if *list { + println!("Printing testing lists..."); + } else { + println!("Not printing testing lists..."); + } + } + None => {} + } + + // Continued program logic goes here... +} diff --git a/third_party/rust/clap/examples/tutorial_derive/02_app_settings.rs b/third_party/rust/clap/examples/tutorial_derive/02_app_settings.rs new file mode 100644 index 0000000000..bccd353f60 --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/02_app_settings.rs @@ -0,0 +1,20 @@ +use clap::{AppSettings, Parser}; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +#[clap(args_override_self = true)] +#[clap(allow_negative_numbers = true)] +#[clap(global_setting(AppSettings::DeriveDisplayOrder))] +struct Cli { + #[clap(long)] + two: String, + #[clap(long)] + one: String, +} + +fn main() { + let cli = Cli::parse(); + + println!("two: {:?}", cli.two); + println!("one: {:?}", cli.one); +} diff --git a/third_party/rust/clap/examples/tutorial_derive/02_apps.rs b/third_party/rust/clap/examples/tutorial_derive/02_apps.rs new file mode 100644 index 0000000000..442e928a9f --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/02_apps.rs @@ -0,0 +1,20 @@ +use clap::Parser; + +#[derive(Parser)] +#[clap(name = "MyApp")] +#[clap(author = "Kevin K. <kbknapp@gmail.com>")] +#[clap(version = "1.0")] +#[clap(about = "Does awesome things", long_about = None)] +struct Cli { + #[clap(long)] + two: String, + #[clap(long)] + one: String, +} + +fn main() { + let cli = Cli::parse(); + + println!("two: {:?}", cli.two); + println!("one: {:?}", cli.one); +} diff --git a/third_party/rust/clap/examples/tutorial_derive/02_crate.rs b/third_party/rust/clap/examples/tutorial_derive/02_crate.rs new file mode 100644 index 0000000000..93f7888af3 --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/02_crate.rs @@ -0,0 +1,17 @@ +use clap::Parser; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + #[clap(long)] + two: String, + #[clap(long)] + one: String, +} + +fn main() { + let cli = Cli::parse(); + + println!("two: {:?}", cli.two); + println!("one: {:?}", cli.one); +} diff --git a/third_party/rust/clap/examples/tutorial_derive/03_01_flag_bool.rs b/third_party/rust/clap/examples/tutorial_derive/03_01_flag_bool.rs new file mode 100644 index 0000000000..8b574b7481 --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/03_01_flag_bool.rs @@ -0,0 +1,14 @@ +use clap::Parser; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + #[clap(short, long)] + verbose: bool, +} + +fn main() { + let cli = Cli::parse(); + + println!("verbose: {:?}", cli.verbose); +} diff --git a/third_party/rust/clap/examples/tutorial_derive/03_01_flag_count.rs b/third_party/rust/clap/examples/tutorial_derive/03_01_flag_count.rs new file mode 100644 index 0000000000..2ab883977a --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/03_01_flag_count.rs @@ -0,0 +1,14 @@ +use clap::Parser; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + #[clap(short, long, parse(from_occurrences))] + verbose: usize, +} + +fn main() { + let cli = Cli::parse(); + + println!("verbose: {:?}", cli.verbose); +} diff --git a/third_party/rust/clap/examples/tutorial_derive/03_02_option.rs b/third_party/rust/clap/examples/tutorial_derive/03_02_option.rs new file mode 100644 index 0000000000..b09aadf20d --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/03_02_option.rs @@ -0,0 +1,14 @@ +use clap::Parser; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + #[clap(short, long)] + name: Option<String>, +} + +fn main() { + let cli = Cli::parse(); + + println!("name: {:?}", cli.name.as_deref()); +} diff --git a/third_party/rust/clap/examples/tutorial_derive/03_03_positional.rs b/third_party/rust/clap/examples/tutorial_derive/03_03_positional.rs new file mode 100644 index 0000000000..f7850ddccf --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/03_03_positional.rs @@ -0,0 +1,13 @@ +use clap::Parser; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + name: Option<String>, +} + +fn main() { + let cli = Cli::parse(); + + println!("name: {:?}", cli.name.as_deref()); +} diff --git a/third_party/rust/clap/examples/tutorial_derive/03_04_subcommands.rs b/third_party/rust/clap/examples/tutorial_derive/03_04_subcommands.rs new file mode 100644 index 0000000000..86cf444c21 --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/03_04_subcommands.rs @@ -0,0 +1,27 @@ +use clap::{Parser, Subcommand}; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +#[clap(propagate_version = true)] +struct Cli { + #[clap(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Adds files to myapp + Add { name: Option<String> }, +} + +fn main() { + let cli = Cli::parse(); + + // You can check for the existence of subcommands, and if found use their + // matches just as you would the top level cmd + match &cli.command { + Commands::Add { name } => { + println!("'myapp add' was used, name is: {:?}", name) + } + } +} diff --git a/third_party/rust/clap/examples/tutorial_derive/03_04_subcommands_alt.rs b/third_party/rust/clap/examples/tutorial_derive/03_04_subcommands_alt.rs new file mode 100644 index 0000000000..0a5b60682d --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/03_04_subcommands_alt.rs @@ -0,0 +1,32 @@ +use clap::{Args, Parser, Subcommand}; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +#[clap(propagate_version = true)] +struct Cli { + #[clap(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Adds files to myapp + Add(Add), +} + +#[derive(Args)] +struct Add { + name: Option<String>, +} + +fn main() { + let cli = Cli::parse(); + + // You can check for the existence of subcommands, and if found use their + // matches just as you would the top level cmd + match &cli.command { + Commands::Add(name) => { + println!("'myapp add' was used, name is: {:?}", name.name) + } + } +} diff --git a/third_party/rust/clap/examples/tutorial_derive/03_05_default_values.rs b/third_party/rust/clap/examples/tutorial_derive/03_05_default_values.rs new file mode 100644 index 0000000000..af4532bbc7 --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/03_05_default_values.rs @@ -0,0 +1,14 @@ +use clap::Parser; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + #[clap(default_value_t = String::from("alice"))] + name: String, +} + +fn main() { + let cli = Cli::parse(); + + println!("name: {:?}", cli.name); +} diff --git a/third_party/rust/clap/examples/tutorial_derive/04_01_enum.rs b/third_party/rust/clap/examples/tutorial_derive/04_01_enum.rs new file mode 100644 index 0000000000..3a2df391ff --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/04_01_enum.rs @@ -0,0 +1,28 @@ +use clap::{ArgEnum, Parser}; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + /// What mode to run the program in + #[clap(arg_enum)] + mode: Mode, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ArgEnum)] +enum Mode { + Fast, + Slow, +} + +fn main() { + let cli = Cli::parse(); + + match cli.mode { + Mode::Fast => { + println!("Hare"); + } + Mode::Slow => { + println!("Tortoise"); + } + } +} diff --git a/third_party/rust/clap/examples/tutorial_derive/04_02_parse.rs b/third_party/rust/clap/examples/tutorial_derive/04_02_parse.rs new file mode 100644 index 0000000000..5f4cbadc04 --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/04_02_parse.rs @@ -0,0 +1,15 @@ +use clap::Parser; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + /// Network port to use + #[clap(parse(try_from_str))] + port: usize, +} + +fn main() { + let cli = Cli::parse(); + + println!("PORT = {}", cli.port); +} diff --git a/third_party/rust/clap/examples/tutorial_derive/04_02_validate.rs b/third_party/rust/clap/examples/tutorial_derive/04_02_validate.rs new file mode 100644 index 0000000000..434f40c869 --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/04_02_validate.rs @@ -0,0 +1,34 @@ +use std::ops::RangeInclusive; + +use clap::Parser; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + /// Network port to use + #[clap(parse(try_from_str=port_in_range))] + port: usize, +} + +fn main() { + let cli = Cli::parse(); + + println!("PORT = {}", cli.port); +} + +const PORT_RANGE: RangeInclusive<usize> = 1..=65535; + +fn port_in_range(s: &str) -> Result<usize, String> { + let port: usize = s + .parse() + .map_err(|_| format!("`{}` isn't a port number", s))?; + if PORT_RANGE.contains(&port) { + Ok(port) + } else { + Err(format!( + "Port not in range {}-{}", + PORT_RANGE.start(), + PORT_RANGE.end() + )) + } +} diff --git a/third_party/rust/clap/examples/tutorial_derive/04_03_relations.rs b/third_party/rust/clap/examples/tutorial_derive/04_03_relations.rs new file mode 100644 index 0000000000..f0e1e5913b --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/04_03_relations.rs @@ -0,0 +1,72 @@ +use clap::{ArgGroup, Parser}; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +#[clap(group( + ArgGroup::new("vers") + .required(true) + .args(&["set-ver", "major", "minor", "patch"]), + ))] +struct Cli { + /// set version manually + #[clap(long, value_name = "VER")] + set_ver: Option<String>, + + /// auto inc major + #[clap(long)] + major: bool, + + /// auto inc minor + #[clap(long)] + minor: bool, + + /// auto inc patch + #[clap(long)] + patch: bool, + + /// some regular input + #[clap(group = "input")] + input_file: Option<String>, + + /// some special input argument + #[clap(long, group = "input")] + spec_in: Option<String>, + + #[clap(short, requires = "input")] + config: Option<String>, +} + +fn main() { + let cli = Cli::parse(); + + // Let's assume the old version 1.2.3 + let mut major = 1; + let mut minor = 2; + let mut patch = 3; + + // See if --set-ver was used to set the version manually + let version = if let Some(ver) = cli.set_ver.as_deref() { + ver.to_string() + } else { + // Increment the one requested (in a real program, we'd reset the lower numbers) + let (maj, min, pat) = (cli.major, cli.minor, cli.patch); + match (maj, min, pat) { + (true, _, _) => major += 1, + (_, true, _) => minor += 1, + (_, _, true) => patch += 1, + _ => unreachable!(), + }; + format!("{}.{}.{}", major, minor, patch) + }; + + println!("Version: {}", version); + + // Check for usage of -c + if let Some(config) = cli.config.as_deref() { + let input = cli + .input_file + .as_deref() + .unwrap_or_else(|| cli.spec_in.as_deref().unwrap()); + println!("Doing work using input {} and config {}", input, config); + } +} diff --git a/third_party/rust/clap/examples/tutorial_derive/04_04_custom.rs b/third_party/rust/clap/examples/tutorial_derive/04_04_custom.rs new file mode 100644 index 0000000000..a03345b829 --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/04_04_custom.rs @@ -0,0 +1,92 @@ +use clap::{CommandFactory, ErrorKind, Parser}; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + /// set version manually + #[clap(long, value_name = "VER")] + set_ver: Option<String>, + + /// auto inc major + #[clap(long)] + major: bool, + + /// auto inc minor + #[clap(long)] + minor: bool, + + /// auto inc patch + #[clap(long)] + patch: bool, + + /// some regular input + input_file: Option<String>, + + /// some special input argument + #[clap(long)] + spec_in: Option<String>, + + #[clap(short)] + config: Option<String>, +} + +fn main() { + let cli = Cli::parse(); + + // Let's assume the old version 1.2.3 + let mut major = 1; + let mut minor = 2; + let mut patch = 3; + + // See if --set-ver was used to set the version manually + let version = if let Some(ver) = cli.set_ver.as_deref() { + if cli.major || cli.minor || cli.patch { + let mut cmd = Cli::command(); + cmd.error( + ErrorKind::ArgumentConflict, + "Can't do relative and absolute version change", + ) + .exit(); + } + ver.to_string() + } else { + // Increment the one requested (in a real program, we'd reset the lower numbers) + let (maj, min, pat) = (cli.major, cli.minor, cli.patch); + match (maj, min, pat) { + (true, false, false) => major += 1, + (false, true, false) => minor += 1, + (false, false, true) => patch += 1, + _ => { + let mut cmd = Cli::command(); + cmd.error( + ErrorKind::ArgumentConflict, + "Can only modify one version field", + ) + .exit(); + } + }; + format!("{}.{}.{}", major, minor, patch) + }; + + println!("Version: {}", version); + + // Check for usage of -c + if let Some(config) = cli.config.as_deref() { + // todo: remove `#[allow(clippy::or_fun_call)]` lint when MSRV is bumped. + #[allow(clippy::or_fun_call)] + let input = cli + .input_file + .as_deref() + // 'or' is preferred to 'or_else' here since `Option::as_deref` is 'const' + .or(cli.spec_in.as_deref()) + .unwrap_or_else(|| { + let mut cmd = Cli::command(); + cmd.error( + ErrorKind::MissingRequiredArgument, + "INPUT_FILE or --spec-in is required when using --config", + ) + .exit() + }); + println!("Doing work using input {} and config {}", input, config); + } +} diff --git a/third_party/rust/clap/examples/tutorial_derive/05_01_assert.rs b/third_party/rust/clap/examples/tutorial_derive/05_01_assert.rs new file mode 100644 index 0000000000..12fdba9b92 --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/05_01_assert.rs @@ -0,0 +1,21 @@ +use clap::Parser; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + /// Network port to use + #[clap(parse(try_from_str))] + port: usize, +} + +fn main() { + let cli = Cli::parse(); + + println!("PORT = {}", cli.port); +} + +#[test] +fn verify_app() { + use clap::CommandFactory; + Cli::command().debug_assert() +} diff --git a/third_party/rust/clap/examples/tutorial_derive/README.md b/third_party/rust/clap/examples/tutorial_derive/README.md new file mode 100644 index 0000000000..706e76c09e --- /dev/null +++ b/third_party/rust/clap/examples/tutorial_derive/README.md @@ -0,0 +1,642 @@ +# Tutorial + +*Jump to [builder tutorial](../tutorial_builder/README.md)* + +1. [Quick Start](#quick-start) +2. [Configuring the Parser](#configuring-the-parser) +3. [Adding Arguments](#adding-arguments) + 1. [Positionals](#positionals) + 2. [Options](#options) + 3. [Flags](#flags) + 4. [Subcommands](#subcommands) + 5. [Defaults](#defaults) +4. Validation + 1. [Enumerated values](#enumerated-values) + 2. [Validated values](#validated-values) + 3. [Argument Relations](#argument-relations) + 4. [Custom Validation](#custom-validation) +5. [Tips](#tips) +6. [Contributing](#contributing) + +## Quick Start + +You can create an application declaratively with a `struct` and some +attributes. **This requires enabling the `derive` feature flag.** + +[Example:](01_quick.rs) +```console +$ 01_quick_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 01_quick_derive[EXE] [OPTIONS] [NAME] [SUBCOMMAND] + +ARGS: + <NAME> Optional name to operate on + +OPTIONS: + -c, --config <FILE> Sets a custom config file + -d, --debug Turn debugging information on + -h, --help Print help information + -V, --version Print version information + +SUBCOMMANDS: + help Print this message or the help of the given subcommand(s) + test does testing things + +``` + +By default, the program does nothing: +```console +$ 01_quick_derive +Debug mode is off + +``` + +But you can mix and match the various features +```console +$ 01_quick_derive -dd test +Debug mode is on +Not printing testing lists... + +``` + +In addition to this tutorial, see the [derive reference](../derive_ref/README.md). + +## Configuring the Parser + +You use derive `Parser` the start building a parser. + +[Example:](02_apps.rs) +```console +$ 02_apps_derive --help +MyApp 1.0 +Kevin K. <kbknapp@gmail.com> +Does awesome things + +USAGE: + 02_apps_derive[EXE] --two <TWO> --one <ONE> + +OPTIONS: + -h, --help Print help information + --one <ONE> + --two <TWO> + -V, --version Print version information + +$ 02_apps_derive --version +MyApp 1.0 + +``` + +You can use `#[clap(author, version, about)]` attribute defaults to fill these fields in from your `Cargo.toml` file. + +[Example:](02_crate.rs) +```console +$ 02_crate_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 02_crate_derive[EXE] --two <TWO> --one <ONE> + +OPTIONS: + -h, --help Print help information + --one <ONE> + --two <TWO> + -V, --version Print version information + +$ 02_crate_derive --version +clap [..] + +``` + +You can use attributes to change the application level behavior of clap. Any `Command` builder function can be used as an attribute. + +[Example:](02_app_settings.rs) +```console +$ 02_app_settings_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 02_app_settings_derive[EXE] --two <TWO> --one <ONE> + +OPTIONS: + --two <TWO> + --one <ONE> + -h, --help Print help information + -V, --version Print version information + +$ 02_app_settings_derive --one -1 --one -3 --two 10 +two: "10" +one: "-3" + +``` + +## Adding Arguments + +### Positionals + +You can have users specify values by their position on the command-line: + +[Example:](03_03_positional.rs) +```console +$ 03_03_positional_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_03_positional_derive[EXE] [NAME] + +ARGS: + <NAME> + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 03_03_positional_derive +name: None + +$ 03_03_positional_derive bob +name: Some("bob") + +``` + +### Options + +You can name your arguments with a flag: +- Order doesn't matter +- They can be optional +- Intent is clearer + +The `#[clap(short = 'c')]` and `#[clap(long = "name")]` attributes that define +the flags are `Arg` methods that are derived from the field name when no value +is specified (`#[clap(short)]` and `#[clap(long)]`). + +[Example:](03_02_option.rs) +```console +$ 03_02_option_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_02_option_derive[EXE] [OPTIONS] + +OPTIONS: + -h, --help Print help information + -n, --name <NAME> + -V, --version Print version information + +$ 03_02_option_derive +name: None + +$ 03_02_option_derive --name bob +name: Some("bob") + +$ 03_02_option_derive --name=bob +name: Some("bob") + +$ 03_02_option_derive -n bob +name: Some("bob") + +$ 03_02_option_derive -n=bob +name: Some("bob") + +$ 03_02_option_derive -nbob +name: Some("bob") + +``` + +### Flags + +Flags can also be switches that can be on/off. This is enabled via the +`#[clap(parse(from_flag)]` attribute though this is implied when the field is a +`bool`. + +[Example:](03_01_flag_bool.rs) +```console +$ 03_01_flag_bool_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_01_flag_bool_derive[EXE] [OPTIONS] + +OPTIONS: + -h, --help Print help information + -v, --verbose + -V, --version Print version information + +$ 03_01_flag_bool_derive +verbose: false + +$ 03_01_flag_bool_derive --verbose +verbose: true + +$ 03_01_flag_bool_derive --verbose --verbose +? failed +error: The argument '--verbose' was provided more than once, but cannot be used multiple times + +USAGE: + 03_01_flag_bool_derive[EXE] [OPTIONS] + +For more information try --help + +``` + +Or counted with `#[clap(parse(from_occurrences))]`: + +[Example:](03_01_flag_count.rs) +```console +$ 03_01_flag_count_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_01_flag_count_derive[EXE] [OPTIONS] + +OPTIONS: + -h, --help Print help information + -v, --verbose + -V, --version Print version information + +$ 03_01_flag_count_derive +verbose: 0 + +$ 03_01_flag_count_derive --verbose +verbose: 1 + +$ 03_01_flag_count_derive --verbose --verbose +verbose: 2 + +``` + +### Subcommands + +Subcommands are derived with `#[derive(Subcommand)]` and be added via `#[clap(subcommand)]` attribute. Each +instance of a Subcommand can have its own version, author(s), Args, and even its own +subcommands. + +[Example:](03_04_subcommands.rs) +```console +$ 03_04_subcommands_derive help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_04_subcommands_derive[EXE] <SUBCOMMAND> + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +SUBCOMMANDS: + add Adds files to myapp + help Print this message or the help of the given subcommand(s) + +$ 03_04_subcommands_derive help add +03_04_subcommands_derive[EXE]-add [..] +Adds files to myapp + +USAGE: + 03_04_subcommands_derive[EXE] add [NAME] + +ARGS: + <NAME> + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 03_04_subcommands_derive add bob +'myapp add' was used, name is: Some("bob") + +``` + +Above, we used a struct-variant to define the `add` subcommand. Alternatively, +you can +[use a struct for your subcommand's arguments](03_04_subcommands_alt.rs). + +Because we used `command: Commands` instead of `command: Option<Commands>`: +```console +$ 03_04_subcommands_derive +? failed +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_04_subcommands_derive[EXE] <SUBCOMMAND> + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +SUBCOMMANDS: + add Adds files to myapp + help Print this message or the help of the given subcommand(s) + +``` + +Because we added `#[clap(propagate_version = true)]`: +```console +$ 03_04_subcommands_derive --version +clap [..] + +$ 03_04_subcommands_derive add --version +03_04_subcommands_derive[EXE]-add [..] + +``` + +### Defaults + +We've previously showed that arguments can be `required` or optional. When +optional, you work with an `Option` and can `unwrap_or`. Alternatively, you can +set `#[clap(default_value_t)]`. + +[Example:](03_05_default_values.rs) +```console +$ 03_05_default_values_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 03_05_default_values_derive[EXE] [NAME] + +ARGS: + <NAME> [default: alice] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 03_05_default_values_derive +name: "alice" + +$ 03_05_default_values_derive bob +name: "bob" + +``` + +## Validation + +### Enumerated values + +If you have arguments of specific values you want to test for, you can derive +`ArgEnum`. + +This allows you specify the valid values for that argument. If the user does not use one of +those specific values, they will receive a graceful exit with error message informing them +of the mistake, and what the possible valid values are + +[Example:](04_01_enum.rs) +```console +$ 04_01_enum_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_01_enum_derive[EXE] <MODE> + +ARGS: + <MODE> What mode to run the program in [possible values: fast, slow] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 04_01_enum_derive fast +Hare + +$ 04_01_enum_derive slow +Tortoise + +$ 04_01_enum_derive medium +? failed +error: "medium" isn't a valid value for '<MODE>' + [possible values: fast, slow] + +USAGE: + 04_01_enum_derive[EXE] <MODE> + +For more information try --help + +``` + +### Validated values + +More generally, you can validate and parse into any data type. + +[Example:](04_02_parse.rs) +```console +$ 04_02_parse_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_02_parse_derive[EXE] <PORT> + +ARGS: + <PORT> Network port to use + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 04_02_parse_derive 22 +PORT = 22 + +$ 04_02_parse_derive foobar +? failed +error: Invalid value "foobar" for '<PORT>': invalid digit found in string + +For more information try --help + +``` + +A custom parser can be used to improve the error messages or provide additional validation: + +[Example:](04_02_validate.rs) +```console +$ 04_02_validate_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_02_validate_derive[EXE] <PORT> + +ARGS: + <PORT> Network port to use + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 04_02_validate_derive 22 +PORT = 22 + +$ 04_02_validate_derive foobar +? failed +error: Invalid value "foobar" for '<PORT>': `foobar` isn't a port number + +For more information try --help + +$ 04_02_validate_derive 0 +? failed +error: Invalid value "0" for '<PORT>': Port not in range 1-65535 + +For more information try --help + +``` + +### Argument Relations + +You can declare dependencies or conflicts between `Arg`s or even `ArgGroup`s. + +`ArgGroup`s make it easier to declare relations instead of having to list each +individually, or when you want a rule to apply "any but not all" arguments. + +Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be +present out of a given set. Imagine that you had multiple arguments, and you want one of them to +be required, but making all of them required isn't feasible because perhaps they conflict with +each other. + +[Example:](04_03_relations.rs) +```console +$ 04_03_relations_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_03_relations_derive[EXE] [OPTIONS] <--set-ver <VER>|--major|--minor|--patch> [INPUT_FILE] + +ARGS: + <INPUT_FILE> some regular input + +OPTIONS: + -c <CONFIG> + -h, --help Print help information + --major auto inc major + --minor auto inc minor + --patch auto inc patch + --set-ver <VER> set version manually + --spec-in <SPEC_IN> some special input argument + -V, --version Print version information + +$ 04_03_relations_derive +? failed +error: The following required arguments were not provided: + <--set-ver <VER>|--major|--minor|--patch> + +USAGE: + 04_03_relations_derive[EXE] [OPTIONS] <--set-ver <VER>|--major|--minor|--patch> [INPUT_FILE] + +For more information try --help + +$ 04_03_relations_derive --major +Version: 2.2.3 + +$ 04_03_relations_derive --major --minor +? failed +error: The argument '--major' cannot be used with '--minor' + +USAGE: + 04_03_relations_derive[EXE] <--set-ver <VER>|--major|--minor|--patch> + +For more information try --help + +$ 04_03_relations_derive --major -c config.toml +? failed +error: The following required arguments were not provided: + <INPUT_FILE|--spec-in <SPEC_IN>> + +USAGE: + 04_03_relations_derive[EXE] -c <CONFIG> <--set-ver <VER>|--major|--minor|--patch> <INPUT_FILE|--spec-in <SPEC_IN>> + +For more information try --help + +$ 04_03_relations_derive --major -c config.toml --spec-in input.txt +Version: 2.2.3 +Doing work using input input.txt and config config.toml + +``` + +### Custom Validation + +As a last resort, you can create custom errors with the basics of clap's formatting. + +[Example:](04_04_custom.rs) +```console +$ 04_04_custom_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_04_custom_derive[EXE] [OPTIONS] [INPUT_FILE] + +ARGS: + <INPUT_FILE> some regular input + +OPTIONS: + -c <CONFIG> + -h, --help Print help information + --major auto inc major + --minor auto inc minor + --patch auto inc patch + --set-ver <VER> set version manually + --spec-in <SPEC_IN> some special input argument + -V, --version Print version information + +$ 04_04_custom_derive +? failed +error: Can only modify one version field + +USAGE: + clap [OPTIONS] [INPUT_FILE] + +For more information try --help + +$ 04_04_custom_derive --major +Version: 2.2.3 + +$ 04_04_custom_derive --major --minor +? failed +error: Can only modify one version field + +USAGE: + clap [OPTIONS] [INPUT_FILE] + +For more information try --help + +$ 04_04_custom_derive --major -c config.toml +? failed +Version: 2.2.3 +error: INPUT_FILE or --spec-in is required when using --config + +USAGE: + clap [OPTIONS] [INPUT_FILE] + +For more information try --help + +$ 04_04_custom_derive --major -c config.toml --spec-in input.txt +Version: 2.2.3 +Doing work using input input.txt and config config.toml + +``` + +## Tips + +- For more complex demonstration of features, see our [examples](../README.md). +- See the [derive reference](../derive_ref/README.md) to understand how to use + anything in the [builder API](https://docs.rs/clap/) in the derive API. +- Proactively check for bad `Command` configurations by calling `Command::debug_assert` in a test ([example](05_01_assert.rs)) + +## Contributing + +New example code: +- Please update the corresponding section in the [builder tutorial](../tutorial_builder/README.md) +- Building: They must be added to [Cargo.toml](../../Cargo.toml) with the appropriate `required-features`. +- Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax (generally they'll go in here). + +See also the general [CONTRIBUTING](../../CONTRIBUTING.md). |