diff --git a/Cargo.toml b/Cargo.toml index 38224475..1ac40b97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -125,6 +125,8 @@ regex = "1.0" lazy_static = "1" version-sync = "0.9" criterion = "0.3.2" +# Cutting out `filesystem` feature +trycmd = { version = "0.8.0", default-features = false, features = ["color-auto", "diff", "examples"] } [[example]] name = "busybox" diff --git a/examples/01a_quick_example.md b/examples/01a_quick_example.md new file mode 100644 index 00000000..8e9bc724 --- /dev/null +++ b/examples/01a_quick_example.md @@ -0,0 +1,40 @@ +This example shows how to create an application with several arguments using usage strings + +Let's first check out the help: +```bash +$ 01a_quick_example --help +MyApp 1.0 + +Kevin K. + +Does awesome things + +USAGE: + 01a_quick_example[EXE] [OPTIONS] [output] [SUBCOMMAND] + +ARGS: + Sets an optional output file + +OPTIONS: + -c, --config 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: +```bash +$ 01a_quick_example +Debug mode is off +``` + +But you can mix and match the various features +```bash +$ 01a_quick_example -dd test +Debug mode is on +Not printing testing lists... +``` diff --git a/examples/01b_quick_example.md b/examples/01b_quick_example.md new file mode 100644 index 00000000..55b1f9fe --- /dev/null +++ b/examples/01b_quick_example.md @@ -0,0 +1,40 @@ +This method shows the traditional, and slightly more configurable way to set up arguments. + +Let's first check out the help: +```bash +$ 01b_quick_example --help +MyApp 1.0 + +Kevin K. + +Does awesome things + +USAGE: + 01b_quick_example[EXE] [OPTIONS] [output] [SUBCOMMAND] + +ARGS: + Sets an optional output file + +OPTIONS: + -c, --config 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: +```bash +$ 01b_quick_example +Debug mode is off +``` + +But you can mix and match the various features +```bash +$ 01b_quick_example -dd test +Debug mode is on +Not printing testing lists... +``` diff --git a/examples/02_apps.md b/examples/02_apps.md new file mode 100644 index 00000000..e26b1dcf --- /dev/null +++ b/examples/02_apps.md @@ -0,0 +1,24 @@ +Apps describe the top level application + +You can see this in the help: +```bash +$ 02_apps --help +MyApp 1.0 + +Kevin K. + +Does awesome things + +USAGE: + 02_apps[EXE] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information +``` + +And among the version +```bash +$ 02_apps --version +MyApp 1.0 +``` diff --git a/examples/02_apps.rs b/examples/02_apps.rs index c5e688cb..4f559de9 100644 --- a/examples/02_apps.rs +++ b/examples/02_apps.rs @@ -1,8 +1,6 @@ use clap::App; fn main() { - // Apps describe the top level application - // // You create an App and set various options on that App using the "builder pattern" // // The options (version(), author(), about()) aren't mandatory, but recommended. There is diff --git a/examples/03_args.md b/examples/03_args.md new file mode 100644 index 00000000..ee2caf6f --- /dev/null +++ b/examples/03_args.md @@ -0,0 +1,29 @@ +Args describe a possible valid argument which may be supplied by the user at runtime. There +are three different types of arguments (flags, options, and positional) as well as a fourth +special type of argument, called Subcommands (which will be discussed separately). + +# Help and Version + +`clap` automatically generates a help and version flag for you, unless you specify your +own. By default help uses "-h" and "--help", and version uses "-V" and "--version". You can +safely override "-V" and "-h" to your own arguments, and "--help" and "--version" will still +be automatically generated for you. + +```bash +$ 03_args --help +MyApp + +USAGE: + 03_args[EXE] [OPTIONS] [output] + +ARGS: + the input file to use + Supply an output file to use + +OPTIONS: + -c, --config sets the config file to use + -d turn on debugging information + -h, --help Print help information + -i, --int Set an interface to use + --license display the license file +``` diff --git a/examples/03_args.rs b/examples/03_args.rs index 47b8b619..ada80fc5 100644 --- a/examples/03_args.rs +++ b/examples/03_args.rs @@ -1,10 +1,6 @@ use clap::{arg, App, Arg}; fn main() { - // Args describe a possible valid argument which may be supplied by the user at runtime. There - // are three different types of arguments (flags, options, and positional) as well as a fourth - // special type of argument, called Subcommands (which will be discussed separately). - // // Args are described in the same manner as Apps using the "builder pattern" with multiple // methods describing various settings for the individual arguments. Or by supplying a "usage" // string. Both methods have their pros and cons. @@ -16,12 +12,6 @@ fn main() { // three types of arguments, some only apply one or two of the types. *NOTE* if you set // incompatible options on a single argument, clap will panic! at runtime. This is by design, // so that you know right away an error was made by the developer, not the end user. - // - // # Help and Version - // clap automatically generates a help and version flag for you, unless you specify your - // own. By default help uses "-h" and "--help", and version uses "-V" and "--version". You can - // safely override "-V" and "-h" to your own arguments, and "--help" and "--version" will still - // be automatically generated for you. let matches = App::new("MyApp") // All application settings go here... // A simple "Flag" argument example (i.e. "-d") using the builder pattern diff --git a/examples/04_using_matches.md b/examples/04_using_matches.md new file mode 100644 index 00000000..8c7c3c83 --- /dev/null +++ b/examples/04_using_matches.md @@ -0,0 +1,15 @@ +Once all App settings (including all arguments) have been set, you call get_matches() which +parses the string provided by the user, and returns all the valid matches to the ones you +specified. + +For example: +```bash +$ 04_using_matches input +Doing real work with file: input +$ 04_using_matches input --debug +Debugging is turned on +Doing real work with file: input +$ 04_using_matches input --config path +Using config file: path +Doing real work with file: input +``` diff --git a/examples/05_flag_args.md b/examples/05_flag_args.md new file mode 100644 index 00000000..b7c1a857 --- /dev/null +++ b/examples/05_flag_args.md @@ -0,0 +1,62 @@ +Of the three argument types, flags are the most simple. Flags are simple switches which can +be either "on" or "off" + +`clap` also supports multiple occurrences of flags, the common example is "verbosity" where a +user could want a little information with "-v" or tons of information with "-v -v" or "-vv" + +Let's look at their help: +```bash +$ 05_flag_args --help +MyApp + +USAGE: + 05_flag_args[EXE] [OPTIONS] [output] + +ARGS: + sets an output file + +OPTIONS: + -a, --awesome turns up the awesome + -c, --config sets a custom config file + -h, --help Print help information +``` + +By default, nothing happens: +```bash +$ 05_flag_args +Nothing is awesome +``` + +Note that `--awesome` places requirements on how other flags are used: +```bash +$ 05_flag_args --awesome +? failed +error: The following required arguments were not provided: + --config + +USAGE: + 05_flag_args[EXE] --config --awesome + +For more information try --help +$ 05_flag_args output.txt --config file.toml --awesome +? failed +error: The argument '--awesome' cannot be used with '' + +USAGE: + 05_flag_args[EXE] --config + +For more information try --help +``` + +You can then add `--awesome` as many times as you like: +```bash +$ 05_flag_args --config file.toml --awesome +Awesomeness is turned on +Some things are awesome +$ 05_flag_args --config file.toml --awesome --awesome +Awesomeness is turned on +Lots of things are awesome +$ 05_flag_args --config file.toml -aaaaaaaaaaaaaaaaaa +Awesomeness is turned on +EVERYTHING is awesome! +``` diff --git a/examples/05_flag_args.rs b/examples/05_flag_args.rs index 40df9455..99244e23 100644 --- a/examples/05_flag_args.rs +++ b/examples/05_flag_args.rs @@ -1,11 +1,6 @@ use clap::{arg, App, Arg}; fn main() { - // Of the three argument types, flags are the most simple. Flags are simple switches which can - // be either "on" or "off" - // - // clap also supports multiple occurrences of flags, the common example is "verbosity" where a - // user could want a little information with "-v" or tons of information with "-v -v" or "-vv" let matches = App::new("MyApp") // Regular App configuration goes here... // We'll add a flag that represents an awesome meter... diff --git a/examples/06_positional_args.md b/examples/06_positional_args.md new file mode 100644 index 00000000..9b941b8e --- /dev/null +++ b/examples/06_positional_args.md @@ -0,0 +1,53 @@ +Positional arguments are those values after the program name which are not preceded by any +identifier (such as "myapp some_file"). Positionals support many of the same options as +flags, as well as a few additional ones. + +Let's look at their help: +```bash +$ 06_positional_args --help +MyApp + +USAGE: + 06_positional_args[EXE] [config] + +ARGS: + the input file to use + the config file to use + +OPTIONS: + -h, --help Print help information +``` + +First, we see that the first argument is required: +``` +$ 06_positional_args +? failed +error: The following required arguments were not provided: + + + +USAGE: + 06_positional_args[EXE] [config] + +For more information try --help +``` + +That first argument causes the second to be required: +``` +$ 06_positional_args input.txt +? failed +error: The following required arguments were not provided: + + +USAGE: + 06_positional_args[EXE] [config] + +For more information try --help +``` + +Everything works now that we specify both: +``` +$ 06_positional_args input.txt config.toml +An input file was specified +Doing work with input.txt and config.toml +``` diff --git a/examples/06_positional_args.rs b/examples/06_positional_args.rs index 3d49bdd7..99815d3a 100644 --- a/examples/06_positional_args.rs +++ b/examples/06_positional_args.rs @@ -1,9 +1,6 @@ use clap::{App, Arg}; fn main() { - // Positional arguments are those values after the program name which are not preceded by any - // identifier (such as "myapp some_file"). Positionals support many of the same options as - // flags, as well as a few additional ones. let matches = App::new("MyApp") // Regular App configuration goes here... // We'll add two positional arguments, an input file, and a config file. diff --git a/examples/07_option_args.md b/examples/07_option_args.md new file mode 100644 index 00000000..9f67e84c --- /dev/null +++ b/examples/07_option_args.md @@ -0,0 +1,77 @@ +Option arguments are those that take an additional value, such as "-c value". In clap they +support three types of specification, those with short() as "-o some", or those with long() +as "--option value" or "--option=value" + +Options also support a multiple setting, which is discussed in the example below. + +Let's look at their help: +```bash +$ 07_option_args --help +MyApp + +USAGE: + 07_option_args[EXE] [OPTIONS] --input [output] + +ARGS: + the output file to use + +OPTIONS: + -c, --config the config file to use + -h, --help Print help information + -i, --input the input file to use +``` + +First, we see that `--input` is required: +```bash +$ 07_option_args +? failed +error: The following required arguments were not provided: + --config + --input + +USAGE: + 07_option_args[EXE] [OPTIONS] --input [output] + +For more information try --help +``` + +But `--input` also requires `--config`: +```bash +$ 07_option_args --input input.txt --input another.txt +? failed +error: The following required arguments were not provided: + --config + +USAGE: + 07_option_args[EXE] [OPTIONS] --input --config [output] + +For more information try --help +``` + +Everything works now that we specify both: +```bash +$ 07_option_args --input input.txt --input another.txt --config config.toml +An input file was specified +An input file: input.txt +An input file: input.txt +An input file: another.txt +The "input" argument was used 2 times +``` + +But we can't mix this with output: +```bash +$ 07_option_args --input input.txt --input another.txt --config config.toml output.txt +? failed +error: The argument '' cannot be used with '--input ' + +USAGE: + 07_option_args[EXE] --input --input --config + +For more information try --help +``` + +That requires passing it in by itself: +```bash +$ 07_option_args output.txt +The "input" argument was used 0 times +``` diff --git a/examples/07_option_args.rs b/examples/07_option_args.rs index e19cebee..705bceaf 100644 --- a/examples/07_option_args.rs +++ b/examples/07_option_args.rs @@ -1,11 +1,6 @@ use clap::{arg, App, Arg}; fn main() { - // Option arguments are those that take an additional value, such as "-c value". In clap they - // support three types of specification, those with short() as "-o some", or those with long() - // as "--option value" or "--option=value" - // - // Options also support a multiple setting, which is discussed in the example below. let matches = App::new("MyApp") // Regular App configuration goes here... // Assume we have an application that accepts an input file via the "-i file" diff --git a/examples/08_subcommands.md b/examples/08_subcommands.md new file mode 100644 index 00000000..bc59971b --- /dev/null +++ b/examples/08_subcommands.md @@ -0,0 +1,61 @@ +Subcommands function exactly like sub-Apps, because that's exactly what they are. Each +instance of a Subcommand can have its own version, author(s), Args, and even its own +subcommands. + +Just like Apps, each subcommand will get its own "help" and "version" flags automatically +generated. Also, like Apps, you can override "-V" or "-h" safely and still get "--help" and +"--version" auto generated. + +**NOTE:** If you specify a subcommand for your App, clap will also autogenerate a "help" +subcommand along with "-h" and "--help" (applies to sub-subcommands as well). + +```bash +$ 08_subcommands help +MyApp 1.0 + +USAGE: + 08_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) +$ 08_subcommands help add +08_subcommands[EXE]-add 0.1 + +Kevin K. + +Adds files to myapp + +USAGE: + 08_subcommands[EXE] add + +ARGS: + the file to add + +OPTIONS: + -h, --help Print help information + -V, --version Print version information +$ 08_subcommands add help +'myapp add' was used, input is: help +``` + +```bash +$ 08_subcommands --version +MyApp 1.0 +``` + +Without any subcommand: +```bash +$ 08_subcommands +No subcommand was used +``` + +And with: +```bash +$ 08_subcommands add input.txt +'myapp add' was used, input is: input.txt +``` diff --git a/examples/08_subcommands.rs b/examples/08_subcommands.rs index 82f9eee7..add2c58b 100644 --- a/examples/08_subcommands.rs +++ b/examples/08_subcommands.rs @@ -1,21 +1,10 @@ use clap::{App, Arg}; fn main() { - // Subcommands function exactly like sub-Apps, because that's exactly what they are. Each - // instance of a Subcommand can have its own version, author(s), Args, and even its own - // subcommands. - // - // # Help and Version - // Just like Apps, each subcommand will get its own "help" and "version" flags automatically - // generated. Also, like Apps, you can override "-V" or "-h" safely and still get "--help" and - // "--version" auto generated. - // - // NOTE: If you specify a subcommand for your App, clap will also autogenerate a "help" - // subcommand along with "-h" and "--help" (applies to sub-subcommands as well). - // // Just like arg() and args(), subcommands can be specified one at a time via subcommand() or // multiple ones at once with a Vec provided to subcommands(). let matches = App::new("MyApp") + .version("1.0") // Normal App and Arg configuration goes here... // In the following example assume we wanted an application which // supported an "add" subcommand, this "add" subcommand also took diff --git a/examples/09_cargo_metadata.md b/examples/09_cargo_metadata.md new file mode 100644 index 00000000..fff7619d --- /dev/null +++ b/examples/09_cargo_metadata.md @@ -0,0 +1,21 @@ +You can have clap pull the application metadata directly from your Cargo.toml using the +`app_from_crate!()` macro. + +```bash +$ 09_cargo_metadata --help +clap 3.0.0-beta.5 + +Kevin K. :Clap Maintainers + +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 09_cargo_metadata[EXE] + +OPTIONS: + -h, --help Print help information + -V, --version Print version information +$ 09_cargo_metadata --version +... +``` +*(censored to keep the release process easy)* diff --git a/examples/10_default_values.md b/examples/10_default_values.md new file mode 100644 index 00000000..f8495039 --- /dev/null +++ b/examples/10_default_values.md @@ -0,0 +1,30 @@ +Using `Arg::default_value`, rather than `Option::unwrap_or`, gives clap more information it can use with our argument. + +For example, let's look at the help: +```bash +$ 10_default_values --help +myapp + +does awesome things + +USAGE: + 10_default_values[EXE] [OPTIONS] [INPUT] + +ARGS: + The input file to use [default: input.txt] + +OPTIONS: + -c The config file to use + -h, --help Print help information +``` +``'s description says what the default is while `-c`'s does not. + +Otherwise, they'll work the same: +```bash +$ 10_default_values +The input file is: input.txt +The config file is: config.json +$ 10_default_values other.txt -c other.toml +The input file is: other.txt +The config file is: other.toml +``` diff --git a/examples/10_default_values.rs b/examples/10_default_values.rs index 714449bf..73668f84 100644 --- a/examples/10_default_values.rs +++ b/examples/10_default_values.rs @@ -1,12 +1,6 @@ use clap::{App, Arg}; fn main() { - // There are two ways in which to get a default value, one is to use clap's Arg::default_value - // method, and the other is to use Rust's built in Option::unwrap_or method. - // - // I'll demo both here. - // - // First, we'll use clap's Arg::default_value with an "INPUT" file. let matches = App::new("myapp") .about("does awesome things") .arg( diff --git a/examples/11_only_specific_values.md b/examples/11_only_specific_values.md new file mode 100644 index 00000000..0eb188f8 --- /dev/null +++ b/examples/11_only_specific_values.md @@ -0,0 +1,48 @@ +If you have arguments of specific values you want to test for, you can use the +.possible_values() method of Arg + +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 + +For this example, assume you want one positional argument of either "fast" or "slow" +i.e. the only possible ways to run the program are "myprog fast" or "myprog slow" + +```bash +$ 11_only_specific_values fast +Hare +$ 11_only_specific_values slow +Tortoise +``` + +Anything else will error, guiding the user to a valid value: +```bash +$ 11_only_specific_values medium +? failed +error: "medium" isn't a valid value for '' + [possible values: fast, slow] + +USAGE: + 11_only_specific_values[EXE] + +For more information try --help +``` + +Valid values also get shown in the help: +```bash +$ 11_only_specific_values --help +myapp + +does awesome things + +USAGE: + 11_only_specific_values[EXE] + +ARGS: + What mode to run the program in [possible values: fast, slow] + +OPTIONS: + -h, --help Print help information +``` + +For integrating this with enums, see [13_enum_values](13_enum_values.md) diff --git a/examples/11_only_specific_values.rs b/examples/11_only_specific_values.rs index 7d0a3453..f7458fe1 100644 --- a/examples/11_only_specific_values.rs +++ b/examples/11_only_specific_values.rs @@ -1,15 +1,6 @@ use clap::{App, Arg}; fn main() { - // If you have arguments of specific values you want to test for, you can use the - // .possible_values() method of Arg - // - // 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 - // - // For this example, assume you want one positional argument of either "fast" or "slow" - // i.e. the only possible ways to run the program are "myprog fast" or "myprog slow" let matches = App::new("myapp") .about("does awesome things") .arg( diff --git a/examples/12_typed_values.md b/examples/12_typed_values.md new file mode 100644 index 00000000..9cf8c554 --- /dev/null +++ b/examples/12_typed_values.md @@ -0,0 +1,32 @@ +You can use some convenience methods provided by clap to get typed values, so long as the +type you're converting into implements std::str::FromStr + +This works for both single, and multiple values (multiple values returns a Vec) + +When getting a typed value, a Result is returned which allows you decide what to do upon a failure, whether exit, provide a +default value, etc. You have control. But it also means you have to write the code or boiler plate +to handle those instances. + +For example, you could exit: +```bash +$ 12_typed_values 1 2 3 +Sequence part 1 + 2: 3 +Sequence part 2 + 2: 4 +Sequence part 3 + 2: 5 +len (10) + 2 = 12 +$ 12_typed_values 1 2 3 four +? failed +error: Invalid value for 'seq': The argument 'four' isn't a valid value: invalid digit found in string +``` + +Or provide a fallback: +```bash +$ 12_typed_values 1 -l 3 +Sequence part 1 + 2: 3 +len (3) + 2 = 5 +$ 12_typed_values 1 -l four +Sequence part 1 + 2: 3 +len (10) + 2 = 12 +``` + +Or you can have clap do the error reporting for you, see [15_custom_validator](15_custom_validator.md) diff --git a/examples/12_typed_values.rs b/examples/12_typed_values.rs index 819a5636..862a8c25 100644 --- a/examples/12_typed_values.rs +++ b/examples/12_typed_values.rs @@ -1,24 +1,6 @@ use clap::{arg, App}; fn main() { - // You can use some convenience methods provided by clap to get typed values, so long as the - // type you're converting into implements std::str::FromStr - // - // This works for both single, and multiple values (multiple values returns a Vec) - // - // There are also two ways in which to get types, those where failures cause the program to exit - // with an error and usage string, and those which return a Result or Result,String> - // respectively. Both methods support single and multiple values. - // - // The method which returns a Result allows you decide what to do upon a failure, exit, provide a - // default value, etc. You have control. But it also means you have to write the code or boiler plate - // to handle those instances. - // - // That is why the second method exists, so you can simply get a T or Vec back, or be sure the - // program will exit gracefully. The catch is, the second method should *only* be used on required - // arguments, because if the argument isn't found, it exits. Just FYI ;) - // - // The following example shows both methods. let matches = App::new("myapp") // Create two arguments, a required positional which accepts multiple values // and an optional '-l value' diff --git a/examples/13_enum_values.md b/examples/13_enum_values.md new file mode 100644 index 00000000..93ac8244 --- /dev/null +++ b/examples/13_enum_values.md @@ -0,0 +1,37 @@ +Building on [11_only_specific_values](11_only_specific_values.md), we will create an enum with 4 values, assign a positional argument +that accepts only one of those values, and use clap to parse the argument. + +```bash +$ 13_enum_values Foo +Found a Foo +$ 13_enum_values Bar +Found a Bar +``` + +Anything else will error, guiding the user to a valid value: +```bash +$ 13_enum_values Alice +? failed +error: "Alice" isn't a valid value for '' + [possible values: Bar, Baz, Foo, Qux] + +USAGE: + 13_enum_values[EXE] + +For more information try --help +``` + +Valid values also get shown in the help: +```bash +$ 13_enum_values --help +myapp + +USAGE: + 13_enum_values[EXE] + +ARGS: + The type to use [possible values: Foo, Bar, Baz, Qux] + +OPTIONS: + -h, --help Print help information +``` diff --git a/examples/13_enum_values.rs b/examples/13_enum_values.rs index d67acc8d..13756e12 100644 --- a/examples/13_enum_values.rs +++ b/examples/13_enum_values.rs @@ -1,6 +1,3 @@ -// In the following example we will create an enum with 4 values, assign a positional argument -// that accepts only one of those values, and use clap to parse the argument. -// // Start with bringing the trait into scope. use std::str::FromStr; diff --git a/examples/14_groups.md b/examples/14_groups.md new file mode 100644 index 00000000..e6f0f510 --- /dev/null +++ b/examples/14_groups.md @@ -0,0 +1,53 @@ +`ArgGroup`s are a family of related arguments and way for you to say, "Any of these arguments". +By placing arguments in a logical group, you can make easier requirement and exclusion rules +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. For example, lets say that you were building an application where one could set a +given version number by supplying a string with an option argument, i.e. `--set-ver v1.2.3`, you +also wanted to support automatically using a previous version number and simply incrementing one +of the three numbers. So you create three flags `--major`, `--minor`, and `--patch`. All of +these arguments shouldn't be used at one time but you want to specify that *at least one* of +them is used. For this, you can create a group. +```bash +$ 14_groups +? failed +error: The following required arguments were not provided: + <--set-ver |--major|--minor|--patch> + +USAGE: + 14_groups[EXE] [OPTIONS] <--set-ver |--major|--minor|--patch> [INPUT_FILE] + +For more information try --help +$ 14_groups --major +Version: 2.2.3 +$ 14_groups --major --minor +? failed +error: The argument '--major' cannot be used with '--minor' + +USAGE: + 14_groups[EXE] [OPTIONS] <--set-ver |--major|--minor|--patch> [INPUT_FILE] + +For more information try --help +``` + +You can also do things such as name an ArgGroup as a confliction or requirement, meaning any +of the arguments that belong to that group will cause a failure if present, or must present +respectively. +```bash +$ 14_groups --major -c config.toml +? failed +error: The following required arguments were not provided: + > + +USAGE: + 14_groups[EXE] -c <--set-ver |--major|--minor|--patch> > + +For more information try --help +$ 14_groups --major -c config.toml --spec-in input.txt +Version: 2.2.3 +Doing work using input input.txt and config config.toml +``` diff --git a/examples/14_groups.rs b/examples/14_groups.rs index 738187e8..79d6acfd 100644 --- a/examples/14_groups.rs +++ b/examples/14_groups.rs @@ -1,25 +1,3 @@ -/// `ArgGroup`s are a family of related arguments and way for you to say, "Any of these arguments". -/// By placing arguments in a logical group, you can make easier requirement and exclusion rules -/// instead of having to list each individually, or when you want a rule to apply "any but not all" -/// arguments. -/// -/// For instance, you can make an entire ArgGroup required, this means that one (and *only* one) -/// argument. from that group must be present. Using more than one argument from an ArgGroup causes -/// a failure (graceful exit). -/// -/// You can also do things such as name an ArgGroup as a confliction or requirement, meaning any -/// of the arguments that belong to that group will cause a failure if present, or must present -/// respectively. -/// -/// 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. For example, lets say that you were building an application where one could set a -/// given version number by supplying a string with an option argument, i.e. `--set-ver v1.2.3`, you -/// also wanted to support automatically using a previous version number and simply incrementing one -/// of the three numbers. So you create three flags `--major`, `--minor`, and `--patch`. All of -/// these arguments shouldn't be used at one time but you want to specify that *at least one* of -/// them is used. For this, you can create a group. use clap::{arg, App, Arg, ArgGroup}; fn main() { diff --git a/examples/15_custom_validator.md b/examples/15_custom_validator.md new file mode 100644 index 00000000..99e2eb61 --- /dev/null +++ b/examples/15_custom_validator.md @@ -0,0 +1,15 @@ +You can define a function (or a closure) to use as a validator to argument values. The +function must accept a `&str` and return `Result<(), String>` where `Err(String)` is the +message displayed to the user. + +```bash +$ 15_custom_validator input.png +The .PNG file is: input.png +$ 15_custom_validator input.txt +? failed +error: Invalid value for '': the file format must be png. + +For more information try --help +``` + +This is especially useful when using [custom types](12_types_values.md). diff --git a/examples/15_custom_validator.rs b/examples/15_custom_validator.rs index 4d190ea4..4161bc0f 100644 --- a/examples/15_custom_validator.rs +++ b/examples/15_custom_validator.rs @@ -1,10 +1,6 @@ use clap::{App, Arg}; fn main() { - // You can define a function (or a closure) to use as a validator to argument values. The - // function must accept a `&str` and return `Result<(), String>` where `Err(String)` is the - // message displayed to the user. - let matches = App::new("myapp") // Application logic goes here... .arg( diff --git a/examples/16_app_settings.md b/examples/16_app_settings.md new file mode 100644 index 00000000..56d37bb6 --- /dev/null +++ b/examples/16_app_settings.md @@ -0,0 +1,52 @@ +You can use `AppSettings` to change the application level behavior of clap. `app.setting()` function +takes `AppSettings` enum as argument. You can learn more about AppSettings in the +documentation, which also has examples on each setting. + +This example will only show usage of one AppSettings setting. See documentation for more +information. + +Something is required: +```bash +$ 16_app_settings +? failed +error: The following required arguments were not provided: + + +USAGE: + 16_app_settings[EXE] + 16_app_settings[EXE] + +For more information try --help +``` + +It can either be an argument: +```bash +$ 16_app_settings input.txt +The input file is: input.txt +``` + +Or the `test` subcommand: +```bash +$ 16_app_settings test +The 'test' subcommand was used +``` + +And see what this looks like in the help: +```bash +$ 16_app_settings --help +myapp + +USAGE: + 16_app_settings[EXE] + 16_app_settings[EXE] + +ARGS: + input file to use + +OPTIONS: + -h, --help Print help information + +SUBCOMMANDS: + help Print this message or the help of the given subcommand(s) + test does some testing +``` diff --git a/examples/16_app_settings.rs b/examples/16_app_settings.rs index 905a8830..9a85e845 100644 --- a/examples/16_app_settings.rs +++ b/examples/16_app_settings.rs @@ -1,13 +1,6 @@ use clap::{arg, App, AppSettings}; fn main() { - // You can use AppSettings to change the application level behavior of clap. .setting() function - // of App struct takes AppSettings enum as argument. You can learn more about AppSettings in the - // documentation, which also has examples on each setting. - // - // This example will only show usage of one AppSettings setting. See documentation for more - // information. - let matches = App::new("myapp") .setting(AppSettings::SubcommandsNegateReqs) // Negates requirement of parent command. diff --git a/examples/21_aliases.md b/examples/21_aliases.md new file mode 100644 index 00000000..d5ec7db4 --- /dev/null +++ b/examples/21_aliases.md @@ -0,0 +1,20 @@ +Subcommands can also have aliases + +``` +$ 21_aliases --help +MyApp + +USAGE: + 21_aliases[EXE] [SUBCOMMAND] + +OPTIONS: + -h, --help Print help information + +SUBCOMMANDS: + help Print this message or the help of the given subcommand(s) + ls Adds files to myapp +$ 21_aliases ls . +'myapp add' was used, input is: . +$ 21_aliases dir . +'myapp add' was used, input is: . +``` diff --git a/examples/22_stop_parsing_with_--.md b/examples/22_stop_parsing_with_--.md new file mode 100644 index 00000000..c8f282d7 --- /dev/null +++ b/examples/22_stop_parsing_with_--.md @@ -0,0 +1,54 @@ +You can use `--` to escape further arguments. + +Let's see what this looks like in the help: +```bash +$ 22_stop_parsing_with_-- --help +myprog + +USAGE: + 22_stop_parsing_with_--[EXE] [OPTIONS] [-- ...] + +ARGS: + ... + +OPTIONS: + -f + -h, --help Print help information + -p +``` + +Here is a baseline without any arguments: +```bash +$ 22_stop_parsing_with_-- +-f used: false +-p's value: None +'slops' values: None +``` + +Notice that we can't pass positional arguments before `--`: +```bash +$ 22_stop_parsing_with_-- foo bar +? failed +error: Found argument 'foo' which wasn't expected, or isn't valid in this context + +USAGE: + 22_stop_parsing_with_--[EXE] [OPTIONS] [-- ...] + +For more information try --help +``` + +But you can after: +```bash +$ 22_stop_parsing_with_-- -f -p=bob -- sloppy slop slop +-f used: true +-p's value: Some("bob") +'slops' values: Some(["sloppy", "slop", "slop"]) +``` + +As mentioned, the parser will directly pass everything through: +```bash +$ 22_stop_parsing_with_-- -- -f -p=bob sloppy slop slop +-f used: false +-p's value: None +'slops' values: Some(["-f", "-p=bob", "sloppy", "slop", "slop"]) +``` diff --git a/examples/23_flag_subcommands_pacman.md b/examples/23_flag_subcommands_pacman.md new file mode 100644 index 00000000..1a76b803 --- /dev/null +++ b/examples/23_flag_subcommands_pacman.md @@ -0,0 +1,33 @@ +This feature allows users of the app to pass subcommands in the fashion of short or long flags. +You may be familiar with it if you ever used [`pacman`](https://wiki.archlinux.org/index.php/pacman). +Some made up examples of what flag subcommands are: + +Here, `-S` is a short flag subcommand: +```bash +$ 23_flag_subcommands_pacman -S package +Installing package... +``` + +Here `--sync` is a long flag subcommand: +```bash +$ 23_flag_subcommands_pacman --sync package +Installing package... +``` + +Now the short flag subcommand (`-S`) with a long flag: +```bash +$ 23_flag_subcommands_pacman -S --search name +Searching for name... +``` + +And the various forms of short flags that work: +``` +$ 23_flag_subcommands_pacman -S -s name +Searching for name... +$ 23_flag_subcommands_pacman -Ss name +Searching for name... +``` +*(users can "stack" short subcommands with short flags or with other short flag subcommands)* + +**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/examples/23_flag_subcommands_pacman.rs b/examples/23_flag_subcommands_pacman.rs index db238b5d..5b42f0d5 100644 --- a/examples/23_flag_subcommands_pacman.rs +++ b/examples/23_flag_subcommands_pacman.rs @@ -1,23 +1,3 @@ -// This feature allows users of the app to pass subcommands in the fashion of short or long flags. -// You may be familiar with it if you ever used [`pacman`](https://wiki.archlinux.org/index.php/pacman). -// Some made up examples of what flag subcommands are: -// -// ```shell -// $ pacman -S -// ^--- short flag subcommand. -// $ pacman --sync -// ^--- long flag subcommand. -// $ pacman -Ss -// ^--- short flag subcommand followed by a short flag -// (users can "stack" short subcommands with short flags or with other short flag subcommands) -// $ pacman -S -s -// ^--- same as above -// $ pacman -S --sync -// ^--- short flag subcommand followed by a long flag -// ``` -// 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. - use clap::{App, AppSettings, Arg}; fn main() { diff --git a/examples/24a_multicall_busybox.md b/examples/24a_multicall_busybox.md new file mode 100644 index 00000000..7291ff26 --- /dev/null +++ b/examples/24a_multicall_busybox.md @@ -0,0 +1,40 @@ +Example of a busybox-style multicall program + +See the documentation for clap::AppSettings::Multicall for rationale. + +This example omits every command except true and false, +which are the most trivial to implement, +```bash +$ busybox true +? 0 +$ busybox false +? 1 +``` +*Note: without the links setup, we can't demonostrate 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. +```bash +$ busybox --install +? failed +... +``` + +Though users must pass something: +```bash +$ busybox +? failed +busybox + +USAGE: + busybox[EXE] [OPTIONS] [SUBCOMMAND] + +OPTIONS: + -h, --help Print help information + --install Install hardlinks for all subcommands in path + +SUBCOMMANDS: + false does nothing unsuccessfully + help Print this message or the help of the given subcommand(s) + true does nothing successfully +``` diff --git a/examples/24a_multicall_busybox.rs b/examples/24a_multicall_busybox.rs index ce7e3c44..e5302098 100644 --- a/examples/24a_multicall_busybox.rs +++ b/examples/24a_multicall_busybox.rs @@ -1,12 +1,3 @@ -//! Example of a `busybox-style` multicall program -//! -//! See the documentation for clap::AppSettings::Multicall for rationale. -//! -//! This example omits every command except true and false, -//! which are the most trivial to implement, -//! 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. - use std::process::exit; use clap::{App, AppSettings, Arg}; diff --git a/examples/24b_multicall_hostname.md b/examples/24b_multicall_hostname.md new file mode 100644 index 00000000..7c5d4df3 --- /dev/null +++ b/examples/24b_multicall_hostname.md @@ -0,0 +1,31 @@ +Example of a `hostname-style` multicall program + +See the documentation for clap::AppSettings::Multicall for rationale. + +This example omits the implementation of displaying address config + +```bash +$ hostname hostname +www +$ hostname dnsdomainname +example.com +``` +*Note: without the links setup, we can't demonostrate the multicall behavior* + +Though users must pass something: +```bash +$ hostname +? failed +hostname + +USAGE: + hostname[EXE] [SUBCOMMAND] + +OPTIONS: + -h, --help Print help information + +SUBCOMMANDS: + dnsdomainname show domain name part of FQDN + help Print this message or the help of the given subcommand(s) + hostname show hostname part of FQDN +``` diff --git a/examples/24b_multicall_hostname.rs b/examples/24b_multicall_hostname.rs index 2bff8b46..3b5219b3 100644 --- a/examples/24b_multicall_hostname.rs +++ b/examples/24b_multicall_hostname.rs @@ -1,9 +1,3 @@ -//! Example of a `hostname-style` multicall program -//! -//! See the documentation for clap::AppSettings::Multicall for rationale. -//! -//! This example omits the implementation of displaying address config - use clap::{App, AppSettings}; fn main() { diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..dcdd32f5 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,8 @@ +# `clap` Examples + +Each example is accompanying by a markdown file demonstrating its features. + +## Contributing + +Each example must have a markdown file. They are verified using +[trycmd](https://docs.rs/trycmd). diff --git a/tests/examples.rs b/tests/examples.rs index 8f2f4394..d4373faa 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -1,61 +1,13 @@ #![cfg(not(tarpaulin))] -use std::ffi::OsStr; -use std::fs; -use std::process::{Command, Output}; - -fn run_example>(name: S, args: &[&str]) -> Output { - let mut all_args = vec!["run", "--example", name.as_ref(), "--"]; - all_args.extend_from_slice(args); - - Command::new(env!("CARGO")) - .args(all_args) - .output() - .expect("failed to run example") -} - #[test] -fn examples_are_functional() { - let example_paths = fs::read_dir("examples") - .expect("couldn't read examples directory") - .map(|result| result.expect("couldn't get directory entry").path()) - .filter(|path| path.is_file() && path.extension().and_then(OsStr::to_str) == Some("rs")); - - let mut example_count = 0; - for path in example_paths { - example_count += 1; - - let example_name = match path.file_name().and_then(OsStr::to_str) { - Some("24a_multicall_busybox.rs") => { - #[cfg(not(feature = "unstable-multicall"))] - continue; - #[allow(unreachable_code)] - "busybox" - } - Some("24b_multicall_hostname.rs") => { - #[cfg(not(feature = "unstable-multicall"))] - continue; - #[allow(unreachable_code)] - "hostname" - } - _ => path - .file_stem() - .and_then(OsStr::to_str) - .expect("unable to determine example name"), - }; - - let help_output = run_example(example_name, &["--help"]); - assert!( - help_output.status.success(), - "{} --help exited with nonzero: {}", - example_name, - String::from_utf8_lossy(&help_output.stderr), - ); - assert!( - !help_output.stdout.is_empty(), - "{} --help had no output", - example_name, - ); +fn example_tests() { + let t = trycmd::TestCases::new(); + t.register_bins(trycmd::cargo::compile_examples([]).unwrap()); + t.case("examples/*.md"); + #[cfg(not(feature = "unstable-multicall"))] + { + t.skip("examples/24a_multicall_busybox.md"); + t.skip("examples/24b_multicall_hostname.md"); } - assert!(example_count > 0); }