summaryrefslogtreecommitdiffstats
path: root/third_party/rust/clap/examples
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/clap/examples
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/clap/examples')
-rw-r--r--third_party/rust/clap/examples/README.md40
-rw-r--r--third_party/rust/clap/examples/cargo-example-derive.md45
-rw-r--r--third_party/rust/clap/examples/cargo-example-derive.rs22
-rw-r--r--third_party/rust/clap/examples/cargo-example.md45
-rw-r--r--third_party/rust/clap/examples/cargo-example.rs23
-rw-r--r--third_party/rust/clap/examples/demo.md20
-rw-r--r--third_party/rust/clap/examples/demo.rs24
-rw-r--r--third_party/rust/clap/examples/derive_ref/README.md429
-rw-r--r--third_party/rust/clap/examples/derive_ref/augment_args.rs27
-rw-r--r--third_party/rust/clap/examples/derive_ref/augment_subcommands.rs21
-rw-r--r--third_party/rust/clap/examples/derive_ref/custom-bool.md47
-rw-r--r--third_party/rust/clap/examples/derive_ref/custom-bool.rs32
-rw-r--r--third_party/rust/clap/examples/derive_ref/flatten_hand_args.rs53
-rw-r--r--third_party/rust/clap/examples/derive_ref/hand_subcommand.rs79
-rw-r--r--third_party/rust/clap/examples/derive_ref/interop_tests.md256
-rw-r--r--third_party/rust/clap/examples/escaped-positional-derive.md65
-rw-r--r--third_party/rust/clap/examples/escaped-positional-derive.rs27
-rw-r--r--third_party/rust/clap/examples/escaped-positional.md65
-rw-r--r--third_party/rust/clap/examples/escaped-positional.rs26
-rw-r--r--third_party/rust/clap/examples/git-derive.md140
-rw-r--r--third_party/rust/clap/examples/git-derive.rs99
-rw-r--r--third_party/rust/clap/examples/git.md138
-rw-r--r--third_party/rust/clap/examples/git.rs101
-rw-r--r--third_party/rust/clap/examples/multicall-busybox.md46
-rw-r--r--third_party/rust/clap/examples/multicall-busybox.rs48
-rw-r--r--third_party/rust/clap/examples/multicall-hostname.md14
-rw-r--r--third_party/rust/clap/examples/multicall-hostname.rs19
-rw-r--r--third_party/rust/clap/examples/pacman.md87
-rw-r--r--third_party/rust/clap/examples/pacman.rs102
-rw-r--r--third_party/rust/clap/examples/repl.rs94
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/01_quick.rs60
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/02_app_settings.rs16
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/02_apps.rs14
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/02_crate.rs13
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/03_01_flag_bool.rs9
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/03_01_flag_count.rs9
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/03_02_option.rs11
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/03_03_positional.rs9
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/03_04_subcommands.rs24
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/03_05_default_values.rs16
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/04_01_enum.rs62
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/04_01_possible.rs27
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/04_02_parse.rs19
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/04_02_validate.rs38
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/04_03_relations.rs69
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/04_04_custom.rs80
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/05_01_assert.rs26
-rw-r--r--third_party/rust/clap/examples/tutorial_builder/README.md664
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/01_quick.rs68
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/02_app_settings.rs20
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/02_apps.rs20
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/02_crate.rs17
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/03_01_flag_bool.rs14
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/03_01_flag_count.rs14
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/03_02_option.rs14
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/03_03_positional.rs13
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/03_04_subcommands.rs27
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/03_04_subcommands_alt.rs32
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/03_05_default_values.rs14
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/04_01_enum.rs28
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/04_02_parse.rs15
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/04_02_validate.rs34
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/04_03_relations.rs72
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/04_04_custom.rs92
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/05_01_assert.rs21
-rw-r--r--third_party/rust/clap/examples/tutorial_derive/README.md642
-rw-r--r--third_party/rust/clap/examples/typed-derive.md86
-rw-r--r--third_party/rust/clap/examples/typed-derive.rs46
68 files changed, 4689 insertions, 0 deletions
diff --git a/third_party/rust/clap/examples/README.md b/third_party/rust/clap/examples/README.md
new file mode 100644
index 0000000000..42ba88991a
--- /dev/null
+++ b/third_party/rust/clap/examples/README.md
@@ -0,0 +1,40 @@
+# Examples
+
+- Basic demo: [derive](demo.md)
+- Typed arguments: [derive](typed-derive.md)
+ - Topics:
+ - Custom `parse()`
+- Custom cargo command: [builder](cargo-example.md), [derive](cargo-example-derive.md)
+ - Topics:
+ - Subcommands
+ - Cargo plugins
+- git-like interface: [builder](git.md), [derive](git-derive.md)
+ - Topics:
+ - Subcommands
+ - External subcommands
+ - Optional subcommands
+ - Default subcommands
+- pacman-like interface: [builder](pacman.md)
+ - Topics:
+ - Flag subcommands
+ - Conflicting arguments
+- Escaped positionals with `--`: [builder](escaped-positional.md), [derive](escaped-positional-derive.md)
+- Multi-call
+ - busybox: [builder](multicall-busybox.md)
+ - Topics:
+ - Subcommands
+ - hostname: [builder](multicall-hostname.md)
+ - Topics:
+ - Subcommands
+- repl: [builder](repl.rs)
+ - Topics:
+ - Read-Eval-Print Loops / Custom command lines
+
+## Contributing
+
+New examples:
+- 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
+- Link the `.md` file from here
+
+See also the general [CONTRIBUTING](../CONTRIBUTING.md).
diff --git a/third_party/rust/clap/examples/cargo-example-derive.md b/third_party/rust/clap/examples/cargo-example-derive.md
new file mode 100644
index 0000000000..994c6d4d80
--- /dev/null
+++ b/third_party/rust/clap/examples/cargo-example-derive.md
@@ -0,0 +1,45 @@
+*Jump to [source](cargo-example-derive.rs)*
+
+For more on creating a custom subcommand, see [the cargo
+book](https://doc.rust-lang.org/cargo/reference/external-tools.html#custom-subcommands).
+The crate [`clap-cargo`](https://github.com/crate-ci/clap-cargo) can help in
+mimicking cargo's interface.
+
+The help looks like:
+```console
+$ cargo-example-derive --help
+cargo
+
+USAGE:
+ cargo <SUBCOMMAND>
+
+OPTIONS:
+ -h, --help Print help information
+
+SUBCOMMANDS:
+ example-derive A simple to use, efficient, and full-featured Command Line Argument Parser
+ help Print this message or the help of the given subcommand(s)
+
+$ cargo-example-derive example-derive --help
+cargo-example-derive [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ cargo example-derive [OPTIONS]
+
+OPTIONS:
+ -h, --help Print help information
+ --manifest-path <MANIFEST_PATH>
+ -V, --version Print version information
+
+```
+
+Then to directly invoke the command, run:
+```console
+$ cargo-example-derive example-derive
+None
+
+$ cargo-example-derive example-derive --manifest-path Cargo.toml
+Some("Cargo.toml")
+
+```
diff --git a/third_party/rust/clap/examples/cargo-example-derive.rs b/third_party/rust/clap/examples/cargo-example-derive.rs
new file mode 100644
index 0000000000..1ee0a02551
--- /dev/null
+++ b/third_party/rust/clap/examples/cargo-example-derive.rs
@@ -0,0 +1,22 @@
+// Note: this requires the `derive` feature
+
+use clap::Parser;
+
+#[derive(Parser)]
+#[clap(name = "cargo")]
+#[clap(bin_name = "cargo")]
+enum Cargo {
+ ExampleDerive(ExampleDerive),
+}
+
+#[derive(clap::Args)]
+#[clap(author, version, about, long_about = None)]
+struct ExampleDerive {
+ #[clap(long, parse(from_os_str))]
+ manifest_path: Option<std::path::PathBuf>,
+}
+
+fn main() {
+ let Cargo::ExampleDerive(args) = Cargo::parse();
+ println!("{:?}", args.manifest_path);
+}
diff --git a/third_party/rust/clap/examples/cargo-example.md b/third_party/rust/clap/examples/cargo-example.md
new file mode 100644
index 0000000000..9279cc4925
--- /dev/null
+++ b/third_party/rust/clap/examples/cargo-example.md
@@ -0,0 +1,45 @@
+*Jump to [source](cargo-example.rs)*
+
+For more on creating a custom subcommand, see [the cargo
+book](https://doc.rust-lang.org/cargo/reference/external-tools.html#custom-subcommands).
+The crate [`clap-cargo`](https://github.com/crate-ci/clap-cargo) can help in
+mimicking cargo's interface.
+
+The help looks like:
+```console
+$ cargo-example --help
+cargo
+
+USAGE:
+ cargo <SUBCOMMAND>
+
+OPTIONS:
+ -h, --help Print help information
+
+SUBCOMMANDS:
+ example A simple to use, efficient, and full-featured Command Line Argument Parser
+ help Print this message or the help of the given subcommand(s)
+
+$ cargo-example example --help
+cargo-example [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ cargo example [OPTIONS]
+
+OPTIONS:
+ -h, --help Print help information
+ --manifest-path <PATH>
+ -V, --version Print version information
+
+```
+
+Then to directly invoke the command, run:
+```console
+$ cargo-example example
+None
+
+$ cargo-example example --manifest-path Cargo.toml
+Some("Cargo.toml")
+
+```
diff --git a/third_party/rust/clap/examples/cargo-example.rs b/third_party/rust/clap/examples/cargo-example.rs
new file mode 100644
index 0000000000..149bf59918
--- /dev/null
+++ b/third_party/rust/clap/examples/cargo-example.rs
@@ -0,0 +1,23 @@
+// Note: this requires the `cargo` feature
+
+fn main() {
+ let cmd = clap::Command::new("cargo")
+ .bin_name("cargo")
+ .subcommand_required(true)
+ .subcommand(
+ clap::command!("example").arg(
+ clap::arg!(--"manifest-path" <PATH>)
+ .required(false)
+ .allow_invalid_utf8(true),
+ ),
+ );
+ let matches = cmd.get_matches();
+ let matches = match matches.subcommand() {
+ Some(("example", matches)) => matches,
+ _ => unreachable!("clap should ensure we don't get here"),
+ };
+ let manifest_path = matches
+ .value_of_os("manifest-path")
+ .map(std::path::PathBuf::from);
+ println!("{:?}", manifest_path);
+}
diff --git a/third_party/rust/clap/examples/demo.md b/third_party/rust/clap/examples/demo.md
new file mode 100644
index 0000000000..9b0e7e260f
--- /dev/null
+++ b/third_party/rust/clap/examples/demo.md
@@ -0,0 +1,20 @@
+*Jump to [source](demo.rs)*
+
+**This requires enabling the `derive` feature flag.**
+
+Used to validate README.md's content
+```console
+$ demo --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ demo[EXE] [OPTIONS] --name <NAME>
+
+OPTIONS:
+ -c, --count <COUNT> Number of times to greet [default: 1]
+ -h, --help Print help information
+ -n, --name <NAME> Name of the person to greet
+ -V, --version Print version information
+
+```
diff --git a/third_party/rust/clap/examples/demo.rs b/third_party/rust/clap/examples/demo.rs
new file mode 100644
index 0000000000..262a81a2c1
--- /dev/null
+++ b/third_party/rust/clap/examples/demo.rs
@@ -0,0 +1,24 @@
+// Note: this requires the `derive` feature
+
+use clap::Parser;
+
+/// Simple program to greet a person
+#[derive(Parser, Debug)]
+#[clap(author, version, about, long_about = None)]
+struct Args {
+ /// Name of the person to greet
+ #[clap(short, long)]
+ name: String,
+
+ /// Number of times to greet
+ #[clap(short, long, default_value_t = 1)]
+ count: u8,
+}
+
+fn main() {
+ let args = Args::parse();
+
+ for _ in 0..args.count {
+ println!("Hello {}!", args.name)
+ }
+}
diff --git a/third_party/rust/clap/examples/derive_ref/README.md b/third_party/rust/clap/examples/derive_ref/README.md
new file mode 100644
index 0000000000..11001dde85
--- /dev/null
+++ b/third_party/rust/clap/examples/derive_ref/README.md
@@ -0,0 +1,429 @@
+# Derive Reference
+
+1. [Overview](#overview)
+2. [Attributes](#attributes)
+ 1. [Terminology](#terminology)
+ 2. [Command Attributes](#command-attributes)
+ 3. [Arg Attributes](#arg-attributes)
+ 4. [Arg Enum Attributes](#arg-enum-attributes)
+ 5. [Possible Value Attributes](#possible-value-attributes)
+3. [Arg Types](#arg-types)
+4. [Doc Comments](#doc-comments)
+5. [Tips](#tips)
+6. [Mixing Builder and Derive APIS](#mixing-builder-and-derive-apis)
+
+## Overview
+
+To derive `clap` types, you need to enable the `derive` feature flag.
+
+See [demo.rs](../demo.rs) and [demo.md](../demo.md) for a brief example.
+
+Let's start by breaking down the anatomy of the derive attributes:
+```rust
+use clap::{Parser, Args, Subcommand, ArgEnum};
+
+/// Doc comment
+#[derive(Parser)]
+#[clap(APP ATTRIBUTE)]
+struct Cli {
+ /// Doc comment
+ #[clap(ARG ATTRIBUTE)]
+ field: UserType,
+
+ #[clap(arg_enum, ARG ATTRIBUTE...)]
+ field: EnumValues,
+
+ #[clap(flatten)]
+ delegate: Struct,
+
+ #[clap(subcommand)]
+ command: Command,
+}
+
+/// Doc comment
+#[derive(Args)]
+#[clap(PARENT APP ATTRIBUTE)]
+struct Struct {
+ /// Doc comment
+ #[clap(ARG ATTRIBUTE)]
+ field: UserType,
+}
+
+/// Doc comment
+#[derive(Subcommand)]
+#[clap(PARENT APP ATTRIBUTE)]
+enum Command {
+ /// Doc comment
+ #[clap(APP ATTRIBUTE)]
+ Variant1(Struct),
+
+ /// Doc comment
+ #[clap(APP ATTRIBUTE)]
+ Variant2 {
+ /// Doc comment
+ #[clap(ARG ATTRIBUTE)]
+ field: UserType,
+ }
+}
+
+/// Doc comment
+#[derive(ArgEnum)]
+#[clap(ARG ENUM ATTRIBUTE)]
+enum EnumValues {
+ /// Doc comment
+ #[clap(POSSIBLE VALUE ATTRIBUTE)]
+ Variant1,
+}
+
+fn main() {
+ let cli = Cli::parse();
+}
+```
+
+- `Parser` parses arguments into a `struct` (arguments) or `enum` (subcommands).
+- `Args` allows defining a set of re-usable arguments that get merged into their parent container.
+- `Subcommand` defines available subcommands.
+ - Subcommand arguments can be defined in a struct-variant or automatically flattened with a tuple-variant.
+- `ArgEnum` allows parsing a value directly into an `enum`, erroring on unsupported values.
+ - The derive doesn't work on enums that contain non-unit variants, unless they are skipped
+
+See also the [tutorial](../tutorial_derive/README.md) and [examples](../README.md).
+
+## Attributes
+
+### Terminology
+
+**Raw attributes** are forwarded directly to the underlying `clap` builder. Any
+`Command`, `Arg`, or `PossibleValue` method can be used as an attribute.
+
+Raw attributes come in two different syntaxes:
+```rust
+#[clap(
+ global = true, // name = arg form, neat for one-arg methods
+ required_if_eq("out", "file") // name(arg1, arg2, ...) form.
+)]
+```
+
+- `method = arg` can only be used for methods which take only one argument.
+- `method(arg1, arg2)` can be used with any method.
+
+As long as `method_name` is not one of the magical methods - it will be
+translated into a mere method call.
+
+**Magic attributes** have post-processing done to them, whether that is
+- Providing of defaults
+- Special behavior is triggered off of it
+
+Magic attributes are more constrained in the syntax they support, usually just
+`<attr> = <value>` though some use `<attr>(<value>)` instead. See the specific
+magic attributes documentation for details. This allows users to access the
+raw behavior of an attribute via `<attr>(<value>)` syntax.
+
+**NOTE:** Some attributes are inferred from [Arg Types](#arg-types) and [Doc
+Comments](#doc-comments). Explicit attributes take precedence over inferred
+attributes.
+
+### Command Attributes
+
+These correspond to a `clap::Command` which is used for both top-level parsers and
+when defining subcommands.
+
+**Magic attributes:**
+- `name = <expr>`: `clap::Command::name`
+ - When not present: [crate `name`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-name-field) (`Parser` container), variant name (`Subcommand` variant)
+- `version [= <expr>]`: `clap::Command::version`
+ - When not present: no version set
+ - Without `<expr>`: defaults to [crate `version`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field)
+- `author [= <expr>]`: `clap::Command::author`
+ - When not present: no author set
+ - Without `<expr>`: defaults to [crate `authors`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-authors-field)
+- `about [= <expr>]`: `clap::Command::about`
+ - When not present: [Doc comment summary](#doc-comments)
+ - Without `<expr>`: [crate `description`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-description-field) (`Parser` container)
+ - **TIP:** When a doc comment is also present, you most likely want to add
+ `#[clap(long_about = None)]` to clear the doc comment so only `about`
+ gets shown with both `-h` and `--help`.
+- `long_about = <expr>`: `clap::Command::long_about`
+ - When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing
+- `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to `about` / `long_about`
+- `next_display_order`: `clap::Command::next_display_order`
+- `next_help_heading`: `clap::Command::next_help_heading`
+ - When `flatten`ing `Args`, this is scoped to just the args in this struct and any struct `flatten`ed into it
+- `rename_all = <expr>`: Override default field / variant name case conversion for `Command::name` / `Arg::name`
+ - When not present: `kebab-case`
+ - Available values: `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lower`, `UPPER`, `verbatim`
+- `rename_all_env = <expr>`: Override default field name case conversion for env variables for `clap::Arg::env`
+ - When not present: `SCREAMING_SNAKE_CASE`
+ - Available values: `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lower`, `UPPER`, `verbatim`
+
+And for `Subcommand` variants:
+- `skip`: Ignore this variant
+- `flatten`: Delegates to the variant for more subcommands (must implement `Subcommand`)
+- `subcommand`: Nest subcommands under the current set of subcommands (must implement `Subcommand`)
+- `external_subcommand`: `clap::Command::allow_external_subcommand(true)`
+ - Variant must be either `Variant(Vec<String>)` or `Variant(Vec<OsString>)`
+
+**Raw attributes:** Any [`Command` method](https://docs.rs/clap/latest/clap/type.Command.html) can also be used as an attribute, see [Terminology](#terminology) for syntax.
+- e.g. `#[clap(arg_required_else_help(true))]` would translate to `cmd.arg_required_else_help(true)`
+
+### Arg Attributes
+
+These correspond to a `clap::Arg`.
+
+**Magic attributes**:
+- `name = <expr>`: `clap::Arg::new`
+ - When not present: case-converted field name is used
+- `help = <expr>`: `clap::Arg::help`
+ - When not present: [Doc comment summary](#doc-comments)
+- `long_help = <expr>`: `clap::Arg::long_help`
+ - When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing
+- `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to `help` / `long_help`
+- `short [= <char>]`: `clap::Arg::short`
+ - When not present: no short set
+ - Without `<char>`: defaults to first character in the case-converted field name
+- `long [= <str>]`: `clap::Arg::long`
+ - When not present: no long set
+ - Without `<str>`: defaults to the case-converted field name
+- `env [= <str>]`: `clap::Arg::env` (needs `env` feature enabled)
+ - When not present: no env set
+ - Without `<str>`: defaults to the case-converted field name
+- `flatten`: Delegates to the field for more arguments (must implement `Args`)
+ - Only `help_heading` can be used with `flatten`. See
+ [clap-rs/clap#3269](https://github.com/clap-rs/clap/issues/3269) for why
+ arg attributes are not generally supported.
+ - **Tip:** Though we do apply a flattened `Args`'s Parent Command Attributes, this
+ makes reuse harder. Generally prefer putting the cmd attributes on the `Parser`
+ or on the flattened field.
+- `subcommand`: Delegates definition of subcommands to the field (must implement `Subcommand`)
+ - When `Option<T>`, the subcommand becomes optional
+- `from_global`: Read a `clap::Arg::global` argument (raw attribute), regardless of what subcommand you are in
+- `parse(<kind> [= <function>])`: `clap::Arg::validator` and `clap::ArgMatches::values_of_t`
+ - Default: `try_from_str`
+ - Warning: for `Path` / `OsString`, be sure to use `try_from_os_str`
+ - See [Arg Types](#arg-types) for more details
+- `arg_enum`: Parse the value using the `ArgEnum` trait
+- `skip [= <expr>]`: Ignore this field, filling in with `<expr>`
+ - Without `<expr>`: fills the field with `Default::default()`
+- `default_value = <str>`: `clap::Arg::default_value` and `clap::Arg::required(false)`
+- `default_value_t [= <expr>]`: `clap::Arg::default_value` and `clap::Arg::required(false)`
+ - Requires `std::fmt::Display` or `#[clap(arg_enum)]`
+ - Without `<expr>`, relies on `Default::default()`
+- `default_value_os_t [= <expr>]`: `clap::Arg::default_value_os` and `clap::Arg::required(false)`
+ - Requires `std::convert::Into<OsString>` or `#[clap(arg_enum)]`
+ - Without `<expr>`, relies on `Default::default()`
+
+**Raw attributes:** Any [`Arg` method](https://docs.rs/clap/latest/clap/struct.Arg.html) can also be used as an attribute, see [Terminology](#terminology) for syntax.
+- e.g. `#[clap(max_values(3))]` would translate to `arg.max_values(3)`
+
+### Arg Enum Attributes
+
+- `rename_all = <expr>`: Override default field / variant name case conversion for `PossibleValue::new`
+ - When not present: `kebab-case`
+ - Available values: `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lower`, `UPPER`, `verbatim`
+
+### Possible Value Attributes
+
+These correspond to a `clap::PossibleValue`.
+
+**Magic attributes**:
+- `name = <expr>`: `clap::PossibleValue::new`
+ - When not present: case-converted field name is used
+- `help = <expr>`: `clap::PossibleValue::help`
+ - When not present: [Doc comment summary](#doc-comments)
+
+**Raw attributes:** Any [`PossibleValue` method](https://docs.rs/clap/latest/clap/struct.PossibleValue.html) can also be used as an attribute, see [Terminology](#terminology) for syntax.
+- e.g. `#[clap(alias("foo"))]` would translate to `pv.alias("foo")`
+
+## Arg Types
+
+`clap` assumes some intent based on the type used:
+
+| Type | Effect | Implies |
+|---------------------|--------------------------------------|------------------------------------------------------------------|
+| `bool` | flag | `#[clap(parse(from_flag))]` |
+| `Option<T>` | optional argument | `.takes_value(true).required(false)` |
+| `Option<Option<T>>` | optional value for optional argument | `.takes_value(true).required(false).min_values(0).max_values(1)` |
+| `T` | required argument | `.takes_value(true).required(!has_default)` |
+| `Vec<T>` | `0..` occurrences of argument | `.takes_value(true).required(false).multiple_occurrences(true)` |
+| `Option<Vec<T>>` | `0..` occurrences of argument | `.takes_value(true).required(false).multiple_occurrences(true)` |
+
+Notes:
+- For custom type behavior, you can override the implied attributes/settings and/or set additional ones
+ - For example, see [custom-bool](./custom-bool.md)
+- `Option<Vec<T>>` will be `None` instead of `vec![]` if no arguments are provided.
+ - This gives the user some flexibility in designing their argument, like with `min_values(0)`
+
+You can then support your custom type with `#[clap(parse(<kind> [= <function>]))]`:
+
+| `<kind>` | Signature | Default `<function>` |
+|--------------------------|---------------------------------------|---------------------------------|
+| `from_str` | `fn(&str) -> T` | `::std::convert::From::from` |
+| `try_from_str` (default) | `fn(&str) -> Result<T, E>` | `::std::str::FromStr::from_str` |
+| `from_os_str` | `fn(&OsStr) -> T` | `::std::convert::From::from` |
+| `try_from_os_str` | `fn(&OsStr) -> Result<T, OsString>` | (no default function) |
+| `from_occurrences` | `fn(u64) -> T` | `value as T` |
+| `from_flag` | `fn(bool) -> T` | `::std::convert::From::from` |
+
+Notes:
+- `from_os_str`:
+ - Implies `arg.takes_value(true).allow_invalid_utf8(true)`
+- `try_from_os_str`:
+ - Implies `arg.takes_value(true).allow_invalid_utf8(true)`
+- `from_occurrences`:
+ - Implies `arg.takes_value(false).multiple_occurrences(true)`
+ - Reads from `clap::ArgMatches::occurrences_of` rather than a `value_of` function
+ - Note: operations on values, like `default_value`, are unlikely to do what you want
+- `from_flag`
+ - Implies `arg.takes_value(false)`
+ - Reads from `clap::ArgMatches::is_present` rather than a `value_of` function
+ - Note: operations on values, like `default_value`, are unlikely to do what you want
+
+**Warning:**
+- To support non-UTF8 paths, you must use `parse(from_os_str)`, otherwise
+ `clap` will use `clap::ArgMatches::value_of` with `PathBuf::FromStr`.
+
+## Doc Comments
+
+In clap, help messages for the whole binary can be specified
+via [`Command::about`] and [`Command::long_about`] while help messages
+for individual arguments can be specified via [`Arg::help`] and [`Arg::long_help`]".
+
+`long_*` variants are used when user calls the program with
+`--help` and "short" variants are used with `-h` flag.
+
+```rust
+# use clap::Parser;
+
+#[derive(Parser)]
+#[clap(about = "I am a program and I work, just pass `-h`", long_about = None)]
+struct Foo {
+ #[clap(short, help = "Pass `-h` and you'll see me!")]
+ bar: String,
+}
+```
+
+For convenience, doc comments can be used instead of raw methods
+(this example works exactly like the one above):
+
+```rust
+# use clap::Parser;
+
+#[derive(Parser)]
+/// I am a program and I work, just pass `-h`
+struct Foo {
+ /// Pass `-h` and you'll see me!
+ bar: String,
+}
+```
+
+**NOTE:** Attributes have priority over doc comments!
+
+**Top level doc comments always generate `Command::about/long_about` calls!**
+If you really want to use the `Command::about/long_about` methods (you likely don't),
+use the `about` / `long_about` attributes to override the calls generated from
+the doc comment. To clear `long_about`, you can use
+`#[clap(long_about = None)]`.
+
+**TIP:** Set `#![deny(missing_docs)]` to catch missing `--help` documentation at compile time.
+
+### Pre-processing
+
+```rust
+# use clap::Parser;
+#[derive(Parser)]
+/// Hi there, I'm Robo!
+///
+/// I like beeping, stumbling, eating your electricity,
+/// and making records of you singing in a shower.
+/// Pay up, or I'll upload it to youtube!
+struct Robo {
+ /// Call my brother SkyNet.
+ ///
+ /// I am artificial superintelligence. I won't rest
+ /// until I'll have destroyed humanity. Enjoy your
+ /// pathetic existence, you mere mortals.
+ #[clap(long)]
+ kill_all_humans: bool,
+}
+```
+
+A doc comment consists of three parts:
+- Short summary
+- A blank line (whitespace only)
+- Detailed description, all the rest
+
+The summary corresponds with `Command::about` / `Arg::help`. When a blank line is
+present, the whole doc comment will be passed to `Command::long_about` /
+`Arg::long_help`. Or in other words, a doc may result in just a `Command::about` /
+`Arg::help` or `Command::about` / `Arg::help` and `Command::long_about` /
+`Arg::long_help`
+
+In addition, when `verbatim_doc_comment` is not present, `clap` applies some preprocessing, including:
+
+- Strip leading and trailing whitespace from every line, if present.
+
+- Strip leading and trailing blank lines, if present.
+
+- Interpret each group of non-empty lines as a word-wrapped paragraph.
+
+ We replace newlines within paragraphs with spaces to allow the output
+ to be re-wrapped to the terminal width.
+
+- Strip any excess blank lines so that there is exactly one per paragraph break.
+
+- If the first paragraph ends in exactly one period,
+ remove the trailing period (i.e. strip trailing periods but not trailing ellipses).
+
+Sometimes you don't want this preprocessing to apply, for example the comment contains
+some ASCII art or markdown tables, you would need to preserve LFs along with
+blank lines and the leading/trailing whitespace. When you pass use the
+`verbatim_doc_comment` magic attribute, you preserve
+them.
+
+**Note:** Keep in mind that `verbatim_doc_comment` will *still*
+- Remove one leading space from each line, even if this attribute is present,
+ to allow for a space between `///` and the content.
+- Remove leading and trailing blank lines
+
+## Tips
+
+- To get access to a `Command` call `CommandFactory::command` (implemented when deriving `Parser`)
+- Proactively check for bad `Command` configurations by calling `Command::debug_assert` in a test ([example](../tutorial_derive/05_01_assert.rs))
+
+## Mixing Builder and Derive APIs
+
+The builder and derive APIs do not live in isolation. They can work together, which is especially helpful if some arguments can be specified at compile-time while others must be specified at runtime.
+
+### Using derived arguments in a builder application
+
+*[Jump to source](augment_args.rs)*
+
+When using the derive API, you can `#[clap(flatten)]` a struct deriving `Args` into a struct deriving `Args` or `Parser`. This example shows how you can augment a `Command` instance created using the builder API with `Args` created using the derive API.
+
+It uses the `Args::augment_args` method to add the arguments to the `Command` instance.
+
+Crates such as [clap-verbosity-flag](https://github.com/rust-cli/clap-verbosity-flag) provide structs that implement `Args` or `Parser`. Without the technique shown in this example, it would not be possible to use such crates with the builder API. `augment_args` to the rescue!
+
+### Using derived subcommands in a builder application
+
+*[Jump to source](augment_subcommands.rs)*
+
+When using the derive API, you can use `#[clap(subcommand)]` inside the struct to add subcommands. The type of the field is usually an enum that derived `Parser`. However, you can also add the subcommands in that enum to a `Command` instance created with the builder API.
+
+It uses the `Subcommand::augment_subcommands` method to add the subcommands to the `Command` instance.
+
+### Adding hand-implemented subcommands to a derived application
+
+*[Jump to source](hand_subcommand.rs)*
+
+When using the derive API, you can use `#[clap(subcommand)]` inside the struct to add subcommands. The type of the field is usually an enum that derived `Parser`. However, you can also implement the `Subcommand` trait manually on this enum (or any other type) and it can still be used inside the struct created with the derive API. The implementation of the `Subcommand` trait will use the builder API to add the subcommands to the `Command` instance created behind the scenes for you by the derive API.
+
+Notice how in the previous example we used `augment_subcommands` on an enum that derived `Parser`, whereas now we implement `augment_subcommands` ourselves, but the derive API calls it automatically since we used the `#[clap(subcommand)]` attribute.
+
+### Flattening hand-implemented args into a derived application
+
+*[Jump to source](flatten_hand_args.rs)*
+
+When using the derive API, you can use `#[clap(flatten)]` inside the struct to add arguments as if they were added directly to the containing struct. The type of the field is usually an struct that derived `Args`. However, you can also implement the `Args` trait manually on this struct (or any other type) and it can still be used inside the struct created with the derive API. The implementation of the `Args` trait will use the builder API to add the arguments to the `Command` instance created behind the scenes for you by the derive API.
+
+Notice how in the example 1 we used `augment_args` on the struct that derived `Parser`, whereas now we implement `augment_args` ourselves, but the derive API calls it automatically since we used the `#[clap(flatten)]` attribute.
diff --git a/third_party/rust/clap/examples/derive_ref/augment_args.rs b/third_party/rust/clap/examples/derive_ref/augment_args.rs
new file mode 100644
index 0000000000..59765ad61f
--- /dev/null
+++ b/third_party/rust/clap/examples/derive_ref/augment_args.rs
@@ -0,0 +1,27 @@
+use clap::{arg, Args as _, Command, FromArgMatches as _, Parser};
+
+#[derive(Parser, Debug)]
+struct DerivedArgs {
+ #[clap(short, long)]
+ derived: bool,
+}
+
+fn main() {
+ let cli = Command::new("CLI").arg(arg!(-b - -built));
+ // Augment built args with derived args
+ let cli = DerivedArgs::augment_args(cli);
+
+ let matches = cli.get_matches();
+ println!("Value of built: {:?}", matches.is_present("built"));
+ println!(
+ "Value of derived via ArgMatches: {:?}",
+ matches.is_present("derived")
+ );
+
+ // Since DerivedArgs implements FromArgMatches, we can extract it from the unstructured ArgMatches.
+ // This is the main benefit of using derived arguments.
+ let derived_matches = DerivedArgs::from_arg_matches(&matches)
+ .map_err(|err| err.exit())
+ .unwrap();
+ println!("Value of derived: {:#?}", derived_matches);
+}
diff --git a/third_party/rust/clap/examples/derive_ref/augment_subcommands.rs b/third_party/rust/clap/examples/derive_ref/augment_subcommands.rs
new file mode 100644
index 0000000000..299c7f8cf6
--- /dev/null
+++ b/third_party/rust/clap/examples/derive_ref/augment_subcommands.rs
@@ -0,0 +1,21 @@
+use clap::{Command, FromArgMatches as _, Parser, Subcommand as _};
+
+#[derive(Parser, Debug)]
+enum Subcommands {
+ Derived {
+ #[clap(short, long)]
+ derived_flag: bool,
+ },
+}
+
+fn main() {
+ let cli = Command::new("Built CLI");
+ // Augment with derived subcommands
+ let cli = Subcommands::augment_subcommands(cli);
+
+ let matches = cli.get_matches();
+ let derived_subcommands = Subcommands::from_arg_matches(&matches)
+ .map_err(|err| err.exit())
+ .unwrap();
+ println!("Derived subcommands: {:#?}", derived_subcommands);
+}
diff --git a/third_party/rust/clap/examples/derive_ref/custom-bool.md b/third_party/rust/clap/examples/derive_ref/custom-bool.md
new file mode 100644
index 0000000000..2769f20e8f
--- /dev/null
+++ b/third_party/rust/clap/examples/derive_ref/custom-bool.md
@@ -0,0 +1,47 @@
+*Jump to [source](custom-bool.rs)*
+
+Example of overriding the magic `bool` behavior
+
+```console
+$ custom-bool --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ custom-bool[EXE] [OPTIONS] --foo <FOO> <BOOM>
+
+ARGS:
+ <BOOM>
+
+OPTIONS:
+ --bar <BAR> [default: false]
+ --foo <FOO>
+ -h, --help Print help information
+ -V, --version Print version information
+
+$ custom-bool
+? failed
+error: The following required arguments were not provided:
+ --foo <FOO>
+ <BOOM>
+
+USAGE:
+ custom-bool[EXE] [OPTIONS] --foo <FOO> <BOOM>
+
+For more information try --help
+
+$ custom-bool --foo true false
+[examples/derive_ref/custom-bool.rs:31] opt = Opt {
+ foo: true,
+ bar: false,
+ boom: false,
+}
+
+$ custom-bool --foo true --bar true false
+[examples/derive_ref/custom-bool.rs:31] opt = Opt {
+ foo: true,
+ bar: true,
+ boom: false,
+}
+
+```
diff --git a/third_party/rust/clap/examples/derive_ref/custom-bool.rs b/third_party/rust/clap/examples/derive_ref/custom-bool.rs
new file mode 100644
index 0000000000..10f93f40ac
--- /dev/null
+++ b/third_party/rust/clap/examples/derive_ref/custom-bool.rs
@@ -0,0 +1,32 @@
+use clap::Parser;
+
+#[derive(Parser, Debug, PartialEq)]
+#[clap(author, version, about, long_about = None)]
+struct Opt {
+ // Default parser for `try_from_str` is FromStr::from_str.
+ // `impl FromStr for bool` parses `true` or `false` so this
+ // works as expected.
+ #[clap(long, parse(try_from_str))]
+ foo: bool,
+
+ // Of course, this could be done with an explicit parser function.
+ #[clap(long, parse(try_from_str = true_or_false), default_value_t)]
+ bar: bool,
+
+ // `bool` can be positional only with explicit `parse(...)` annotation
+ #[clap(parse(try_from_str))]
+ boom: bool,
+}
+
+fn true_or_false(s: &str) -> Result<bool, &'static str> {
+ match s {
+ "true" => Ok(true),
+ "false" => Ok(false),
+ _ => Err("expected `true` or `false`"),
+ }
+}
+
+fn main() {
+ let opt = Opt::parse();
+ dbg!(opt);
+}
diff --git a/third_party/rust/clap/examples/derive_ref/flatten_hand_args.rs b/third_party/rust/clap/examples/derive_ref/flatten_hand_args.rs
new file mode 100644
index 0000000000..2969457e18
--- /dev/null
+++ b/third_party/rust/clap/examples/derive_ref/flatten_hand_args.rs
@@ -0,0 +1,53 @@
+use clap::error::Error;
+use clap::{Arg, ArgMatches, Args, Command, FromArgMatches, Parser};
+
+#[derive(Debug)]
+struct CliArgs {
+ foo: bool,
+ bar: bool,
+ quuz: Option<String>,
+}
+
+impl FromArgMatches for CliArgs {
+ fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
+ Ok(Self {
+ foo: matches.is_present("foo"),
+ bar: matches.is_present("bar"),
+ quuz: matches.value_of("quuz").map(|quuz| quuz.to_owned()),
+ })
+ }
+ fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
+ self.foo |= matches.is_present("foo");
+ self.bar |= matches.is_present("bar");
+ if let Some(quuz) = matches.value_of("quuz") {
+ self.quuz = Some(quuz.to_owned());
+ }
+ Ok(())
+ }
+}
+
+impl Args for CliArgs {
+ fn augment_args(cmd: Command<'_>) -> Command<'_> {
+ cmd.arg(Arg::new("foo").short('f').long("foo"))
+ .arg(Arg::new("bar").short('b').long("bar"))
+ .arg(Arg::new("quuz").short('q').long("quuz").takes_value(true))
+ }
+ fn augment_args_for_update(cmd: Command<'_>) -> Command<'_> {
+ cmd.arg(Arg::new("foo").short('f').long("foo"))
+ .arg(Arg::new("bar").short('b').long("bar"))
+ .arg(Arg::new("quuz").short('q').long("quuz").takes_value(true))
+ }
+}
+
+#[derive(Parser, Debug)]
+struct Cli {
+ #[clap(short, long)]
+ top_level: bool,
+ #[clap(flatten)]
+ more_args: CliArgs,
+}
+
+fn main() {
+ let args = Cli::parse();
+ println!("{:#?}", args);
+}
diff --git a/third_party/rust/clap/examples/derive_ref/hand_subcommand.rs b/third_party/rust/clap/examples/derive_ref/hand_subcommand.rs
new file mode 100644
index 0000000000..5afd941327
--- /dev/null
+++ b/third_party/rust/clap/examples/derive_ref/hand_subcommand.rs
@@ -0,0 +1,79 @@
+use clap::error::{Error, ErrorKind};
+use clap::{ArgMatches, Args as _, Command, FromArgMatches, Parser, Subcommand};
+
+#[derive(Parser, Debug)]
+struct AddArgs {
+ name: Vec<String>,
+}
+#[derive(Parser, Debug)]
+struct RemoveArgs {
+ #[clap(short, long)]
+ force: bool,
+ name: Vec<String>,
+}
+
+#[derive(Debug)]
+enum CliSub {
+ Add(AddArgs),
+ Remove(RemoveArgs),
+}
+
+impl FromArgMatches for CliSub {
+ fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
+ match matches.subcommand() {
+ Some(("add", args)) => Ok(Self::Add(AddArgs::from_arg_matches(args)?)),
+ Some(("remove", args)) => Ok(Self::Remove(RemoveArgs::from_arg_matches(args)?)),
+ Some((_, _)) => Err(Error::raw(
+ ErrorKind::UnrecognizedSubcommand,
+ "Valid subcommands are `add` and `remove`",
+ )),
+ None => Err(Error::raw(
+ ErrorKind::MissingSubcommand,
+ "Valid subcommands are `add` and `remove`",
+ )),
+ }
+ }
+ fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
+ match matches.subcommand() {
+ Some(("add", args)) => *self = Self::Add(AddArgs::from_arg_matches(args)?),
+ Some(("remove", args)) => *self = Self::Remove(RemoveArgs::from_arg_matches(args)?),
+ Some((_, _)) => {
+ return Err(Error::raw(
+ ErrorKind::UnrecognizedSubcommand,
+ "Valid subcommands are `add` and `remove`",
+ ))
+ }
+ None => (),
+ };
+ Ok(())
+ }
+}
+
+impl Subcommand for CliSub {
+ fn augment_subcommands(cmd: Command<'_>) -> Command<'_> {
+ cmd.subcommand(AddArgs::augment_args(Command::new("add")))
+ .subcommand(RemoveArgs::augment_args(Command::new("remove")))
+ .subcommand_required(true)
+ }
+ fn augment_subcommands_for_update(cmd: Command<'_>) -> Command<'_> {
+ cmd.subcommand(AddArgs::augment_args(Command::new("add")))
+ .subcommand(RemoveArgs::augment_args(Command::new("remove")))
+ .subcommand_required(true)
+ }
+ fn has_subcommand(name: &str) -> bool {
+ matches!(name, "add" | "remove")
+ }
+}
+
+#[derive(Parser, Debug)]
+struct Cli {
+ #[clap(short, long)]
+ top_level: bool,
+ #[clap(subcommand)]
+ subcommand: CliSub,
+}
+
+fn main() {
+ let args = Cli::parse();
+ println!("{:#?}", args);
+}
diff --git a/third_party/rust/clap/examples/derive_ref/interop_tests.md b/third_party/rust/clap/examples/derive_ref/interop_tests.md
new file mode 100644
index 0000000000..746fe1878d
--- /dev/null
+++ b/third_party/rust/clap/examples/derive_ref/interop_tests.md
@@ -0,0 +1,256 @@
+Following are tests for the interop examples in this directory.
+
+## Augment Args
+
+```console
+$ interop_augment_args
+Value of built: false
+Value of derived via ArgMatches: false
+Value of derived: DerivedArgs {
+ derived: false,
+}
+
+```
+
+```console
+$ interop_augment_args -b --derived
+Value of built: true
+Value of derived via ArgMatches: true
+Value of derived: DerivedArgs {
+ derived: true,
+}
+
+```
+
+```console
+$ interop_augment_args -d --built
+Value of built: true
+Value of derived via ArgMatches: true
+Value of derived: DerivedArgs {
+ derived: true,
+}
+
+```
+
+```console
+$ interop_augment_args --unknown
+? failed
+error: Found argument '--unknown' which wasn't expected, or isn't valid in this context
+
+ If you tried to supply `--unknown` as a value rather than a flag, use `-- --unknown`
+
+USAGE:
+ interop_augment_args[EXE] [OPTIONS]
+
+For more information try --help
+
+```
+
+## Augment Subcommands
+
+```console
+$ interop_augment_subcommands
+? failed
+error: A subcommand is required but one was not provided.
+```
+
+```console
+$ interop_augment_subcommands derived
+Derived subcommands: Derived {
+ derived_flag: false,
+}
+
+```
+
+```console
+$ interop_augment_subcommands derived --derived-flag
+Derived subcommands: Derived {
+ derived_flag: true,
+}
+
+```
+
+```console
+$ interop_augment_subcommands derived --unknown
+? failed
+error: Found argument '--unknown' which wasn't expected, or isn't valid in this context
+
+ If you tried to supply `--unknown` as a value rather than a flag, use `-- --unknown`
+
+USAGE:
+ interop_augment_subcommands[EXE] derived [OPTIONS]
+
+For more information try --help
+
+```
+
+```console
+$ interop_augment_subcommands unknown
+? failed
+error: Found argument 'unknown' which wasn't expected, or isn't valid in this context
+
+USAGE:
+ interop_augment_subcommands[EXE] [SUBCOMMAND]
+
+For more information try --help
+
+```
+
+## Hand-Implemented Subcommand
+
+```console
+$ interop_hand_subcommand
+? failed
+error: 'interop_hand_subcommand[EXE]' requires a subcommand but one was not provided
+
+USAGE:
+ interop_hand_subcommand[EXE] [OPTIONS] <SUBCOMMAND>
+
+For more information try --help
+
+```
+
+```console
+$ interop_hand_subcommand add
+Cli {
+ top_level: false,
+ subcommand: Add(
+ AddArgs {
+ name: [],
+ },
+ ),
+}
+
+```
+
+```console
+$ interop_hand_subcommand add a b c
+Cli {
+ top_level: false,
+ subcommand: Add(
+ AddArgs {
+ name: [
+ "a",
+ "b",
+ "c",
+ ],
+ },
+ ),
+}
+
+```
+
+```console
+$ interop_hand_subcommand add --unknown
+? failed
+error: Found argument '--unknown' which wasn't expected, or isn't valid in this context
+
+ If you tried to supply `--unknown` as a value rather than a flag, use `-- --unknown`
+
+USAGE:
+ interop_hand_subcommand[EXE] add [NAME]...
+
+For more information try --help
+
+```
+
+```console
+$ interop_hand_subcommand remove
+Cli {
+ top_level: false,
+ subcommand: Remove(
+ RemoveArgs {
+ force: false,
+ name: [],
+ },
+ ),
+}
+
+```
+
+```console
+$ interop_hand_subcommand remove --force a b c
+Cli {
+ top_level: false,
+ subcommand: Remove(
+ RemoveArgs {
+ force: true,
+ name: [
+ "a",
+ "b",
+ "c",
+ ],
+ },
+ ),
+}
+
+```
+
+```console
+$ interop_hand_subcommand unknown
+? failed
+error: Found argument 'unknown' which wasn't expected, or isn't valid in this context
+
+USAGE:
+ interop_hand_subcommand[EXE] [OPTIONS] <SUBCOMMAND>
+
+For more information try --help
+
+```
+
+## Flatten Hand-Implemented Args
+
+```console
+$ interop_flatten_hand_args
+Cli {
+ top_level: false,
+ more_args: CliArgs {
+ foo: false,
+ bar: false,
+ quuz: None,
+ },
+}
+
+```
+
+```console
+$ interop_flatten_hand_args -f --bar
+Cli {
+ top_level: false,
+ more_args: CliArgs {
+ foo: true,
+ bar: true,
+ quuz: None,
+ },
+}
+
+```
+
+```console
+$ interop_flatten_hand_args --quuz abc
+Cli {
+ top_level: false,
+ more_args: CliArgs {
+ foo: false,
+ bar: false,
+ quuz: Some(
+ "abc",
+ ),
+ },
+}
+
+```
+
+```console
+$ interop_flatten_hand_args --unknown
+? failed
+error: Found argument '--unknown' which wasn't expected, or isn't valid in this context
+
+ If you tried to supply `--unknown` as a value rather than a flag, use `-- --unknown`
+
+USAGE:
+ interop_flatten_hand_args[EXE] [OPTIONS]
+
+For more information try --help
+
+```
diff --git a/third_party/rust/clap/examples/escaped-positional-derive.md b/third_party/rust/clap/examples/escaped-positional-derive.md
new file mode 100644
index 0000000000..3b5f8fe565
--- /dev/null
+++ b/third_party/rust/clap/examples/escaped-positional-derive.md
@@ -0,0 +1,65 @@
+*Jump to [source](escaped-positional-derive.rs)*
+
+**This requires enabling the `derive` feature flag.**
+
+You can use `--` to escape further arguments.
+
+Let's see what this looks like in the help:
+```console
+$ escaped-positional-derive --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ escaped-positional-derive[EXE] [OPTIONS] [-- <SLOP>...]
+
+ARGS:
+ <SLOP>...
+
+OPTIONS:
+ -f
+ -h, --help Print help information
+ -p <PEAR>
+ -V, --version Print version information
+
+```
+
+Here is a baseline without any arguments:
+```console
+$ escaped-positional-derive
+-f used: false
+-p's value: None
+'slops' values: []
+
+```
+
+Notice that we can't pass positional arguments before `--`:
+```console
+$ escaped-positional-derive foo bar
+? failed
+error: Found argument 'foo' which wasn't expected, or isn't valid in this context
+
+USAGE:
+ escaped-positional-derive[EXE] [OPTIONS] [-- <SLOP>...]
+
+For more information try --help
+
+```
+
+But you can after:
+```console
+$ escaped-positional-derive -f -p=bob -- sloppy slop slop
+-f used: true
+-p's value: Some("bob")
+'slops' values: ["sloppy", "slop", "slop"]
+
+```
+
+As mentioned, the parser will directly pass everything through:
+```console
+$ escaped-positional-derive -- -f -p=bob sloppy slop slop
+-f used: false
+-p's value: None
+'slops' values: ["-f", "-p=bob", "sloppy", "slop", "slop"]
+
+```
diff --git a/third_party/rust/clap/examples/escaped-positional-derive.rs b/third_party/rust/clap/examples/escaped-positional-derive.rs
new file mode 100644
index 0000000000..8038395aff
--- /dev/null
+++ b/third_party/rust/clap/examples/escaped-positional-derive.rs
@@ -0,0 +1,27 @@
+// Note: this requires the `derive` feature
+
+use clap::Parser;
+
+#[derive(Parser)]
+#[clap(author, version, about, long_about = None)]
+struct Cli {
+ #[clap(short = 'f')]
+ eff: bool,
+
+ #[clap(short = 'p', value_name = "PEAR")]
+ pea: Option<String>,
+
+ #[clap(last = true)]
+ slop: Vec<String>,
+}
+
+fn main() {
+ let args = Cli::parse();
+
+ // This is what will happen with `myprog -f -p=bob -- sloppy slop slop`...
+ println!("-f used: {:?}", args.eff); // -f used: true
+ println!("-p's value: {:?}", args.pea); // -p's value: Some("bob")
+ println!("'slops' values: {:?}", args.slop); // 'slops' values: Some(["sloppy", "slop", "slop"])
+
+ // Continued program logic goes here...
+}
diff --git a/third_party/rust/clap/examples/escaped-positional.md b/third_party/rust/clap/examples/escaped-positional.md
new file mode 100644
index 0000000000..1f71a87369
--- /dev/null
+++ b/third_party/rust/clap/examples/escaped-positional.md
@@ -0,0 +1,65 @@
+*Jump to [source](escaped-positional.rs)*
+
+**This requires enabling the `cargo` feature flag.**
+
+You can use `--` to escape further arguments.
+
+Let's see what this looks like in the help:
+```console
+$ escaped-positional --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ escaped-positional[EXE] [OPTIONS] [-- <SLOP>...]
+
+ARGS:
+ <SLOP>...
+
+OPTIONS:
+ -f
+ -h, --help Print help information
+ -p <PEAR>
+ -V, --version Print version information
+
+```
+
+Here is a baseline without any arguments:
+```console
+$ escaped-positional
+-f used: false
+-p's value: None
+'slops' values: []
+
+```
+
+Notice that we can't pass positional arguments before `--`:
+```console
+$ escaped-positional foo bar
+? failed
+error: Found argument 'foo' which wasn't expected, or isn't valid in this context
+
+USAGE:
+ escaped-positional[EXE] [OPTIONS] [-- <SLOP>...]
+
+For more information try --help
+
+```
+
+But you can after:
+```console
+$ escaped-positional -f -p=bob -- sloppy slop slop
+-f used: true
+-p's value: Some("bob")
+'slops' values: ["sloppy", "slop", "slop"]
+
+```
+
+As mentioned, the parser will directly pass everything through:
+```console
+$ escaped-positional -- -f -p=bob sloppy slop slop
+-f used: false
+-p's value: None
+'slops' values: ["-f", "-p=bob", "sloppy", "slop", "slop"]
+
+```
diff --git a/third_party/rust/clap/examples/escaped-positional.rs b/third_party/rust/clap/examples/escaped-positional.rs
new file mode 100644
index 0000000000..f6d61bd965
--- /dev/null
+++ b/third_party/rust/clap/examples/escaped-positional.rs
@@ -0,0 +1,26 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command};
+
+fn main() {
+ let matches = command!()
+ .arg(arg!(eff: -f))
+ .arg(arg!(pea: -p <PEAR>).required(false))
+ .arg(
+ arg!(slop: [SLOP]).multiple_occurrences(true).last(true), // Indicates that `slop` is only accessible after `--`.
+ )
+ .get_matches();
+
+ // This is what will happen with `myprog -f -p=bob -- sloppy slop slop`...
+ println!("-f used: {:?}", matches.is_present("eff")); // -f used: true
+ println!("-p's value: {:?}", matches.value_of("pea")); // -p's value: Some("bob")
+ println!(
+ "'slops' values: {:?}",
+ matches
+ .values_of("slop")
+ .map(|vals| vals.collect::<Vec<_>>())
+ .unwrap_or_default()
+ ); // 'slops' values: Some(["sloppy", "slop", "slop"])
+
+ // Continued program logic goes here...
+}
diff --git a/third_party/rust/clap/examples/git-derive.md b/third_party/rust/clap/examples/git-derive.md
new file mode 100644
index 0000000000..dc27776f58
--- /dev/null
+++ b/third_party/rust/clap/examples/git-derive.md
@@ -0,0 +1,140 @@
+*Jump to [source](git-derive.rs)*
+
+**This requires enabling the `derive` feature flag.**
+
+Git is an example of several common subcommand patterns.
+
+Help:
+```console
+$ git-derive
+? failed
+git
+A fictional versioning CLI
+
+USAGE:
+ git-derive[EXE] <SUBCOMMAND>
+
+OPTIONS:
+ -h, --help Print help information
+
+SUBCOMMANDS:
+ add adds things
+ clone Clones repos
+ help Print this message or the help of the given subcommand(s)
+ push pushes things
+ stash
+
+$ git-derive help
+git
+A fictional versioning CLI
+
+USAGE:
+ git-derive[EXE] <SUBCOMMAND>
+
+OPTIONS:
+ -h, --help Print help information
+
+SUBCOMMANDS:
+ add adds things
+ clone Clones repos
+ help Print this message or the help of the given subcommand(s)
+ push pushes things
+ stash
+
+$ git-derive help add
+git-derive[EXE]-add
+adds things
+
+USAGE:
+ git-derive[EXE] add <PATH>...
+
+ARGS:
+ <PATH>... Stuff to add
+
+OPTIONS:
+ -h, --help Print help information
+
+```
+
+A basic argument:
+```console
+$ git-derive add
+? failed
+git-derive[EXE]-add
+adds things
+
+USAGE:
+ git-derive[EXE] add <PATH>...
+
+ARGS:
+ <PATH>... Stuff to add
+
+OPTIONS:
+ -h, --help Print help information
+
+$ git-derive add Cargo.toml Cargo.lock
+Adding ["Cargo.toml", "Cargo.lock"]
+
+```
+
+Default subcommand:
+```console
+$ git-derive stash -h
+git-derive[EXE]-stash
+
+USAGE:
+ git-derive[EXE] stash [OPTIONS]
+ git-derive[EXE] stash <SUBCOMMAND>
+
+OPTIONS:
+ -h, --help Print help information
+ -m, --message <MESSAGE>
+
+SUBCOMMANDS:
+ apply
+ help Print this message or the help of the given subcommand(s)
+ pop
+ push
+
+$ git-derive stash push -h
+git-derive[EXE]-stash-push
+
+USAGE:
+ git-derive[EXE] stash push [OPTIONS]
+
+OPTIONS:
+ -h, --help Print help information
+ -m, --message <MESSAGE>
+
+$ git-derive stash pop -h
+git-derive[EXE]-stash-pop
+
+USAGE:
+ git-derive[EXE] stash pop [STASH]
+
+ARGS:
+ <STASH>
+
+OPTIONS:
+ -h, --help Print help information
+
+$ git-derive stash -m "Prototype"
+Pushing StashPush { message: Some("Prototype") }
+
+$ git-derive stash pop
+Popping None
+
+$ git-derive stash push -m "Prototype"
+Pushing StashPush { message: Some("Prototype") }
+
+$ git-derive stash pop
+Popping None
+
+```
+
+External subcommands:
+```console
+$ git-derive custom-tool arg1 --foo bar
+Calling out to "custom-tool" with ["arg1", "--foo", "bar"]
+
+```
diff --git a/third_party/rust/clap/examples/git-derive.rs b/third_party/rust/clap/examples/git-derive.rs
new file mode 100644
index 0000000000..7e44edb1af
--- /dev/null
+++ b/third_party/rust/clap/examples/git-derive.rs
@@ -0,0 +1,99 @@
+// Note: this requires the `derive` feature
+
+use std::ffi::OsString;
+use std::path::PathBuf;
+
+use clap::{Args, Parser, Subcommand};
+
+/// A fictional versioning CLI
+#[derive(Debug, Parser)]
+#[clap(name = "git")]
+#[clap(about = "A fictional versioning CLI", long_about = None)]
+struct Cli {
+ #[clap(subcommand)]
+ command: Commands,
+}
+
+#[derive(Debug, Subcommand)]
+enum Commands {
+ /// Clones repos
+ #[clap(arg_required_else_help = true)]
+ Clone {
+ /// The remote to clone
+ remote: String,
+ },
+ /// pushes things
+ #[clap(arg_required_else_help = true)]
+ Push {
+ /// The remote to target
+ remote: String,
+ },
+ /// adds things
+ #[clap(arg_required_else_help = true)]
+ Add {
+ /// Stuff to add
+ #[clap(required = true, parse(from_os_str))]
+ path: Vec<PathBuf>,
+ },
+ Stash(Stash),
+ #[clap(external_subcommand)]
+ External(Vec<OsString>),
+}
+
+#[derive(Debug, Args)]
+#[clap(args_conflicts_with_subcommands = true)]
+struct Stash {
+ #[clap(subcommand)]
+ command: Option<StashCommands>,
+
+ #[clap(flatten)]
+ push: StashPush,
+}
+
+#[derive(Debug, Subcommand)]
+enum StashCommands {
+ Push(StashPush),
+ Pop { stash: Option<String> },
+ Apply { stash: Option<String> },
+}
+
+#[derive(Debug, Args)]
+struct StashPush {
+ #[clap(short, long)]
+ message: Option<String>,
+}
+
+fn main() {
+ let args = Cli::parse();
+
+ match args.command {
+ Commands::Clone { remote } => {
+ println!("Cloning {}", remote);
+ }
+ Commands::Push { remote } => {
+ println!("Pushing to {}", remote);
+ }
+ Commands::Add { path } => {
+ println!("Adding {:?}", path);
+ }
+ Commands::Stash(stash) => {
+ let stash_cmd = stash.command.unwrap_or(StashCommands::Push(stash.push));
+ match stash_cmd {
+ StashCommands::Push(push) => {
+ println!("Pushing {:?}", push);
+ }
+ StashCommands::Pop { stash } => {
+ println!("Popping {:?}", stash);
+ }
+ StashCommands::Apply { stash } => {
+ println!("Applying {:?}", stash);
+ }
+ }
+ }
+ Commands::External(args) => {
+ println!("Calling out to {:?} with {:?}", &args[0], &args[1..]);
+ }
+ }
+
+ // Continued program logic goes here...
+}
diff --git a/third_party/rust/clap/examples/git.md b/third_party/rust/clap/examples/git.md
new file mode 100644
index 0000000000..2cdfe653b3
--- /dev/null
+++ b/third_party/rust/clap/examples/git.md
@@ -0,0 +1,138 @@
+*Jump to [source](git.rs)*
+
+Git is an example of several common subcommand patterns.
+
+Help:
+```console
+$ git
+? failed
+git
+A fictional versioning CLI
+
+USAGE:
+ git[EXE] <SUBCOMMAND>
+
+OPTIONS:
+ -h, --help Print help information
+
+SUBCOMMANDS:
+ add adds things
+ clone Clones repos
+ help Print this message or the help of the given subcommand(s)
+ push pushes things
+ stash
+
+$ git help
+git
+A fictional versioning CLI
+
+USAGE:
+ git[EXE] <SUBCOMMAND>
+
+OPTIONS:
+ -h, --help Print help information
+
+SUBCOMMANDS:
+ add adds things
+ clone Clones repos
+ help Print this message or the help of the given subcommand(s)
+ push pushes things
+ stash
+
+$ git help add
+git[EXE]-add
+adds things
+
+USAGE:
+ git[EXE] add <PATH>...
+
+ARGS:
+ <PATH>... Stuff to add
+
+OPTIONS:
+ -h, --help Print help information
+
+```
+
+A basic argument:
+```console
+$ git add
+? failed
+git[EXE]-add
+adds things
+
+USAGE:
+ git[EXE] add <PATH>...
+
+ARGS:
+ <PATH>... Stuff to add
+
+OPTIONS:
+ -h, --help Print help information
+
+$ git add Cargo.toml Cargo.lock
+Adding ["Cargo.toml", "Cargo.lock"]
+
+```
+
+Default subcommand:
+```console
+$ git stash -h
+git[EXE]-stash
+
+USAGE:
+ git[EXE] stash [OPTIONS]
+ git[EXE] stash <SUBCOMMAND>
+
+OPTIONS:
+ -h, --help Print help information
+ -m, --message <MESSAGE>
+
+SUBCOMMANDS:
+ apply
+ help Print this message or the help of the given subcommand(s)
+ pop
+ push
+
+$ git stash push -h
+git[EXE]-stash-push
+
+USAGE:
+ git[EXE] stash push [OPTIONS]
+
+OPTIONS:
+ -h, --help Print help information
+ -m, --message <MESSAGE>
+
+$ git stash pop -h
+git[EXE]-stash-pop
+
+USAGE:
+ git[EXE] stash pop [STASH]
+
+ARGS:
+ <STASH>
+
+OPTIONS:
+ -h, --help Print help information
+
+$ git stash -m "Prototype"
+Pushing Some("Prototype")
+
+$ git stash pop
+Popping None
+
+$ git stash push -m "Prototype"
+Pushing Some("Prototype")
+
+$ git stash pop
+Popping None
+
+```
+
+External subcommands:
+```console
+$ git custom-tool arg1 --foo bar
+Calling out to "custom-tool" with ["arg1", "--foo", "bar"]
+
+```
diff --git a/third_party/rust/clap/examples/git.rs b/third_party/rust/clap/examples/git.rs
new file mode 100644
index 0000000000..1ced54a90e
--- /dev/null
+++ b/third_party/rust/clap/examples/git.rs
@@ -0,0 +1,101 @@
+// Note: this requires the `cargo` feature
+
+use std::path::PathBuf;
+
+use clap::{arg, Command};
+
+fn cli() -> Command<'static> {
+ Command::new("git")
+ .about("A fictional versioning CLI")
+ .subcommand_required(true)
+ .arg_required_else_help(true)
+ .allow_external_subcommands(true)
+ .allow_invalid_utf8_for_external_subcommands(true)
+ .subcommand(
+ Command::new("clone")
+ .about("Clones repos")
+ .arg(arg!(<REMOTE> "The remote to clone"))
+ .arg_required_else_help(true),
+ )
+ .subcommand(
+ Command::new("push")
+ .about("pushes things")
+ .arg(arg!(<REMOTE> "The remote to target"))
+ .arg_required_else_help(true),
+ )
+ .subcommand(
+ Command::new("add")
+ .about("adds things")
+ .arg_required_else_help(true)
+ .arg(arg!(<PATH> ... "Stuff to add").allow_invalid_utf8(true)),
+ )
+ .subcommand(
+ Command::new("stash")
+ .args_conflicts_with_subcommands(true)
+ .args(push_args())
+ .subcommand(Command::new("push").args(push_args()))
+ .subcommand(Command::new("pop").arg(arg!([STASH])))
+ .subcommand(Command::new("apply").arg(arg!([STASH]))),
+ )
+}
+
+fn push_args() -> Vec<clap::Arg<'static>> {
+ vec![arg!(-m --message <MESSAGE>).required(false)]
+}
+
+fn main() {
+ let matches = cli().get_matches();
+
+ match matches.subcommand() {
+ Some(("clone", sub_matches)) => {
+ println!(
+ "Cloning {}",
+ sub_matches.value_of("REMOTE").expect("required")
+ );
+ }
+ Some(("push", sub_matches)) => {
+ println!(
+ "Pushing to {}",
+ sub_matches.value_of("REMOTE").expect("required")
+ );
+ }
+ Some(("add", sub_matches)) => {
+ let paths = sub_matches
+ .values_of_os("PATH")
+ .unwrap_or_default()
+ .map(PathBuf::from)
+ .collect::<Vec<_>>();
+ println!("Adding {:?}", paths);
+ }
+ Some(("stash", sub_matches)) => {
+ let stash_command = sub_matches.subcommand().unwrap_or(("push", sub_matches));
+ match stash_command {
+ ("apply", sub_matches) => {
+ let stash = sub_matches.value_of("STASH");
+ println!("Applying {:?}", stash);
+ }
+ ("pop", sub_matches) => {
+ let stash = sub_matches.value_of("STASH");
+ println!("Popping {:?}", stash);
+ }
+ ("push", sub_matches) => {
+ let message = sub_matches.value_of("message");
+ println!("Pushing {:?}", message);
+ }
+ (name, _) => {
+ unreachable!("Unsupported subcommand `{}`", name)
+ }
+ }
+ }
+ Some((ext, sub_matches)) => {
+ let args = sub_matches
+ .values_of_os("")
+ .unwrap_or_default()
+ .collect::<Vec<_>>();
+ println!("Calling out to {:?} with {:?}", ext, args);
+ }
+ _ => unreachable!(), // If all subcommands are defined above, anything else is unreachabe!()
+ }
+
+ // Continued program logic goes here...
+}
diff --git a/third_party/rust/clap/examples/multicall-busybox.md b/third_party/rust/clap/examples/multicall-busybox.md
new file mode 100644
index 0000000000..a09418403f
--- /dev/null
+++ b/third_party/rust/clap/examples/multicall-busybox.md
@@ -0,0 +1,46 @@
+*Jump to [source](multicall-busybox.rs)*
+
+Example of a busybox-style multicall program
+
+See the documentation for `clap::Command::multicall` for rationale.
+
+This example omits every command except true and false,
+which are the most trivial to implement,
+```console
+$ busybox true
+? 0
+
+$ busybox false
+? 1
+
+```
+*Note: without the links setup, we can't demonstrate the multicall behavior*
+
+But includes the `--install` option as an example of why it can be useful
+for the main program to take arguments that aren't applet subcommands.
+```console
+$ busybox --install
+? failed
+...
+
+```
+
+Though users must pass something:
+```console
+$ busybox
+? failed
+busybox
+
+USAGE:
+ busybox [OPTIONS] [APPLET]
+
+OPTIONS:
+ -h, --help Print help information
+ --install <install> Install hardlinks for all subcommands in path
+
+APPLETS:
+ false does nothing unsuccessfully
+ help Print this message or the help of the given subcommand(s)
+ true does nothing successfully
+
+```
diff --git a/third_party/rust/clap/examples/multicall-busybox.rs b/third_party/rust/clap/examples/multicall-busybox.rs
new file mode 100644
index 0000000000..30865a8303
--- /dev/null
+++ b/third_party/rust/clap/examples/multicall-busybox.rs
@@ -0,0 +1,48 @@
+// Note: this requires the `unstable-multicall` feature
+
+use std::process::exit;
+
+use clap::{Arg, Command};
+
+fn applet_commands() -> [Command<'static>; 2] {
+ [
+ Command::new("true").about("does nothing successfully"),
+ Command::new("false").about("does nothing unsuccessfully"),
+ ]
+}
+
+fn main() {
+ let cmd = Command::new(env!("CARGO_CRATE_NAME"))
+ .multicall(true)
+ .subcommand(
+ Command::new("busybox")
+ .arg_required_else_help(true)
+ .subcommand_value_name("APPLET")
+ .subcommand_help_heading("APPLETS")
+ .arg(
+ Arg::new("install")
+ .long("install")
+ .help("Install hardlinks for all subcommands in path")
+ .exclusive(true)
+ .takes_value(true)
+ .default_missing_value("/usr/local/bin")
+ .use_value_delimiter(false),
+ )
+ .subcommands(applet_commands()),
+ )
+ .subcommands(applet_commands());
+
+ let matches = cmd.get_matches();
+ let mut subcommand = matches.subcommand();
+ if let Some(("busybox", cmd)) = subcommand {
+ if cmd.occurrences_of("install") > 0 {
+ unimplemented!("Make hardlinks to the executable here");
+ }
+ subcommand = cmd.subcommand();
+ }
+ match subcommand {
+ Some(("false", _)) => exit(1),
+ Some(("true", _)) => exit(0),
+ _ => unreachable!("parser should ensure only valid subcommand names are used"),
+ }
+}
diff --git a/third_party/rust/clap/examples/multicall-hostname.md b/third_party/rust/clap/examples/multicall-hostname.md
new file mode 100644
index 0000000000..9e17ca16cb
--- /dev/null
+++ b/third_party/rust/clap/examples/multicall-hostname.md
@@ -0,0 +1,14 @@
+*Jump to [source](multicall-hostname.rs)*
+
+Example of a `hostname-style` multicall program
+
+See the documentation for `clap::Command::multicall` for rationale.
+
+This example omits the implementation of displaying address config
+
+```console
+$ hostname
+www
+
+```
+*Note: without the links setup, we can't demonstrate the multicall behavior*
diff --git a/third_party/rust/clap/examples/multicall-hostname.rs b/third_party/rust/clap/examples/multicall-hostname.rs
new file mode 100644
index 0000000000..2c89a14484
--- /dev/null
+++ b/third_party/rust/clap/examples/multicall-hostname.rs
@@ -0,0 +1,19 @@
+// Note: this requires the `unstable-multicall` feature
+
+use clap::Command;
+
+fn main() {
+ let cmd = Command::new(env!("CARGO_CRATE_NAME"))
+ .multicall(true)
+ .arg_required_else_help(true)
+ .subcommand_value_name("APPLET")
+ .subcommand_help_heading("APPLETS")
+ .subcommand(Command::new("hostname").about("show hostname part of FQDN"))
+ .subcommand(Command::new("dnsdomainname").about("show domain name part of FQDN"));
+
+ match cmd.get_matches().subcommand_name() {
+ Some("hostname") => println!("www"),
+ Some("dnsdomainname") => println!("example.com"),
+ _ => unreachable!("parser should ensure only valid subcommand names are used"),
+ }
+}
diff --git a/third_party/rust/clap/examples/pacman.md b/third_party/rust/clap/examples/pacman.md
new file mode 100644
index 0000000000..7f6c5a7d33
--- /dev/null
+++ b/third_party/rust/clap/examples/pacman.md
@@ -0,0 +1,87 @@
+*Jump to [source](pacman.rs)*
+
+[`pacman`](https://wiki.archlinux.org/index.php/pacman) defines subcommands via flags.
+
+Here, `-S` is a short flag subcommand:
+```console
+$ pacman -S package
+Installing package...
+
+```
+
+Here `--sync` is a long flag subcommand:
+```console
+$ pacman --sync package
+Installing package...
+
+```
+
+Now the short flag subcommand (`-S`) with a long flag:
+```console
+$ pacman -S --search name
+Searching for name...
+
+```
+
+And the various forms of short flags that work:
+```console
+$ pacman -S -s name
+Searching for name...
+
+$ pacman -Ss name
+Searching for name...
+
+```
+*(users can "stack" short subcommands with short flags or with other short flag subcommands)*
+
+In the help, this looks like:
+```console
+$ pacman -h
+pacman 5.2.1
+Pacman Development Team
+package manager utility
+
+USAGE:
+ pacman[EXE] <SUBCOMMAND>
+
+OPTIONS:
+ -h, --help Print help information
+ -V, --version Print version information
+
+SUBCOMMANDS:
+ help Print this message or the help of the given subcommand(s)
+ query -Q --query Query the package database.
+ sync -S --sync Synchronize packages.
+
+$ pacman -S -h
+pacman[EXE]-sync
+Synchronize packages.
+
+USAGE:
+ pacman[EXE] {sync|--sync|-S} [OPTIONS] [--] [package]...
+
+ARGS:
+ <package>... packages
+
+OPTIONS:
+ -h, --help Print help information
+ -i, --info view package information
+ -s, --search <search>... search remote repositories for matching strings
+
+```
+
+And errors:
+```console
+$ pacman -S -s foo -i bar
+? failed
+error: The argument '--search <search>...' cannot be used with '--info'
+
+USAGE:
+ pacman[EXE] {sync|--sync|-S} --search <search>... <package>...
+
+For more information try --help
+
+```
+
+**NOTE:** Keep in mind that subcommands, flags, and long flags are *case sensitive*: `-Q` and `-q` are different flags/subcommands. For example, you can have both `-Q` subcommand and `-q` flag, and they will be properly disambiguated.
+Let's make a quick program to illustrate.
diff --git a/third_party/rust/clap/examples/pacman.rs b/third_party/rust/clap/examples/pacman.rs
new file mode 100644
index 0000000000..c088a8fe91
--- /dev/null
+++ b/third_party/rust/clap/examples/pacman.rs
@@ -0,0 +1,102 @@
+use clap::{Arg, Command};
+
+fn main() {
+ let matches = Command::new("pacman")
+ .about("package manager utility")
+ .version("5.2.1")
+ .subcommand_required(true)
+ .arg_required_else_help(true)
+ .author("Pacman Development Team")
+ // Query subcommand
+ //
+ // Only a few of its arguments are implemented below.
+ .subcommand(
+ Command::new("query")
+ .short_flag('Q')
+ .long_flag("query")
+ .about("Query the package database.")
+ .arg(
+ Arg::new("search")
+ .short('s')
+ .long("search")
+ .help("search locally installed packages for matching strings")
+ .conflicts_with("info")
+ .takes_value(true)
+ .multiple_values(true),
+ )
+ .arg(
+ Arg::new("info")
+ .long("info")
+ .short('i')
+ .conflicts_with("search")
+ .help("view package information")
+ .takes_value(true)
+ .multiple_values(true),
+ ),
+ )
+ // Sync subcommand
+ //
+ // Only a few of its arguments are implemented below.
+ .subcommand(
+ Command::new("sync")
+ .short_flag('S')
+ .long_flag("sync")
+ .about("Synchronize packages.")
+ .arg(
+ Arg::new("search")
+ .short('s')
+ .long("search")
+ .conflicts_with("info")
+ .takes_value(true)
+ .multiple_values(true)
+ .help("search remote repositories for matching strings"),
+ )
+ .arg(
+ Arg::new("info")
+ .long("info")
+ .conflicts_with("search")
+ .short('i')
+ .help("view package information"),
+ )
+ .arg(
+ Arg::new("package")
+ .help("packages")
+ .required_unless_present("search")
+ .takes_value(true)
+ .multiple_values(true),
+ ),
+ )
+ .get_matches();
+
+ match matches.subcommand() {
+ Some(("sync", sync_matches)) => {
+ if sync_matches.is_present("search") {
+ let packages: Vec<_> = sync_matches.values_of("search").unwrap().collect();
+ let values = packages.join(", ");
+ println!("Searching for {}...", values);
+ return;
+ }
+
+ let packages: Vec<_> = sync_matches.values_of("package").unwrap().collect();
+ let values = packages.join(", ");
+
+ if sync_matches.is_present("info") {
+ println!("Retrieving info for {}...", values);
+ } else {
+ println!("Installing {}...", values);
+ }
+ }
+ Some(("query", query_matches)) => {
+ if let Some(packages) = query_matches.values_of("info") {
+ let comma_sep = packages.collect::<Vec<_>>().join(", ");
+ println!("Retrieving info for {}...", comma_sep);
+ } else if let Some(queries) = query_matches.values_of("search") {
+ let comma_sep = queries.collect::<Vec<_>>().join(", ");
+ println!("Searching Locally for {}...", comma_sep);
+ } else {
+ println!("Displaying all locally installed packages...");
+ }
+ }
+ _ => unreachable!(), // If all subcommands are defined above, anything else is unreachable
+ }
+}
diff --git a/third_party/rust/clap/examples/repl.rs b/third_party/rust/clap/examples/repl.rs
new file mode 100644
index 0000000000..f1b65c3090
--- /dev/null
+++ b/third_party/rust/clap/examples/repl.rs
@@ -0,0 +1,94 @@
+// Note: this requires the `unstable-multicall` feature
+
+use std::io::Write;
+
+use clap::Command;
+
+fn main() -> Result<(), String> {
+ loop {
+ let line = readline()?;
+ let line = line.trim();
+ if line.is_empty() {
+ continue;
+ }
+
+ match respond(line) {
+ Ok(quit) => {
+ if quit {
+ break;
+ }
+ }
+ Err(err) => {
+ write!(std::io::stdout(), "{}", err).map_err(|e| e.to_string())?;
+ std::io::stdout().flush().map_err(|e| e.to_string())?;
+ }
+ }
+ }
+
+ Ok(())
+}
+
+fn respond(line: &str) -> Result<bool, String> {
+ let args = shlex::split(line).ok_or("error: Invalid quoting")?;
+ let matches = cli()
+ .try_get_matches_from(&args)
+ .map_err(|e| e.to_string())?;
+ match matches.subcommand() {
+ Some(("ping", _matches)) => {
+ write!(std::io::stdout(), "Pong").map_err(|e| e.to_string())?;
+ std::io::stdout().flush().map_err(|e| e.to_string())?;
+ }
+ Some(("quit", _matches)) => {
+ write!(std::io::stdout(), "Exiting ...").map_err(|e| e.to_string())?;
+ std::io::stdout().flush().map_err(|e| e.to_string())?;
+ return Ok(true);
+ }
+ Some((name, _matches)) => unimplemented!("{}", name),
+ None => unreachable!("subcommand required"),
+ }
+
+ Ok(false)
+}
+
+fn cli() -> Command<'static> {
+ // strip out usage
+ const PARSER_TEMPLATE: &str = "\
+ {all-args}
+ ";
+ // strip out name/version
+ const APPLET_TEMPLATE: &str = "\
+ {about-with-newline}\n\
+ {usage-heading}\n {usage}\n\
+ \n\
+ {all-args}{after-help}\
+ ";
+
+ Command::new("repl")
+ .multicall(true)
+ .arg_required_else_help(true)
+ .subcommand_required(true)
+ .subcommand_value_name("APPLET")
+ .subcommand_help_heading("APPLETS")
+ .help_template(PARSER_TEMPLATE)
+ .subcommand(
+ Command::new("ping")
+ .about("Get a response")
+ .help_template(APPLET_TEMPLATE),
+ )
+ .subcommand(
+ Command::new("quit")
+ .alias("exit")
+ .about("Quit the REPL")
+ .help_template(APPLET_TEMPLATE),
+ )
+}
+
+fn readline() -> Result<String, String> {
+ write!(std::io::stdout(), "$ ").map_err(|e| e.to_string())?;
+ std::io::stdout().flush().map_err(|e| e.to_string())?;
+ let mut buffer = String::new();
+ std::io::stdin()
+ .read_line(&mut buffer)
+ .map_err(|e| e.to_string())?;
+ Ok(buffer)
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/01_quick.rs b/third_party/rust/clap/examples/tutorial_builder/01_quick.rs
new file mode 100644
index 0000000000..7ab5081dfc
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/01_quick.rs
@@ -0,0 +1,60 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command, Command};
+use std::path::Path;
+
+fn main() {
+ let matches = command!()
+ .arg(arg!([name] "Optional name to operate on"))
+ .arg(
+ arg!(
+ -c --config <FILE> "Sets a custom config file"
+ )
+ // We don't have syntax yet for optional options, so manually calling `required`
+ .required(false)
+ // Support non-UTF8 paths
+ .allow_invalid_utf8(true),
+ )
+ .arg(arg!(
+ -d --debug ... "Turn debugging information on"
+ ))
+ .subcommand(
+ Command::new("test")
+ .about("does testing things")
+ .arg(arg!(-l --list "lists test values")),
+ )
+ .get_matches();
+
+ // You can check the value provided by positional arguments, or option arguments
+ if let Some(name) = matches.value_of("name") {
+ println!("Value for name: {}", name);
+ }
+
+ if let Some(raw_config) = matches.value_of_os("config") {
+ let config_path = Path::new(raw_config);
+ 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 matches.occurrences_of("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
+ if let Some(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...
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/02_app_settings.rs b/third_party/rust/clap/examples/tutorial_builder/02_app_settings.rs
new file mode 100644
index 0000000000..3485f588eb
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/02_app_settings.rs
@@ -0,0 +1,16 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command, AppSettings};
+
+fn main() {
+ let matches = command!()
+ .args_override_self(true)
+ .global_setting(AppSettings::DeriveDisplayOrder)
+ .allow_negative_numbers(true)
+ .arg(arg!(--two <VALUE>))
+ .arg(arg!(--one <VALUE>))
+ .get_matches();
+
+ println!("two: {:?}", matches.value_of("two").expect("required"));
+ println!("one: {:?}", matches.value_of("one").expect("required"));
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/02_apps.rs b/third_party/rust/clap/examples/tutorial_builder/02_apps.rs
new file mode 100644
index 0000000000..c9422d64a3
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/02_apps.rs
@@ -0,0 +1,14 @@
+use clap::{arg, Command};
+
+fn main() {
+ let matches = Command::new("MyApp")
+ .version("1.0")
+ .author("Kevin K. <kbknapp@gmail.com>")
+ .about("Does awesome things")
+ .arg(arg!(--two <VALUE>))
+ .arg(arg!(--one <VALUE>))
+ .get_matches();
+
+ println!("two: {:?}", matches.value_of("two").expect("required"));
+ println!("one: {:?}", matches.value_of("one").expect("required"));
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/02_crate.rs b/third_party/rust/clap/examples/tutorial_builder/02_crate.rs
new file mode 100644
index 0000000000..df214f3f5c
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/02_crate.rs
@@ -0,0 +1,13 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command};
+
+fn main() {
+ let matches = command!()
+ .arg(arg!(--two <VALUE>))
+ .arg(arg!(--one <VALUE>))
+ .get_matches();
+
+ println!("two: {:?}", matches.value_of("two").expect("required"));
+ println!("one: {:?}", matches.value_of("one").expect("required"));
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/03_01_flag_bool.rs b/third_party/rust/clap/examples/tutorial_builder/03_01_flag_bool.rs
new file mode 100644
index 0000000000..a8d85c4c2e
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/03_01_flag_bool.rs
@@ -0,0 +1,9 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command};
+
+fn main() {
+ let matches = command!().arg(arg!(-v - -verbose)).get_matches();
+
+ println!("verbose: {:?}", matches.is_present("verbose"));
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/03_01_flag_count.rs b/third_party/rust/clap/examples/tutorial_builder/03_01_flag_count.rs
new file mode 100644
index 0000000000..c5532c07a4
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/03_01_flag_count.rs
@@ -0,0 +1,9 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command};
+
+fn main() {
+ let matches = command!().arg(arg!(-v --verbose ...)).get_matches();
+
+ println!("verbose: {:?}", matches.occurrences_of("verbose"));
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/03_02_option.rs b/third_party/rust/clap/examples/tutorial_builder/03_02_option.rs
new file mode 100644
index 0000000000..29ad60a99c
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/03_02_option.rs
@@ -0,0 +1,11 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command};
+
+fn main() {
+ let matches = command!()
+ .arg(arg!(-n --name <NAME>).required(false))
+ .get_matches();
+
+ println!("name: {:?}", matches.value_of("name"));
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/03_03_positional.rs b/third_party/rust/clap/examples/tutorial_builder/03_03_positional.rs
new file mode 100644
index 0000000000..03bfab8e05
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/03_03_positional.rs
@@ -0,0 +1,9 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command};
+
+fn main() {
+ let matches = command!().arg(arg!([NAME])).get_matches();
+
+ println!("NAME: {:?}", matches.value_of("NAME"));
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/03_04_subcommands.rs b/third_party/rust/clap/examples/tutorial_builder/03_04_subcommands.rs
new file mode 100644
index 0000000000..1ab79e714d
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/03_04_subcommands.rs
@@ -0,0 +1,24 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command, Command};
+
+fn main() {
+ let matches = command!()
+ .propagate_version(true)
+ .subcommand_required(true)
+ .arg_required_else_help(true)
+ .subcommand(
+ Command::new("add")
+ .about("Adds files to myapp")
+ .arg(arg!([NAME])),
+ )
+ .get_matches();
+
+ match matches.subcommand() {
+ Some(("add", sub_matches)) => println!(
+ "'myapp add' was used, name is: {:?}",
+ sub_matches.value_of("NAME")
+ ),
+ _ => unreachable!("Exhausted list of subcommands and subcommand_required prevents `None`"),
+ }
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/03_05_default_values.rs b/third_party/rust/clap/examples/tutorial_builder/03_05_default_values.rs
new file mode 100644
index 0000000000..f88e3953c8
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/03_05_default_values.rs
@@ -0,0 +1,16 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command};
+
+fn main() {
+ let matches = command!()
+ .arg(arg!([NAME]).default_value("alice"))
+ .get_matches();
+
+ println!(
+ "NAME: {:?}",
+ matches
+ .value_of("NAME")
+ .expect("default ensures there is always a value")
+ );
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/04_01_enum.rs b/third_party/rust/clap/examples/tutorial_builder/04_01_enum.rs
new file mode 100644
index 0000000000..128b3cdc4a
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/04_01_enum.rs
@@ -0,0 +1,62 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command, ArgEnum, PossibleValue};
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ArgEnum)]
+enum Mode {
+ Fast,
+ Slow,
+}
+
+impl Mode {
+ pub fn possible_values() -> impl Iterator<Item = PossibleValue<'static>> {
+ Mode::value_variants()
+ .iter()
+ .filter_map(ArgEnum::to_possible_value)
+ }
+}
+
+impl std::fmt::Display for Mode {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.to_possible_value()
+ .expect("no values are skipped")
+ .get_name()
+ .fmt(f)
+ }
+}
+
+impl std::str::FromStr for Mode {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ for variant in Self::value_variants() {
+ if variant.to_possible_value().unwrap().matches(s, false) {
+ return Ok(*variant);
+ }
+ }
+ Err(format!("Invalid variant: {}", s))
+ }
+}
+
+fn main() {
+ let matches = command!()
+ .arg(
+ arg!(<MODE>)
+ .help("What mode to run the program in")
+ .possible_values(Mode::possible_values()),
+ )
+ .get_matches();
+
+ // Note, it's safe to call unwrap() because the arg is required
+ match matches
+ .value_of_t("MODE")
+ .expect("'MODE' is required and parsing will fail if its missing")
+ {
+ Mode::Fast => {
+ println!("Hare");
+ }
+ Mode::Slow => {
+ println!("Tortoise");
+ }
+ }
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/04_01_possible.rs b/third_party/rust/clap/examples/tutorial_builder/04_01_possible.rs
new file mode 100644
index 0000000000..77160392a3
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/04_01_possible.rs
@@ -0,0 +1,27 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command};
+
+fn main() {
+ let matches = command!()
+ .arg(
+ arg!(<MODE>)
+ .help("What mode to run the program in")
+ .possible_values(["fast", "slow"]),
+ )
+ .get_matches();
+
+ // Note, it's safe to call unwrap() because the arg is required
+ match matches
+ .value_of("MODE")
+ .expect("'MODE' is required and parsing will fail if its missing")
+ {
+ "fast" => {
+ println!("Hare");
+ }
+ "slow" => {
+ println!("Tortoise");
+ }
+ _ => unreachable!(),
+ }
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/04_02_parse.rs b/third_party/rust/clap/examples/tutorial_builder/04_02_parse.rs
new file mode 100644
index 0000000000..e354af3a8a
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/04_02_parse.rs
@@ -0,0 +1,19 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command};
+
+fn main() {
+ let matches = command!()
+ .arg(
+ arg!(<PORT>)
+ .help("Network port to use")
+ .validator(|s| s.parse::<usize>()),
+ )
+ .get_matches();
+
+ // Note, it's safe to call unwrap() because the arg is required
+ let port: usize = matches
+ .value_of_t("PORT")
+ .expect("'PORT' is required and parsing will fail if its missing");
+ println!("PORT = {}", port);
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/04_02_validate.rs b/third_party/rust/clap/examples/tutorial_builder/04_02_validate.rs
new file mode 100644
index 0000000000..a49f869e00
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/04_02_validate.rs
@@ -0,0 +1,38 @@
+// Note: this requires the `cargo` feature
+
+use std::ops::RangeInclusive;
+
+use clap::{arg, command};
+
+fn main() {
+ let matches = command!()
+ .arg(
+ arg!(<PORT>)
+ .help("Network port to use")
+ .validator(port_in_range),
+ )
+ .get_matches();
+
+ // Note, it's safe to call unwrap() because the arg is required
+ let port: usize = matches
+ .value_of_t("PORT")
+ .expect("'PORT' is required and parsing will fail if its missing");
+ println!("PORT = {}", port);
+}
+
+const PORT_RANGE: RangeInclusive<usize> = 1..=65535;
+
+fn port_in_range(s: &str) -> Result<(), String> {
+ let port: usize = s
+ .parse()
+ .map_err(|_| format!("`{}` isn't a port number", s))?;
+ if PORT_RANGE.contains(&port) {
+ Ok(())
+ } else {
+ Err(format!(
+ "Port not in range {}-{}",
+ PORT_RANGE.start(),
+ PORT_RANGE.end()
+ ))
+ }
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/04_03_relations.rs b/third_party/rust/clap/examples/tutorial_builder/04_03_relations.rs
new file mode 100644
index 0000000000..495bf365cc
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/04_03_relations.rs
@@ -0,0 +1,69 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command, ArgGroup};
+
+fn main() {
+ // Create application like normal
+ let matches = command!()
+ // Add the version arguments
+ .arg(arg!(--"set-ver" <VER> "set version manually").required(false))
+ .arg(arg!(--major "auto inc major"))
+ .arg(arg!(--minor "auto inc minor"))
+ .arg(arg!(--patch "auto inc patch"))
+ // Create a group, make it required, and add the above arguments
+ .group(
+ ArgGroup::new("vers")
+ .required(true)
+ .args(&["set-ver", "major", "minor", "patch"]),
+ )
+ // Arguments can also be added to a group individually, these two arguments
+ // are part of the "input" group which is not required
+ .arg(arg!([INPUT_FILE] "some regular input").group("input"))
+ .arg(
+ arg!(--"spec-in" <SPEC_IN> "some special input argument")
+ .required(false)
+ .group("input"),
+ )
+ // Now let's assume we have a -c [config] argument which requires one of
+ // (but **not** both) the "input" arguments
+ .arg(arg!(config: -c <CONFIG>).required(false).requires("input"))
+ .get_matches();
+
+ // 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) = matches.value_of("set-ver") {
+ ver.to_string()
+ } else {
+ // Increment the one requested (in a real program, we'd reset the lower numbers)
+ let (maj, min, pat) = (
+ matches.is_present("major"),
+ matches.is_present("minor"),
+ matches.is_present("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 matches.is_present("config") {
+ let input = matches
+ .value_of("INPUT_FILE")
+ .unwrap_or_else(|| matches.value_of("spec-in").unwrap());
+ println!(
+ "Doing work using input {} and config {}",
+ input,
+ matches.value_of("config").unwrap()
+ );
+ }
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/04_04_custom.rs b/third_party/rust/clap/examples/tutorial_builder/04_04_custom.rs
new file mode 100644
index 0000000000..6993329d32
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/04_04_custom.rs
@@ -0,0 +1,80 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command, ErrorKind};
+
+fn main() {
+ // Create application like normal
+ let mut cmd = command!()
+ // Add the version arguments
+ .arg(arg!(--"set-ver" <VER> "set version manually").required(false))
+ .arg(arg!(--major "auto inc major"))
+ .arg(arg!(--minor "auto inc minor"))
+ .arg(arg!(--patch "auto inc patch"))
+ // Arguments can also be added to a group individually, these two arguments
+ // are part of the "input" group which is not required
+ .arg(arg!([INPUT_FILE] "some regular input"))
+ .arg(arg!(--"spec-in" <SPEC_IN> "some special input argument").required(false))
+ // Now let's assume we have a -c [config] argument which requires one of
+ // (but **not** both) the "input" arguments
+ .arg(arg!(config: -c <CONFIG>).required(false));
+ let matches = cmd.get_matches_mut();
+
+ // 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) = matches.value_of("set-ver") {
+ if matches.is_present("major") || matches.is_present("minor") || matches.is_present("patch")
+ {
+ 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) = (
+ matches.is_present("major"),
+ matches.is_present("minor"),
+ matches.is_present("patch"),
+ );
+ match (maj, min, pat) {
+ (true, false, false) => major += 1,
+ (false, true, false) => minor += 1,
+ (false, false, true) => patch += 1,
+ _ => {
+ cmd.error(
+ ErrorKind::ArgumentConflict,
+ "Can only modify one version field",
+ )
+ .exit();
+ }
+ };
+ format!("{}.{}.{}", major, minor, patch)
+ };
+
+ println!("Version: {}", version);
+
+ // Check for usage of -c
+ if matches.is_present("config") {
+ let input = matches
+ .value_of("INPUT_FILE")
+ .or_else(|| matches.value_of("spec-in"))
+ .unwrap_or_else(|| {
+ cmd.error(
+ ErrorKind::MissingRequiredArgument,
+ "INPUT_FILE or --spec-in is required when using --config",
+ )
+ .exit()
+ });
+ println!(
+ "Doing work using input {} and config {}",
+ input,
+ matches.value_of("config").unwrap()
+ );
+ }
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/05_01_assert.rs b/third_party/rust/clap/examples/tutorial_builder/05_01_assert.rs
new file mode 100644
index 0000000000..f40f6ebd20
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/05_01_assert.rs
@@ -0,0 +1,26 @@
+// Note: this requires the `cargo` feature
+
+use clap::{arg, command};
+
+fn main() {
+ let matches = cmd().get_matches();
+
+ // Note, it's safe to call unwrap() because the arg is required
+ let port: usize = matches
+ .value_of_t("PORT")
+ .expect("'PORT' is required and parsing will fail if its missing");
+ println!("PORT = {}", port);
+}
+
+fn cmd() -> clap::Command<'static> {
+ command!().arg(
+ arg!(<PORT>)
+ .help("Network port to use")
+ .validator(|s| s.parse::<usize>()),
+ )
+}
+
+#[test]
+fn verify_app() {
+ cmd().debug_assert();
+}
diff --git a/third_party/rust/clap/examples/tutorial_builder/README.md b/third_party/rust/clap/examples/tutorial_builder/README.md
new file mode 100644
index 0000000000..fcbda4b3a0
--- /dev/null
+++ b/third_party/rust/clap/examples/tutorial_builder/README.md
@@ -0,0 +1,664 @@
+# Tutorial
+
+*Jump to [derive tutorial](../tutorial_derive/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 with several arguments using usage strings.
+
+[Example:](01_quick.rs)
+```console
+$ 01_quick --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 01_quick[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
+Debug mode is off
+
+```
+
+But you can mix and match the various features
+```console
+$ 01_quick -dd test
+Debug mode is on
+Not printing testing lists...
+
+```
+
+## Configuring the Parser
+
+You use the `Command` the start building a parser.
+
+[Example:](02_apps.rs)
+```console
+$ 02_apps --help
+MyApp 1.0
+Kevin K. <kbknapp@gmail.com>
+Does awesome things
+
+USAGE:
+ 02_apps[EXE] --two <VALUE> --one <VALUE>
+
+OPTIONS:
+ -h, --help Print help information
+ --one <VALUE>
+ --two <VALUE>
+ -V, --version Print version information
+
+$ 02_apps --version
+MyApp 1.0
+
+```
+
+You can use `command!()` to fill these fields in from your `Cargo.toml`
+file. **This requires the `cargo` feature flag.**
+
+[Example:](02_crate.rs)
+```console
+$ 02_crate --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 02_crate[EXE] --two <VALUE> --one <VALUE>
+
+OPTIONS:
+ -h, --help Print help information
+ --one <VALUE>
+ --two <VALUE>
+ -V, --version Print version information
+
+$ 02_crate --version
+clap [..]
+
+```
+
+You can use `Command` methods to change the application level behavior of clap.
+
+[Example:](02_app_settings.rs)
+```console
+$ 02_app_settings --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 02_app_settings[EXE] --two <VALUE> --one <VALUE>
+
+OPTIONS:
+ --two <VALUE>
+ --one <VALUE>
+ -h, --help Print help information
+ -V, --version Print version information
+
+$ 02_app_settings --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 --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 03_03_positional[EXE] [NAME]
+
+ARGS:
+ <NAME>
+
+OPTIONS:
+ -h, --help Print help information
+ -V, --version Print version information
+
+$ 03_03_positional
+NAME: None
+
+$ 03_03_positional bob
+NAME: Some("bob")
+
+```
+
+### Options
+
+You can name your arguments with a flag:
+- Order doesn't matter
+- They can be optional
+- Intent is clearer
+
+[Example:](03_02_option.rs)
+```console
+$ 03_02_option --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 03_02_option[EXE] [OPTIONS]
+
+OPTIONS:
+ -h, --help Print help information
+ -n, --name <NAME>
+ -V, --version Print version information
+
+$ 03_02_option
+name: None
+
+$ 03_02_option --name bob
+name: Some("bob")
+
+$ 03_02_option --name=bob
+name: Some("bob")
+
+$ 03_02_option -n bob
+name: Some("bob")
+
+$ 03_02_option -n=bob
+name: Some("bob")
+
+$ 03_02_option -nbob
+name: Some("bob")
+
+```
+
+### Flags
+
+Flags can also be switches that can be on/off:
+
+[Example:](03_01_flag_bool.rs)
+```console
+$ 03_01_flag_bool --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 03_01_flag_bool[EXE] [OPTIONS]
+
+OPTIONS:
+ -h, --help Print help information
+ -v, --verbose
+ -V, --version Print version information
+
+$ 03_01_flag_bool
+verbose: false
+
+$ 03_01_flag_bool --verbose
+verbose: true
+
+$ 03_01_flag_bool --verbose --verbose
+? failed
+error: The argument '--verbose' was provided more than once, but cannot be used multiple times
+
+USAGE:
+ 03_01_flag_bool[EXE] [OPTIONS]
+
+For more information try --help
+
+```
+
+Or counted.
+
+[Example:](03_01_flag_count.rs)
+```console
+$ 03_01_flag_count --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 03_01_flag_count[EXE] [OPTIONS]
+
+OPTIONS:
+ -h, --help Print help information
+ -v, --verbose
+ -V, --version Print version information
+
+$ 03_01_flag_count
+verbose: 0
+
+$ 03_01_flag_count --verbose
+verbose: 1
+
+$ 03_01_flag_count --verbose --verbose
+verbose: 2
+
+```
+
+### Subcommands
+
+Subcommands are defined as `Command`s that get added via `Command::subcommand`. 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 help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 03_04_subcommands[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 help add
+03_04_subcommands[EXE]-add [..]
+Adds files to myapp
+
+USAGE:
+ 03_04_subcommands[EXE] add [NAME]
+
+ARGS:
+ <NAME>
+
+OPTIONS:
+ -h, --help Print help information
+ -V, --version Print version information
+
+$ 03_04_subcommands add bob
+'myapp add' was used, name is: Some("bob")
+
+```
+
+Because we set `Command::arg_required_else_help`:
+```console
+$ 03_04_subcommands
+? failed
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 03_04_subcommands[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 set `Command::propagate_version`:
+```console
+$ 03_04_subcommands --version
+clap [..]
+
+$ 03_04_subcommands add --version
+03_04_subcommands[EXE]-add [..]
+
+```
+
+### Defaults
+
+We've previously showed that arguments can be `required` or optional. When
+optional, you work with a `Option` and can `unwrap_or`. Alternatively, you can
+set `Arg::default_value`.
+
+[Example:](03_05_default_values.rs)
+```console
+$ 03_05_default_values --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 03_05_default_values[EXE] [NAME]
+
+ARGS:
+ <NAME> [default: alice]
+
+OPTIONS:
+ -h, --help Print help information
+ -V, --version Print version information
+
+$ 03_05_default_values
+NAME: "alice"
+
+$ 03_05_default_values bob
+NAME: "bob"
+
+```
+
+## Validation
+
+### Enumerated values
+
+If you have arguments of specific values you want to test for, you can use the
+`Arg::possible_values()`.
+
+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_possible.rs)
+```console
+$ 04_01_possible --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 04_01_possible[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_possible fast
+Hare
+
+$ 04_01_possible slow
+Tortoise
+
+$ 04_01_possible medium
+? failed
+error: "medium" isn't a valid value for '<MODE>'
+ [possible values: fast, slow]
+
+USAGE:
+ 04_01_possible[EXE] <MODE>
+
+For more information try --help
+
+```
+
+When enabling the `derive` feature, you can use `ArgEnum` to take care of the boiler plate for you, giving the same results.
+
+[Example:](04_01_enum.rs)
+```console
+$ 04_01_enum --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 04_01_enum[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 fast
+Hare
+
+$ 04_01_enum slow
+Tortoise
+
+$ 04_01_enum medium
+? failed
+error: "medium" isn't a valid value for '<MODE>'
+ [possible values: fast, slow]
+
+USAGE:
+ 04_01_enum[EXE] <MODE>
+
+For more information try --help
+
+```
+
+### Validated values
+
+More generally, you can parse into any data type.
+
+[Example:](04_02_parse.rs)
+```console
+$ 04_02_parse --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 04_02_parse[EXE] <PORT>
+
+ARGS:
+ <PORT> Network port to use
+
+OPTIONS:
+ -h, --help Print help information
+ -V, --version Print version information
+
+$ 04_02_parse 22
+PORT = 22
+
+$ 04_02_parse foobar
+? failed
+error: Invalid value "foobar" for '<PORT>': invalid digit found in string
+
+For more information try --help
+
+```
+
+A custom validator can be used to improve the error messages or provide additional validation:
+
+[Example:](04_02_validate.rs)
+```console
+$ 04_02_validate --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 04_02_validate[EXE] <PORT>
+
+ARGS:
+ <PORT> Network port to use
+
+OPTIONS:
+ -h, --help Print help information
+ -V, --version Print version information
+
+$ 04_02_validate 22
+PORT = 22
+
+$ 04_02_validate foobar
+? failed
+error: Invalid value "foobar" for '<PORT>': `foobar` isn't a port number
+
+For more information try --help
+
+$ 04_02_validate 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 --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 04_03_relations[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
+? failed
+error: The following required arguments were not provided:
+ <--set-ver <VER>|--major|--minor|--patch>
+
+USAGE:
+ 04_03_relations[EXE] [OPTIONS] <--set-ver <VER>|--major|--minor|--patch> [INPUT_FILE]
+
+For more information try --help
+
+$ 04_03_relations --major
+Version: 2.2.3
+
+$ 04_03_relations --major --minor
+? failed
+error: The argument '--major' cannot be used with '--minor'
+
+USAGE:
+ 04_03_relations[EXE] <--set-ver <VER>|--major|--minor|--patch>
+
+For more information try --help
+
+$ 04_03_relations --major -c config.toml
+? failed
+error: The following required arguments were not provided:
+ <INPUT_FILE|--spec-in <SPEC_IN>>
+
+USAGE:
+ 04_03_relations[EXE] -c <CONFIG> <--set-ver <VER>|--major|--minor|--patch> <INPUT_FILE|--spec-in <SPEC_IN>>
+
+For more information try --help
+
+$ 04_03_relations --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 --help
+clap [..]
+A simple to use, efficient, and full-featured Command Line Argument Parser
+
+USAGE:
+ 04_04_custom[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
+? failed
+error: Can only modify one version field
+
+USAGE:
+ 04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
+
+For more information try --help
+
+$ 04_04_custom --major
+Version: 2.2.3
+
+$ 04_04_custom --major --minor
+? failed
+error: Can only modify one version field
+
+USAGE:
+ 04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
+
+For more information try --help
+
+$ 04_04_custom --major -c config.toml
+? failed
+Version: 2.2.3
+error: INPUT_FILE or --spec-in is required when using --config
+
+USAGE:
+ 04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
+
+For more information try --help
+
+$ 04_04_custom --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).
+- 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 [derive tutorial](../tutorial_derive/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).
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).
diff --git a/third_party/rust/clap/examples/typed-derive.md b/third_party/rust/clap/examples/typed-derive.md
new file mode 100644
index 0000000000..7c61f70d9a
--- /dev/null
+++ b/third_party/rust/clap/examples/typed-derive.md
@@ -0,0 +1,86 @@
+*Jump to [source](typed-derive.rs)*
+
+**This requires enabling the `derive` feature flag.**
+
+Help:
+```console
+$ typed-derive --help
+clap
+
+USAGE:
+ typed-derive[EXE] [OPTIONS]
+
+OPTIONS:
+ --bind <BIND> Handle IP addresses
+ -D <DEFINES> Hand-written parser for tuples
+ -h, --help Print help information
+ -I <DIR> Allow invalid UTF-8 paths
+ -O <OPTIMIZATION> Implicitly using `std::str::FromStr`
+ --sleep <SLEEP> Allow human-readable durations
+
+```
+
+Optimization-level (number)
+```console
+$ typed-derive -O 1
+Args { optimization: Some(1), include: None, bind: None, sleep: None, defines: [] }
+
+$ typed-derive -O plaid
+? failed
+error: Invalid value "plaid" for '-O <OPTIMIZATION>': invalid digit found in string
+
+For more information try --help
+
+```
+
+Include (path)
+```console
+$ typed-derive -I../hello
+Args { optimization: None, include: Some("../hello"), bind: None, sleep: None, defines: [] }
+
+```
+
+IP Address
+```console
+$ typed-derive --bind 192.0.0.1
+Args { optimization: None, include: None, bind: Some(192.0.0.1), sleep: None, defines: [] }
+
+$ typed-derive --bind localhost
+? failed
+error: Invalid value "localhost" for '--bind <BIND>': invalid IP address syntax
+
+For more information try --help
+
+```
+
+Time
+```console
+$ typed-derive --sleep 10s
+Args { optimization: None, include: None, bind: None, sleep: Some(Duration(10s)), defines: [] }
+
+$ typed-derive --sleep forever
+? failed
+error: Invalid value "forever" for '--sleep <SLEEP>': expected number at 0
+
+For more information try --help
+
+```
+
+Defines (key-value pairs)
+```console
+$ typed-derive -D Foo=10 -D Alice=30
+Args { optimization: None, include: None, bind: None, sleep: None, defines: [("Foo", 10), ("Alice", 30)] }
+
+$ typed-derive -D Foo
+? failed
+error: Invalid value "Foo" for '-D <DEFINES>': invalid KEY=value: no `=` found in `Foo`
+
+For more information try --help
+
+$ typed-derive -D Foo=Bar
+? failed
+error: Invalid value "Foo=Bar" for '-D <DEFINES>': invalid digit found in string
+
+For more information try --help
+
+```
diff --git a/third_party/rust/clap/examples/typed-derive.rs b/third_party/rust/clap/examples/typed-derive.rs
new file mode 100644
index 0000000000..237bbe15e8
--- /dev/null
+++ b/third_party/rust/clap/examples/typed-derive.rs
@@ -0,0 +1,46 @@
+// Note: this requires the `derive` feature
+
+use clap::Parser;
+use std::error::Error;
+
+#[derive(Parser, Debug)]
+struct Args {
+ /// Implicitly using `std::str::FromStr`
+ #[clap(short = 'O')]
+ optimization: Option<usize>,
+
+ /// Allow invalid UTF-8 paths
+ #[clap(short = 'I', parse(from_os_str), value_name = "DIR", value_hint = clap::ValueHint::DirPath)]
+ include: Option<std::path::PathBuf>,
+
+ /// Handle IP addresses
+ #[clap(long)]
+ bind: Option<std::net::IpAddr>,
+
+ /// Allow human-readable durations
+ #[clap(long)]
+ sleep: Option<humantime::Duration>,
+
+ /// Hand-written parser for tuples
+ #[clap(short = 'D', parse(try_from_str = parse_key_val), multiple_occurrences(true))]
+ defines: Vec<(String, i32)>,
+}
+
+/// Parse a single key-value pair
+fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error + Send + Sync + 'static>>
+where
+ T: std::str::FromStr,
+ T::Err: Error + Send + Sync + 'static,
+ U: std::str::FromStr,
+ U::Err: Error + Send + Sync + 'static,
+{
+ let pos = s
+ .find('=')
+ .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?;
+ Ok((s[..pos].parse()?, s[pos + 1..].parse()?))
+}
+
+fn main() {
+ let args = Args::parse();
+ println!("{:?}", args);
+}