├── clap.png
├── index.html
├── clap-tests
├── .gitignore
├── Cargo.toml
├── Makefile
├── src
│ └── main.rs
└── run_tests.py
├── src
├── args
│ ├── argbuilder
│ │ ├── mod.rs
│ │ ├── flag.rs
│ │ ├── positional.rs
│ │ └── option.rs
│ ├── matchedarg.rs
│ ├── mod.rs
│ ├── subcommand.rs
│ ├── argmatches.rs
│ └── group.rs
├── app
│ ├── mod.rs
│ ├── suggestions.rs
│ ├── settings.rs
│ └── errors.rs
├── lib.rs
├── fmt.rs
└── usageparser.rs
├── tests
├── yaml.rs
├── unique_args.rs
├── print_help.rs
├── app_settings.rs
├── conflicts.rs
├── flags.rs
├── multiple_occurrences.rs
├── opts.rs
├── app.yml
├── positionals.rs
├── require.rs
└── posix_compatible.rs
├── .gitignore
├── .clog.toml
├── benches
├── 01_default.rs
├── 02_simple.rs
└── 03_complex.rs
├── .travis.yml
├── Makefile
├── CONTRIBUTORS.md
├── examples
├── 10_default_values.rs
├── 09_auto_version.rs
├── 02_apps.rs
├── 11_only_specific_values.rs
├── 17_yaml.rs
├── 13b_enum_values_manual.rs
├── 15_custom_validator.rs
├── 16_app_settings.rs
├── 12_typed_values.rs
├── 13a_enum_values_automatic.rs
├── 04_using_matches.rs
├── 08_subcommands.rs
├── 18_builder_macro.rs
├── 05_flag_args.rs
├── 17_yaml.yml
├── 06_positional_args.rs
├── 01c_quick_example.rs
├── 01a_quick_example.rs
├── 07_option_args.rs
├── 14_groups.rs
├── 01b_quick_example.rs
└── 03_args.rs
├── LICENSE-MIT
├── Cargo.toml
└── CONTRIBUTING.md
/clap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nelsonjchen/clap-rs/master/clap.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/clap-tests/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled files
2 | *.o
3 | *.so
4 | *.rlib
5 | *.dll
6 |
7 | # Executables
8 | *.exe
9 |
10 | # Generated by Cargo
11 | /target/
12 |
--------------------------------------------------------------------------------
/clap-tests/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 |
3 | name = "claptests"
4 | version = "0.0.1"
5 | authors = ["Kevin K. "]
6 |
7 | [dependencies.clap]
8 | path = ".."
9 |
--------------------------------------------------------------------------------
/src/args/argbuilder/mod.rs:
--------------------------------------------------------------------------------
1 | pub use self::flag::FlagBuilder;
2 | pub use self::option::OptBuilder;
3 | pub use self::positional::PosBuilder;
4 |
5 | mod flag;
6 | mod positional;
7 | mod option;
8 |
--------------------------------------------------------------------------------
/src/app/mod.rs:
--------------------------------------------------------------------------------
1 | mod settings;
2 | mod app;
3 | mod suggestions;
4 | mod errors;
5 |
6 | pub use self::settings::AppSettings;
7 | pub use self::app::App;
8 | pub use self::errors::{ClapError, ClapErrorType};
9 |
--------------------------------------------------------------------------------
/tests/yaml.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | extern crate clap;
3 |
4 | use clap::App;
5 |
6 | #[test]
7 | #[cfg(feature="yaml")]
8 | fn create_app_from_yaml() {
9 | let yml = load_yaml!("app.yml");
10 | App::from_yaml(yml);
11 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled files
2 | *.o
3 | *.so
4 | *.rlib
5 | *.dll
6 |
7 | # Executables
8 | *.exe
9 |
10 | # Generated by Cargo
11 | /target/
12 |
13 | # Cargo files
14 | Cargo.lock
15 |
16 | # Temp files
17 | .*~
18 |
19 | # Backup files
20 | *.bak
21 | *.bk
22 |
--------------------------------------------------------------------------------
/.clog.toml:
--------------------------------------------------------------------------------
1 | [clog]
2 | repository = "https://github.com/kbknapp/clap-rs"
3 | outfile = "CHANGELOG.md"
4 | from-latest-tag = true
5 |
6 | [sections]
7 | Performance = ["perf"]
8 | Improvements = ["impr", "im", "imp"]
9 | Documentation = ["docs"]
10 | Deprecations = ["depr"]
11 | Examples = ["examples"]
--------------------------------------------------------------------------------
/src/args/matchedarg.rs:
--------------------------------------------------------------------------------
1 | use std::collections::BTreeMap;
2 |
3 | #[doc(hidden)]
4 | pub struct MatchedArg {
5 | // #[doc(hidden)]
6 | // pub name: String,
7 | #[doc(hidden)]
8 | pub occurrences: u8,
9 | #[doc(hidden)]
10 | // Consider VecMap once stablized
11 | pub values: Option>,
12 | }
13 |
--------------------------------------------------------------------------------
/clap-tests/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: build test clean
2 |
3 | build:
4 | @# It may be that this project was never built, and no Cargo.lock exists.
5 | @# Thus it may be ignored
6 | cargo update 2>/dev/null || :
7 | cargo build --release
8 |
9 | test:
10 | $(MAKE) build || ($(MAKE) clean && false)
11 | ./run_tests.py
12 |
13 | clean:
14 | cargo clean
15 |
--------------------------------------------------------------------------------
/benches/01_default.rs:
--------------------------------------------------------------------------------
1 | #![feature(test)]
2 |
3 | extern crate clap;
4 | extern crate test;
5 |
6 | use clap::App;
7 |
8 | use test::Bencher;
9 |
10 | #[bench]
11 | fn build_app(b: &mut Bencher) {
12 | b.iter(|| App::new("claptests"));
13 | }
14 |
15 | #[bench]
16 | fn parse_clean(b: &mut Bencher) {
17 | b.iter(|| App::new("claptests").get_matches_from(vec![""]));
18 | }
19 |
--------------------------------------------------------------------------------
/src/args/mod.rs:
--------------------------------------------------------------------------------
1 | pub use self::arg::Arg;
2 | pub use self::argmatches::ArgMatches;
3 | pub use self::subcommand::SubCommand;
4 | pub use self::argbuilder::{FlagBuilder, OptBuilder, PosBuilder};
5 | pub use self::matchedarg::MatchedArg;
6 | pub use self::group::ArgGroup;
7 |
8 | mod arg;
9 | mod argmatches;
10 | mod subcommand;
11 | mod argbuilder;
12 | mod matchedarg;
13 | mod group;
14 |
--------------------------------------------------------------------------------
/tests/unique_args.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg};
4 |
5 |
6 | #[test]
7 | #[should_panic]
8 | fn unique_arg_names() {
9 | App::new("some").args(vec![
10 | Arg::with_name("arg").short("a"),
11 | Arg::with_name("arg").short("b")
12 | ]);
13 | }
14 |
15 | #[test]
16 | #[should_panic]
17 | fn unique_arg_shorts() {
18 | App::new("some").args(vec![
19 | Arg::with_name("arg1").short("a"),
20 | Arg::with_name("arg2").short("a")
21 | ]);
22 | }
23 |
24 | #[test]
25 | #[should_panic]
26 | fn unique_arg_longs() {
27 | App::new("some").args(vec![
28 | Arg::with_name("arg1").long("long"),
29 | Arg::with_name("arg2").long("long")
30 | ]);
31 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: rust
2 | sudo: required
3 | rust:
4 | - nightly
5 | - beta
6 | - stable
7 | before_script:
8 | - |
9 | pip install 'travis-cargo<0.2' --user &&
10 | export PATH=$HOME/.local/bin:$PATH
11 | script:
12 | - |
13 | cargo build --features yaml &&
14 | cargo test --features yaml &&
15 | make -C clap-tests test &&
16 | travis-cargo --only stable doc
17 | after_success:
18 | - |
19 | travis-cargo --only stable doc-upload &&
20 | travis-cargo --only stable coveralls -- --features yaml
21 | env:
22 | global:
23 | secure: JLBlgHY6OEmhJ8woewNJHmuBokTNUv7/WvLkJGV8xk0t6bXBwSU0jNloXwlH7FiQTc4TccX0PumPDD4MrMgxIAVFPmmmlQOCmdpYP4tqZJ8xo189E5zk8lKF5OyaVYCs5SMmFC3cxCsKjfwGIexNu3ck5Uhwe9jI0tqgkgM3URA=
24 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | THIS_MAKEFILE_PATH:=$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
2 | THIS_DIR:=$(shell cd $(dir $(THIS_MAKEFILE_PATH));pwd)
3 |
4 | test:
5 | cargo test
6 |
7 | build:
8 | cargo build
9 |
10 | update-readme:
11 | cd "$(THIS_DIR)"
12 | cp src/lib.rs code.bak
13 | cat README.md | sed -e 's/^/\/\/! /g' > readme.bak
14 | sed -i '/\/\/!/d' src/lib.rs
15 | sed -i '/\/\/ DOCS/r readme.bak' src/lib.rs
16 | cat src/lib.rs | sed -e 's/`rust/`ignore/g' > src/lib.rs.tmp
17 | cat src/lib.rs.tmp | sed -e 's/`toml/`ignore/g' > src/lib.rs
18 | cat src/lib.rs | sed -e 's/\`sh/`ignore/g' > src/lib.rs.tmp
19 | make clean || (make clean && false)
20 |
21 | clean:
22 | cd "$(THIS_DIR)"
23 | mv code.bak src/lib.rs || true
24 | rm src/lib.rs.t* || true
25 | rm *.bak || true
26 |
--------------------------------------------------------------------------------
/CONTRIBUTORS.md:
--------------------------------------------------------------------------------
1 | The following is a list of contributors to the [clap](https://github.com/kbknapp/clap-rs) project, in alphabetical order:
2 |
3 | * [Alexander Kuvaev](https://github.com/Vinatorul) <>
4 | * [Ivan Dmitrievsky](https://github.com/idmit) <>
5 | * [J/A](https://github.com/archer884)
6 | * [Jacob Helwig](https://github.com/jhelwig) <>
7 | * [James McGlashan](https://github.com/james-darkfox)
8 | * [Kevin K.](https://github.com/kbknapp) <>
9 | * [Markus Unterwaditzer](https://github.com/untitaker) <>
10 | * [Sebastian Thiel](https://github.com/Byron) <>
11 | * [Severen Redwood](https://github.com/SShrike) <>
12 | * [SungRim Huh](https://github.com/sru) <>
13 | * [Tshepang Lekhonkhobe](https://github.com/tshepang) <>
14 | * [Vincent Prouillet](https://github.com/Keats)
15 |
--------------------------------------------------------------------------------
/examples/10_default_values.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg};
4 |
5 | fn main() {
6 | // You can get a "default value" like feature by using Option's .unwrap_or() method
7 | //
8 | // Let's assume you have -c argument to allow users to specify a configuration file
9 | // but you also want to support a default file, if none is specified.
10 | let matches = App::new("myapp").about("does awesome things")
11 | .arg(Arg::with_name("CONFIG")
12 | .help("The config file to use (default is \"config.json\")")
13 | .short("c")
14 | .takes_value(true))
15 | .get_matches();
16 |
17 | let config_file = matches.value_of("CONFIG").unwrap_or("config.json");
18 |
19 | // If the user passed in a -c we'll see that value, if not we'll see 'config.json'
20 | println!("The config file is: {}", config_file);
21 | }
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![crate_type= "lib"]
2 | #![cfg_attr(feature = "nightly", feature(plugin))]
3 | //#![cfg_attr(feature = "lints", plugin(clippy))]
4 | //#![cfg_attr(feature = "lints", allow(option_unwrap_used))]
5 | //#![cfg_attr(feature = "lints", allow(explicit_iter_loop))]
6 | //#![cfg_attr(feature = "lints", deny(warnings))]
7 | // Fix until clippy on crates.io is updated to include needless_lifetimes lint
8 | //#![cfg_attr(feature = "lints", allow(unknown_lints))]
9 |
10 | // DOCS
11 |
12 | #[cfg(feature = "suggestions")]
13 | extern crate strsim;
14 | #[cfg(feature = "color")]
15 | extern crate ansi_term;
16 | #[cfg(feature = "yaml")]
17 | extern crate yaml_rust;
18 |
19 | #[cfg(feature = "yaml")]
20 | pub use yaml_rust::YamlLoader;
21 | pub use args::{Arg, SubCommand, ArgMatches, ArgGroup};
22 | pub use app::{App, AppSettings, ClapError, ClapErrorType};
23 | pub use fmt::Format;
24 |
25 | #[macro_use]
26 | mod macros;
27 | mod app;
28 | mod args;
29 | mod usageparser;
30 | mod fmt;
31 |
32 | #[cfg(test)]
33 | mod tests;
34 |
--------------------------------------------------------------------------------
/tests/print_help.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::App;
4 |
5 | #[test]
6 | fn print_app_help() {
7 | let mut app = App::new("test")
8 | .author("Kevin K.")
9 | .about("tests stuff")
10 | .version("1.3")
11 | .args_from_usage("-f, --flag 'some flag'
12 | --option [opt] 'some option'");
13 | // We call a get_matches method to cause --help and --version to be built
14 | let _ = app.get_matches_from_safe_borrow(vec![""]);
15 |
16 | // Now we check the output of print_help()
17 | let mut help = vec![];
18 | app.write_help(&mut help).ok().expect("failed to print help");
19 | assert_eq!(&*String::from_utf8_lossy(&*help), &*String::from("test 1.3\n\
20 | Kevin K.
21 | tests stuff
22 |
23 | USAGE:
24 | \ttest [FLAGS] [OPTIONS]
25 |
26 | FLAGS:
27 | -f, --flag some flag
28 | -h, --help Prints help information
29 | -V, --version Prints version information
30 |
31 | OPTIONS:
32 | --option some option\n"));
33 | }
34 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Kevin B. Knapp
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 |
3 | name = "clap"
4 | version = "1.4.0"
5 | authors = ["Kevin K. "]
6 | exclude = ["examples/*", "clap-tests/*", "tests/*", "benches/*", "clap.png"]
7 | description = "A simple to use, efficient, and full featured Command Line Argument Parser"
8 | repository = "https://github.com/kbknapp/clap-rs.git"
9 | documentation = "http://kbknapp.github.io/clap-rs"
10 | readme = "README.md"
11 | license = "MIT"
12 | keywords = ["argument", "command", "arg", "parser", "parse"]
13 |
14 | [dependencies.strsim]
15 | version = "~0.4.0"
16 | optional = true
17 |
18 | [dependencies.ansi_term]
19 | version = "~0.6.3"
20 | optional = true
21 |
22 | [dependencies.yaml-rust]
23 | version = "~0.2.1"
24 | optional = true
25 |
26 | #[dependencies.clippy]
27 | #version = "~0.0.12"
28 | #optional = true
29 |
30 | [features]
31 | default=["suggestions", "color"]
32 | suggestions=["strsim"]
33 | color = ["ansi_term"]
34 | yaml = ["yaml-rust"]
35 | #lints = ["clippy", "nightly"]
36 |
37 | # for building with nightly and unstable features
38 | nightly = []
39 |
40 | # for building with travis-cargo
41 | #unstable = ["lints", "nightly"]
42 | unstable = ["nightly"]
43 |
44 | # for building with debug messages
45 | debug = []
46 |
47 |
--------------------------------------------------------------------------------
/examples/09_auto_version.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | extern crate clap;
3 |
4 | use clap::App;
5 |
6 | fn main() {
7 | // You can have clap pull the application version directly from your Cargo.toml starting with
8 | // clap v0.4.14 on crates.io (or master#a81f915 on github). Using Rust's env! macro like this:
9 | //
10 | // let version = format!("{}.{}.{}{}",
11 | // env!("CARGO_PKG_VERSION_MAJOR"),
12 | // env!("CARGO_PKG_VERSION_MINOR"),
13 | // env!("CARGO_PKG_VERSION_PATCH"),
14 | // option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""));
15 | //
16 | // Starting from v0.6.6 on crates.io you can also use the crate_version!() macro instead of
17 | // manually using the env!() macros. Under the hood, the macro uses this exact method to get
18 | // the version.
19 | //
20 | // Thanks to https://github.com/jhelwig for pointing this out
21 | App::new("myapp")
22 | .about("does awesome things")
23 | // use crate_version! to pull the version number
24 | .version(&crate_version!()[..])
25 | .get_matches();
26 |
27 | // running the this app with the -V or --version will display whatever version is in your
28 | // Cargo.toml, the default being: myapp 0.0.1
29 | }
30 |
--------------------------------------------------------------------------------
/benches/02_simple.rs:
--------------------------------------------------------------------------------
1 | #![feature(test)]
2 |
3 | extern crate clap;
4 | extern crate test;
5 |
6 | use clap::App;
7 |
8 | use test::Bencher;
9 |
10 | macro_rules! create_app {
11 | () => ({
12 | App::new("claptests")
13 | .version("0.1")
14 | .about("tests clap library")
15 | .author("Kevin K. ")
16 | .args_from_usage("-f --flag 'tests flags'
17 | -o --option=[opt] 'tests options'
18 | [positional] 'tests positional'")
19 | })
20 | }
21 |
22 | #[bench]
23 | fn build_app(b: &mut Bencher) {
24 |
25 | b.iter(|| create_app!());
26 | }
27 |
28 | #[bench]
29 | fn parse_clean(b: &mut Bencher) {
30 | b.iter(|| create_app!().get_matches_from(vec![""]));
31 | }
32 |
33 | #[bench]
34 | fn parse_flag(b: &mut Bencher) {
35 | b.iter(|| create_app!().get_matches_from(vec!["", "-f"]));
36 | }
37 |
38 | #[bench]
39 | fn parse_option(b: &mut Bencher) {
40 | b.iter(|| create_app!().get_matches_from(vec!["", "-o", "option1"]));
41 | }
42 |
43 | #[bench]
44 | fn parse_positional(b: &mut Bencher) {
45 | b.iter(|| create_app!().get_matches_from(vec!["", "arg1"]));
46 | }
47 |
48 | #[bench]
49 | fn parse_complex(b: &mut Bencher) {
50 | b.iter(|| create_app!().get_matches_from(vec!["", "-o", "option1", "-f", "arg1"]));
51 | }
52 |
--------------------------------------------------------------------------------
/examples/02_apps.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App};
4 |
5 | fn main() {
6 | // Apps describe the top level application
7 | //
8 | // You create an App and set various options on that App using the "builder pattern"
9 | //
10 | // The options (version(), author(), about()) aren't mandatory, but recommended. There is
11 | // another option, usage(), which is an exception to the rule. This should only be used when
12 | // the default usage string automatically generated by clap doesn't suffice.
13 | //
14 | // You also set all the valid arguments your App should accept via the arg(), args(), arg_from_usage()
15 | // and args_from_usage() (as well as subcommands via the subcommand() and subcommands() methods) which
16 | // will be covered later.
17 | //
18 | // Once all options have been set, call .get_matches() in order to start the parsing and find all valid
19 | // command line arguments that supplied by the user at runtime. The name given to new() will be displayed
20 | // when the version or help flags are used.
21 | App::new("MyApp")
22 | .version("1.0")
23 | .author("Kevin K. ")
24 | .about("Does awesome things")
25 | .get_matches();
26 |
27 | // This example doesn't do much, but it *does* give automatic -h, --help, -V, and --version functionality ;)
28 |
29 | // Continued program logic goes here...
30 | }
31 |
--------------------------------------------------------------------------------
/examples/11_only_specific_values.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg};
4 |
5 | fn main() {
6 | // If you have arguments of specific values you want to test for, you can use the
7 | // .possible_values() method of Arg
8 | //
9 | // This allows you specify the valid values for that argument. If the user does not use one of
10 | // those specific values, they will receive a graceful exit with error message informing them
11 | // of the mistake, and what the possible valid values are
12 | //
13 | // For this example, assume you want one positional argument of either "fast" or "slow"
14 | // i.e. the only possible ways to run the program are "myprog fast" or "myprog slow"
15 | let mode_vals = ["fast", "slow"];
16 | let matches = App::new("myapp").about("does awesome things")
17 | .arg(Arg::with_name("MODE")
18 | .help("What mode to run the program in")
19 | .index(1)
20 | .possible_values(&mode_vals)
21 | .required(true))
22 | .get_matches();
23 |
24 | // Note, it's safe to call unwrap() because the arg is required
25 | match matches.value_of("MODE").unwrap() {
26 | "fast" => {
27 | // Do fast things...
28 | },
29 | "slow" => {
30 | // Do slow things...
31 | },
32 | _ => unreachable!()
33 | }
34 | }
--------------------------------------------------------------------------------
/examples/17_yaml.rs:
--------------------------------------------------------------------------------
1 | // In order to use YAML to define your CLI you must compile clap with the "yaml" feature becasue
2 | // it's **not** included by default.
3 | //
4 | // In order to do this, ensure your Cargo.toml looks like one of the following:
5 | //
6 | // [dependencies.clap]
7 | // features = ["yaml"]
8 | //
9 | // __OR__
10 | //
11 | // [dependencies]
12 | // clap = { features = ["yaml"] }
13 |
14 |
15 | // Using yaml requires calling a clap macro `load_yaml!()` so we must use the '#[macro_use]'
16 | // directive
17 | #[macro_use]
18 | extern crate clap;
19 |
20 | use clap::App;
21 |
22 | fn main() {
23 | // To load a yaml file containing our CLI definition such as the example '17_yaml.yml' we can
24 | // use the convenience macro which loads the file at compile relative to the current file
25 | // similiar to how modules are found.
26 | //
27 | // Then we pass that yaml object to App to build the CLI.
28 | //
29 | // Finally we call get_matches() to start the parsing process. We use the matches just as we
30 | // normally would
31 | let yml = load_yaml!("17_yaml.yml");
32 | let m = App::from_yaml(yml).get_matches();
33 |
34 | // Because the example 17_yaml.yml is rather large we'll just look a single arg so you can
35 | // see that it works...
36 | if let Some(mode) = m.value_of("mode") {
37 | match mode {
38 | "fast" => println!("We're really going now!"),
39 | "slow" => println!("Awwww, too slow :("),
40 | _ => unreachable!()
41 | }
42 | } else {
43 | println!("--mode wasn't used...");
44 | }
45 | }
--------------------------------------------------------------------------------
/examples/13b_enum_values_manual.rs:
--------------------------------------------------------------------------------
1 | // If you require more complex configuration than simple_enum! provides, you can implement the
2 | // trait manually, as in the following example.
3 | //
4 | // In the following example we will create an enum with 4 values, assign a positional argument
5 | // that accepts only one of those values, and use clap to parse the argument.
6 | //
7 | // Start with bringing the trait into scope.
8 | use std::str::FromStr;
9 |
10 | // Add clap like normal
11 | #[macro_use]
12 | extern crate clap;
13 |
14 | use clap::{App, Arg};
15 |
16 | // Define your enum
17 | enum Vals {
18 | Foo,
19 | Bar,
20 | Baz,
21 | Qux
22 | }
23 |
24 | // Implement the trait
25 | impl FromStr for Vals {
26 | type Err = &'static str;
27 |
28 | fn from_str(s: &str) -> Result {
29 | match s {
30 | "Foo" => Ok(Vals::Foo),
31 | "Bar" => Ok(Vals::Bar),
32 | "Baz" => Ok(Vals::Baz),
33 | "Qux" => Ok(Vals::Qux),
34 | _ => Err("no match")
35 | }
36 | }
37 | }
38 |
39 | fn main() {
40 | // Create the application like normal
41 | let enum_vals = ["Foo", "Bar", "Baz", "Qux"];
42 | let m = App::new("myapp")
43 | // Use a single positional argument that is required
44 | .arg(Arg::from_usage(" 'The type to use'")
45 | // Define the list of possible values
46 | .possible_values(&enum_vals))
47 | .get_matches();
48 |
49 | let t = value_t_or_exit!(m.value_of("type"), Vals);
50 |
51 | // Now we can use our enum like normal.
52 | match t {
53 | Vals::Foo => println!("Found a Foo"),
54 | Vals::Bar => println!("Found a Bar"),
55 | Vals::Baz => println!("Found a Baz"),
56 | Vals::Qux => println!("Found a Qux")
57 | }
58 | }
--------------------------------------------------------------------------------
/examples/15_custom_validator.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg};
4 |
5 | fn main() {
6 | // You can define a function (or a closure) to use as a validator to argument values. The
7 | // function must accept a String and return Result<(), String> where Err(String) is the message
8 | // displayed to the user.
9 |
10 | let matches = App::new("myapp")
11 | // Application logic goes here...
12 | .arg(Arg::with_name("input")
13 | .help("the input file to use")
14 | .index(1)
15 | .required(true)
16 |
17 | .validator(|val| {
18 | // val is the argument value passed in by the user
19 | // val has type of String.
20 |
21 | if val.ends_with(".png") {
22 | Ok(())
23 | } else {
24 | // clap automatically adds "error: " to the beginning
25 | // of the message.
26 | Err(String::from("the file format must be png."))
27 | }
28 |
29 | // Of course, you can do more complicated validation as
30 | // well, but for the simplicity, this example only checks
31 | // if the value passed in ends with ".png" or not.
32 | }))
33 | .get_matches();
34 |
35 | // Here we can call .unwrap() because the argument is required.
36 | println!("The .PNG file is: {}", matches.value_of("input").unwrap());
37 | }
38 |
--------------------------------------------------------------------------------
/tests/app_settings.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg, SubCommand, AppSettings, ClapErrorType};
4 |
5 | #[test]
6 | fn sub_command_negate_requred() {
7 | App::new("sub_command_negate")
8 | .setting(AppSettings::SubcommandsNegateReqs)
9 | .arg(Arg::with_name("test")
10 | .required(true)
11 | .index(1))
12 | .subcommand(SubCommand::with_name("sub1"))
13 | .get_matches_from(vec!["", "sub1"]);
14 | }
15 |
16 | #[test]
17 | fn sub_command_negate_requred_2() {
18 | let result = App::new("sub_command_negate")
19 | .setting(AppSettings::SubcommandsNegateReqs)
20 | .arg(Arg::with_name("test")
21 | .required(true)
22 | .index(1))
23 | .subcommand(SubCommand::with_name("sub1"))
24 | .get_matches_from_safe(vec![""]);
25 | assert!(result.is_err());
26 | let err = result.err().unwrap();
27 | assert_eq!(err.error_type, ClapErrorType::MissingRequiredArgument);
28 | }
29 |
30 | #[test]
31 | fn app_settings_fromstr() {
32 | assert_eq!("subcommandsnegatereqs".parse::().ok().unwrap(), AppSettings::SubcommandsNegateReqs);
33 | assert_eq!("subcommandsrequired".parse::().ok().unwrap(), AppSettings::SubcommandRequired);
34 | assert_eq!("argrequiredelsehelp".parse::().ok().unwrap(), AppSettings::ArgRequiredElseHelp);
35 | assert_eq!("globalversion".parse::().ok().unwrap(), AppSettings::GlobalVersion);
36 | assert_eq!("versionlesssubcommands".parse::().ok().unwrap(), AppSettings::VersionlessSubcommands);
37 | assert_eq!("unifiedhelpmessage".parse::().ok().unwrap(), AppSettings::UnifiedHelpMessage);
38 | assert_eq!("waitonerror".parse::().ok().unwrap(), AppSettings::WaitOnError);
39 | assert_eq!("subcommandrequiredelsehelp".parse::().ok().unwrap(), AppSettings::SubcommandRequiredElseHelp);
40 | assert!("hahahaha".parse::().is_err());
41 | }
--------------------------------------------------------------------------------
/src/app/suggestions.rs:
--------------------------------------------------------------------------------
1 | #[cfg(feature = "suggestions")]
2 | use strsim;
3 |
4 | /// Produces a string from a given list of possible values which is similar to
5 | /// the passed in value `v` with a certain confidence.
6 | /// Thus in a list of possible values like ["foo", "bar"], the value "fop" will yield
7 | /// `Some("foo")`, whereas "blark" would yield `None`.
8 | #[cfg(feature = "suggestions")]
9 | #[cfg_attr(feature = "lints", allow(needless_lifetimes))]
10 | pub fn did_you_mean<'a, T, I>(v: &str,
11 | possible_values: I)
12 | -> Option<&'a str>
13 | where T: AsRef + 'a,
14 | I: IntoIterator-
15 | {
16 |
17 | let mut candidate: Option<(f64, &str)> = None;
18 | for pv in possible_values.into_iter() {
19 | let confidence = strsim::jaro_winkler(v, pv.as_ref());
20 | if confidence > 0.8 &&
21 | (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence)) {
22 | candidate = Some((confidence, pv.as_ref()));
23 | }
24 | }
25 | match candidate {
26 | None => None,
27 | Some((_, candidate)) => Some(candidate),
28 | }
29 | }
30 |
31 | #[cfg(not(feature = "suggestions"))]
32 | pub fn did_you_mean<'a, T, I>(_: &str,
33 | _: I)
34 | -> Option<&'a str>
35 | where T: AsRef + 'a,
36 | I: IntoIterator
-
37 | {
38 | None
39 | }
40 |
41 | /// A helper to determine message formatting
42 | pub enum DidYouMeanMessageStyle {
43 | /// Suggested value is a long flag
44 | LongFlag,
45 | /// Suggested value is one of various possible values
46 | EnumValue,
47 | }
48 |
49 | #[cfg(test)]
50 | mod test {
51 | use super::*;
52 |
53 | #[test]
54 | fn did_you_mean_possible_values() {
55 | let p_vals = ["test", "possible", "values"];
56 | assert_eq!(did_you_mean("tst", p_vals.iter()), Some("test"));
57 | assert!(did_you_mean("hahaahahah", p_vals.iter()).is_none());
58 |
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/examples/16_app_settings.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, AppSettings, SubCommand};
4 |
5 | fn main() {
6 | // You can use AppSettings to change the application level behavior of clap. .setting() function
7 | // of App struct takes AppSettings enum as argument. There is also .settings() function which
8 | // takes slice of AppSettings enum. You can learn more about AppSettings in the documentation,
9 | // which also has examples on each setting.
10 | //
11 | // This example will only show usage of one AppSettings setting. See documentation for more
12 | // information.
13 |
14 | let matches = App::new("myapp")
15 | .setting(AppSettings::SubcommandsNegateReqs)
16 | // Negates requirement of parent command.
17 |
18 | .arg_from_usage(" 'input file to use'")
19 | // Required positional argument called input. This
20 | // will be only required if subcommand is not present.
21 |
22 | .subcommand(SubCommand::with_name("test")
23 | .about("does some testing"))
24 | // if program is invoked with subcommand, you do not
25 | // need to specify the argument anymore due to
26 | // the AppSettings::SubcommandsNegateReqs setting.
27 |
28 | .get_matches();
29 |
30 | // Calling unwrap() on "input" would not be advised here, because although it's required,
31 | // if the user uses a subcommand, those requirements are no longer required. Hence, we should
32 | // use some sort of 'if let' construct
33 | if let Some(inp) = matches.value_of("input") {
34 | println!("The input file is: {}", inp);
35 | }
36 |
37 | match matches.subcommand() {
38 | ("test", _) => println!("The 'test' subcommand was used"),
39 | _ => unreachable!()
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/fmt.rs:
--------------------------------------------------------------------------------
1 | use std::fmt;
2 |
3 | #[cfg(all(feature = "color", not(target_os = "windows")))]
4 | use ansi_term::Colour::{Red, Green, Yellow};
5 | #[cfg(all(feature = "color", not(target_os = "windows")))]
6 | use ansi_term::ANSIString;
7 |
8 |
9 | pub enum Format {
10 | Error(T),
11 | Warning(T),
12 | Good(T),
13 | }
14 |
15 | #[cfg(all(feature = "color", not(target_os = "windows")))]
16 | impl> Format {
17 | fn format(&self) -> ANSIString {
18 | match *self {
19 | Format::Error(ref e) => Red.bold().paint(e.as_ref()),
20 | Format::Warning(ref e) => Yellow.paint(e.as_ref()),
21 | Format::Good(ref e) => Green.paint(e.as_ref()),
22 | }
23 | }
24 |
25 | }
26 |
27 | #[cfg(all(feature = "color", not(target_os = "windows")))]
28 | impl> fmt::Display for Format {
29 | fn fmt(&self,
30 | f: &mut fmt::Formatter) -> fmt::Result {
31 | write!(f, "{}", &self.format())
32 | }
33 | }
34 |
35 | #[cfg(any(not(feature = "color"), target_os = "windows"))]
36 | impl Format {
37 | fn format(&self) -> &T {
38 | match *self {
39 | Format::Error(ref e) => e,
40 | Format::Warning(ref e) => e,
41 | Format::Good(ref e) => e,
42 | }
43 | }
44 | }
45 |
46 | #[cfg(any(not(feature = "color"), target_os = "windows"))]
47 | impl fmt::Display for Format {
48 | fn fmt(&self,
49 | f: &mut fmt::Formatter) -> fmt::Result {
50 | write!(f, "{}", &self.format())
51 | }
52 | }
53 |
54 | #[cfg(test)]
55 | mod test {
56 | use super::Format;
57 | use ansi_term::Colour::{Red, Green, Yellow};
58 |
59 | #[test]
60 | fn colored_output() {
61 | let err = Format::Error("error");
62 | assert_eq!(&*format!("{}", err), &*format!("{}", Red.bold().paint("error")));
63 | let good = Format::Good("good");
64 | assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good")));
65 | let warn = Format::Warning("warn");
66 | assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn")));
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/args/subcommand.rs:
--------------------------------------------------------------------------------
1 | #[cfg(feature = "yaml")]
2 | use yaml_rust::Yaml;
3 |
4 | use App;
5 | use ArgMatches;
6 |
7 | /// The abstract representation of a command line subcommand used by the consumer of the library.
8 | ///
9 | ///
10 | /// This struct is used by the library consumer and describes all the valid options of the
11 | /// subcommand for their program. SubCommands are treated like "sub apps" and contain all the same
12 | /// possibilities (such as their own arguments and subcommands).
13 | ///
14 | /// # Example
15 | ///
16 | /// ```no_run
17 | /// # use clap::{App, Arg, SubCommand};
18 | /// # let matches = App::new("myprog")
19 | /// # .subcommand(
20 | /// SubCommand::with_name("conifg")
21 | /// .about("Used for configuration")
22 | /// .arg(Arg::with_name("config_file")
23 | /// .help("The configuration file to use")
24 | /// .index(1))
25 | /// # ).get_matches();
26 | pub struct SubCommand<'n, 'a> {
27 | #[doc(hidden)]
28 | pub name: &'n str,
29 | #[doc(hidden)]
30 | pub matches: ArgMatches<'n, 'a>,
31 | }
32 |
33 | impl<'n, 'a> SubCommand<'n, 'a> {
34 | /// Creates a new instance of a subcommand requiring a name. Will be displayed
35 | /// to the user when they print version or help and usage information.
36 | ///
37 | /// # Example
38 | ///
39 | /// ```no_run
40 | /// # use clap::{App, Arg, SubCommand};
41 | /// # let prog = App::new("myprog").subcommand(
42 | /// SubCommand::with_name("config")
43 | /// # ).get_matches();
44 | /// ```
45 | pub fn with_name<'au, 'v, 'ab, 'u, 'h, 'ar>(name: &'ar str) -> App<'au, 'v, 'ab, 'u, 'h, 'ar> {
46 | App::new(name)
47 | }
48 |
49 | /// Creates a new instance of a subcommand from a YAML (.yml) document
50 | ///
51 | /// # Example
52 | ///
53 | /// ```ignore
54 | /// # use clap::{App, Arg, SubCommand};
55 | /// let sc_yaml = load_yaml!("test_subcommand.yml");
56 | /// let sc = SubCommand::from_yaml(sc_yaml);
57 | /// ```
58 | #[cfg(feature = "yaml")]
59 | pub fn from_yaml<'y>(yaml: &'y Yaml) -> App<'y, 'y, 'y, 'y, 'y, 'y> {
60 | App::from_yaml(yaml)
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/tests/conflicts.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg, ClapErrorType, ArgGroup};
4 |
5 | #[test]
6 | fn flag_conflict() {
7 | let result = App::new("flag_conflict")
8 | .arg(Arg::from_usage("-f, --flag 'some flag'")
9 | .conflicts_with("other"))
10 | .arg(Arg::from_usage("-o, --other 'some flag'"))
11 | .get_matches_from_safe(vec!["", "-f", "-o"]);
12 | assert!(result.is_err());
13 | let err = result.err().unwrap();
14 | assert_eq!(err.error_type, ClapErrorType::ArgumentConflict);
15 | }
16 |
17 | #[test]
18 | fn flag_conflict_2() {
19 | let result = App::new("flag_conflict")
20 | .arg(Arg::from_usage("-f, --flag 'some flag'")
21 | .conflicts_with("other"))
22 | .arg(Arg::from_usage("-o, --other 'some flag'"))
23 | .get_matches_from_safe(vec!["", "-o", "-f"]);
24 | assert!(result.is_err());
25 | let err = result.err().unwrap();
26 | assert_eq!(err.error_type, ClapErrorType::ArgumentConflict);
27 | }
28 |
29 | #[test]
30 | fn group_conflict() {
31 | let result = App::new("group_conflict")
32 | .arg(Arg::from_usage("-f, --flag 'some flag'")
33 | .conflicts_with("gr"))
34 | .arg_group(ArgGroup::with_name("gr")
35 | .required(true)
36 | .add("some")
37 | .add("other"))
38 | .arg(Arg::from_usage("--some 'some arg'"))
39 | .arg(Arg::from_usage("--other 'other arg'"))
40 | .get_matches_from_safe(vec!["", "--other", "-f"]);
41 | assert!(result.is_err());
42 | let err = result.err().unwrap();
43 | assert_eq!(err.error_type, ClapErrorType::ArgumentConflict);
44 | }
45 |
46 | #[test]
47 | fn group_conflict_2() {
48 | let result = App::new("group_conflict")
49 | .arg(Arg::from_usage("-f, --flag 'some flag'")
50 | .conflicts_with("gr"))
51 | .arg_group(ArgGroup::with_name("gr")
52 | .required(true)
53 | .add("some")
54 | .add("other"))
55 | .arg(Arg::from_usage("--some 'some arg'"))
56 | .arg(Arg::from_usage("--other 'other arg'"))
57 | .get_matches_from_safe(vec!["", "-f", "--some"]);
58 | assert!(result.is_err());
59 | let err = result.err().unwrap();
60 | assert_eq!(err.error_type, ClapErrorType::ArgumentConflict);
61 | }
--------------------------------------------------------------------------------
/tests/flags.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg};
4 |
5 | #[test]
6 | fn flag_using_short() {
7 | let m = App::new("flag")
8 | .args(vec![
9 | Arg::from_usage("-f, --flag 'some flag'"),
10 | Arg::from_usage("-c, --color 'some other flag'")
11 | ])
12 | .get_matches_from(vec!["", "-f", "-c"]);
13 | assert!(m.is_present("flag"));
14 | assert!(m.is_present("color"));
15 | }
16 |
17 | #[test]
18 | fn flag_using_long() {
19 | let m = App::new("flag")
20 | .args(vec![
21 | Arg::from_usage("--flag 'some flag'"),
22 | Arg::from_usage("--color 'some other flag'")
23 | ])
24 | .get_matches_from(vec!["", "--flag", "--color"]);
25 | assert!(m.is_present("flag"));
26 | assert!(m.is_present("color"));
27 | }
28 |
29 | #[test]
30 | fn flag_using_mixed() {
31 | let m = App::new("flag")
32 | .args(vec![
33 | Arg::from_usage("-f, --flag 'some flag'"),
34 | Arg::from_usage("-c, --color 'some other flag'")
35 | ])
36 | .get_matches_from(vec!["", "-f", "--color"]);
37 | assert!(m.is_present("flag"));
38 | assert!(m.is_present("color"));
39 |
40 | let m = App::new("flag")
41 | .args(vec![
42 | Arg::from_usage("-f, --flag 'some flag'"),
43 | Arg::from_usage("-c, --color 'some other flag'")
44 | ])
45 | .get_matches_from(vec!["", "--flag", "-c"]);
46 | assert!(m.is_present("flag"));
47 | assert!(m.is_present("color"));
48 | }
49 |
50 | #[test]
51 | fn multiple_flags_in_single() {
52 | let m = App::new("multe_flags")
53 | .args(vec![
54 | Arg::from_usage("-f, --flag 'some flag'"),
55 | Arg::from_usage("-c, --color 'some other flag'"),
56 | Arg::from_usage("-d, --debug 'another other flag'")
57 | ])
58 | .get_matches_from(vec!["", "-fcd"]);
59 | assert!(m.is_present("flag"));
60 | assert!(m.is_present("color"));
61 | assert!(m.is_present("debug"));
62 | }
63 |
64 | #[test]
65 | #[should_panic]
66 | fn short_flag_misspel() {
67 | App::new("short_flag")
68 | .arg(Arg::from_usage("-f1, --flag 'some flag'"));
69 | }
70 |
71 | #[test]
72 | #[should_panic]
73 | fn short_flag_name_missing() {
74 | App::new("short_flag")
75 | .arg(Arg::from_usage("-f 'some flag'"));
76 | }
--------------------------------------------------------------------------------
/tests/multiple_occurrences.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg};
4 |
5 |
6 | #[test]
7 | fn multiple_occurrences_of_flags_long() {
8 | let m = App::new("multiple_occurrences")
9 | .arg(Arg::from_usage("--multflag 'allowed multiple flag'")
10 | .multiple(true))
11 | .arg(Arg::from_usage("--flag 'disallowed multiple flag'"))
12 | .get_matches_from(vec![
13 | "",
14 | "--multflag",
15 | "--flag",
16 | "--multflag"
17 | ]);
18 | assert!(m.is_present("multflag"));
19 | assert_eq!(m.occurrences_of("multflag"), 2);
20 | assert!(m.is_present("flag"));
21 | assert_eq!(m.occurrences_of("flag"), 1)
22 | }
23 |
24 | #[test]
25 | fn multiple_occurrences_of_flags_short() {
26 | let m = App::new("multiple_occurrences")
27 | .arg(Arg::from_usage("-m --multflag 'allowed multiple flag'")
28 | .multiple(true))
29 | .arg(Arg::from_usage("-f --flag 'disallowed multiple flag'"))
30 | .get_matches_from(vec![
31 | "",
32 | "-m",
33 | "-f",
34 | "-m"
35 | ]);
36 | assert!(m.is_present("multflag"));
37 | assert_eq!(m.occurrences_of("multflag"), 2);
38 | assert!(m.is_present("flag"));
39 | assert_eq!(m.occurrences_of("flag"), 1);
40 | }
41 |
42 | #[test]
43 | fn multiple_occurrences_of_flags_mixed() {
44 | let m = App::new("multiple_occurrences")
45 | .arg(Arg::from_usage("-m, --multflag1 'allowed multiple flag'")
46 | .multiple(true))
47 | .arg(Arg::from_usage("-n, --multflag2 'another allowed multiple flag'")
48 | .multiple(true))
49 | .arg(Arg::from_usage("-f, --flag 'disallowed multiple flag'"))
50 | .get_matches_from(vec![
51 | "",
52 | "-m",
53 | "-f",
54 | "-n",
55 | "--multflag1",
56 | "-m",
57 | "--multflag2"
58 | ]);
59 | assert!(m.is_present("multflag1"));
60 | assert_eq!(m.occurrences_of("multflag1"), 3);
61 | assert!(m.is_present("multflag2"));
62 | assert_eq!(m.occurrences_of("multflag2"), 2);
63 | assert!(m.is_present("flag"));
64 | assert_eq!(m.occurrences_of("flag"), 1);
65 | }
--------------------------------------------------------------------------------
/src/args/argbuilder/flag.rs:
--------------------------------------------------------------------------------
1 | // use std::collections::HashSet;
2 | use std::fmt::{Display, Formatter, Result};
3 |
4 | pub struct FlagBuilder<'n> {
5 | pub name: &'n str,
6 | /// The long version of the flag (i.e. word)
7 | /// without the preceding `--`
8 | pub long: Option<&'n str>,
9 | /// The string of text that will displayed to
10 | /// the user when the application's `help`
11 | /// text is displayed
12 | pub help: Option<&'n str>,
13 | /// Determines if multiple instances of the same
14 | /// flag are allowed
15 | /// I.e. `-v -v -v` or `-vvv`
16 | pub multiple: bool,
17 | /// A list of names for other arguments that
18 | /// *may not* be used with this flag
19 | pub blacklist: Option>,
20 | /// A list of names of other arguments that
21 | /// are *required* to be used when this
22 | /// flag is used
23 | pub requires: Option>,
24 | /// The short version (i.e. single character)
25 | /// of the argument, no preceding `-`
26 | pub short: Option,
27 | pub global: bool,
28 | /// A list of names for other arguments that *mutually override* this flag
29 | pub overrides: Option>,
30 | pub hidden: bool
31 | }
32 |
33 | impl<'n> Display for FlagBuilder<'n> {
34 | fn fmt(&self,
35 | f: &mut Formatter)
36 | -> Result {
37 | if let Some(l) = self.long {
38 | write!(f, "--{}", l)
39 | } else {
40 | write!(f, "-{}", self.short.unwrap())
41 | }
42 | }
43 | }
44 | #[cfg(test)]
45 | mod test {
46 | use super::FlagBuilder;
47 |
48 | #[test]
49 | fn flagbuilder_display() {
50 | let f = FlagBuilder {
51 | name: "flg",
52 | short: None,
53 | long: Some("flag"),
54 | help: None,
55 | multiple: true,
56 | blacklist: None,
57 | requires: None,
58 | global: false,
59 | overrides: None,
60 | hidden: false,
61 | };
62 |
63 | assert_eq!(&*format!("{}", f), "--flag");
64 |
65 | let f2 = FlagBuilder {
66 | name: "flg",
67 | short: Some('f'),
68 | long: None,
69 | help: None,
70 | multiple: false,
71 | blacklist: None,
72 | requires: None,
73 | global: false,
74 | overrides: None,
75 | hidden: false,
76 | };
77 |
78 | assert_eq!(&*format!("{}", f2), "-f");
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/examples/12_typed_values.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | extern crate clap;
3 |
4 | use clap::App;
5 |
6 | fn main() {
7 | // You can use some convenience macros provided by clap to get typed values, so long as the
8 | // type you specify implements std::str::FromStr
9 | //
10 | // This works for both single, and multiple values (multiple values returns a Vec)
11 | //
12 | // There are also two ways in which to get types, those where failures cause the program to exit
13 | // with an error and usage string, and those which return a Result or Result,String>
14 | // respectively. Both methods support single and multiple values.
15 | //
16 | // The macro which returns a Result allows you decide what to do upon a failure, exit, provide a
17 | // default value, etc. You have control. But it also means you have to write the code or boiler plate
18 | // to handle those instances.
19 | //
20 | // That is why the second method exists, so you can simply get a T or Vec back, or be sure the
21 | // program will exit gracefully. The catch is, the second method should *only* be used on required
22 | // arguments, because if the argument isn't found, it exits. Just FYI ;)
23 | //
24 | // The following example shows both methods.
25 | //
26 | // **NOTE:** to use the macros, you must include #[macro_use] just above the 'extern crate clap;'
27 | // declaration in your crate root.
28 | let matches = App::new("myapp")
29 | // Create two arguments, a required positional which accepts multiple values
30 | // and an optional '-l value'
31 | .args_from_usage(
32 | "... 'A sequence of whole positive numbers, i.e. 20 25 30'
33 | -l [len] 'A length to use, defaults to 10 when omitted'")
34 | .get_matches();
35 |
36 | // Here we get a value of type u32 from our optional -l argument.
37 | // If the value provided to len failes to parse, we default to 10
38 | //
39 | // Using other methods such as unwrap_or_else(|e| println!("{}",e))
40 | // are possible too.
41 | let len = value_t!(matches.value_of("len"), u32).unwrap_or(10);
42 |
43 | println!("len ({}) + 2 = {}", len, len + 2);
44 |
45 | // This code loops through all the values provided to "seq" and adds 2
46 | // If seq fails to parse, the program exits, you don't have an option
47 | for v in value_t_or_exit!(matches.values_of("seq"), u32) {
48 | println!("Sequence part {} + 2: {}", v, v + 2);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/examples/13a_enum_values_automatic.rs:
--------------------------------------------------------------------------------
1 | // You can use clap's value_t! macro with a custom enum by implementing the std::str::FromStr
2 | // trait which is very straight forward. There are three ways to do this, for simple enums
3 | // meaning those that don't require 'pub' or any '#[derive()]' directives you can use clas's
4 | // simple_enum! macro. For those that require 'pub' or any '#[derive()]'s you can use clap's
5 | // arg_enum! macro. The third way is to implement std::str::FromStr manually.
6 | //
7 | // In most circumstances using either simple_enum! or arg_enum! is fine.
8 | //
9 | // In the following example we will create two enums using macros, assign a positional argument
10 | // that accepts only one of those values, and use clap to parse the argument.
11 |
12 | // Add clap like normal
13 | #[macro_use]
14 | extern crate clap;
15 |
16 | use clap::{App, Arg};
17 |
18 | // Define your enum, the simple_num! macro takes a enum name followed by => and each value
19 | // separated by a ','
20 | simple_enum!{ Foo => Bar, Baz, Qux }
21 |
22 | // Using arg_enum! is more like traditional enum declarations
23 | //
24 | // **NOTE:** Only bare variants are supported
25 | arg_enum!{
26 | #[derive(Debug)]
27 | pub enum Oof {
28 | Rab,
29 | Zab,
30 | Xuq
31 | }
32 | }
33 |
34 | fn main() {
35 | // Create the application like normal
36 | let enum_vals = ["fast", "slow"];
37 | let m = App::new("myapp")
38 | // Use a single positional argument that is required
39 | .arg(Arg::from_usage(" 'The Foo to use'")
40 | // You can define a list of possible values if you want the values to be
41 | // displayed in the help information. Whether you use possible_values() or
42 | // not, the valid values will ALWAYS be displayed on a failed parse.
43 | .possible_values(&enum_vals))
44 | // For the second positional, lets not use possible_values() just to show the difference
45 | .arg_from_usage(" 'The Oof to use'")
46 | .get_matches();
47 |
48 | let t = value_t_or_exit!(m.value_of("type"), Foo);
49 | let t2 = value_t_or_exit!(m.value_of("type2"), Oof);
50 |
51 |
52 | // Now we can use our enum like normal.
53 | match t {
54 | Foo::Bar => println!("Found a Bar"),
55 | Foo::Baz => println!("Found a Baz"),
56 | Foo::Qux => println!("Found a Qux")
57 | }
58 |
59 | // Since our Oof derives Debug, we can do this:
60 | println!("Oof: {:?}", t2);
61 | }
--------------------------------------------------------------------------------
/tests/opts.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg};
4 |
5 | #[test]
6 | fn opts_using_short() {
7 | let m = App::new("opts")
8 | .args(vec![
9 | Arg::from_usage("-f [flag] 'some flag'"),
10 | Arg::from_usage("-c [color] 'some other flag'")
11 | ])
12 | .get_matches_from(vec!["", "-f", "some", "-c", "other"]);
13 | assert!(m.is_present("flag"));
14 | assert_eq!(m.value_of("flag").unwrap(), "some");
15 | assert!(m.is_present("color"));
16 | assert_eq!(m.value_of("color").unwrap(), "other");
17 | }
18 |
19 | #[test]
20 | fn opts_using_long_space() {
21 | let m = App::new("opts")
22 | .args(vec![
23 | Arg::from_usage("--flag [flag] 'some flag'"),
24 | Arg::from_usage("--color [color] 'some other flag'")
25 | ])
26 | .get_matches_from(vec!["", "--flag", "some", "--color", "other"]);
27 | assert!(m.is_present("flag"));
28 | assert_eq!(m.value_of("flag").unwrap(), "some");
29 | assert!(m.is_present("color"));
30 | assert_eq!(m.value_of("color").unwrap(), "other");
31 | }
32 |
33 | #[test]
34 | fn opts_using_long_equals() {
35 | let m = App::new("opts")
36 | .args(vec![
37 | Arg::from_usage("--flag [flag] 'some flag'"),
38 | Arg::from_usage("--color [color] 'some other flag'")
39 | ])
40 | .get_matches_from(vec!["", "--flag=some", "--color=other"]);
41 | assert!(m.is_present("flag"));
42 | assert_eq!(m.value_of("flag").unwrap(), "some");
43 | assert!(m.is_present("color"));
44 | assert_eq!(m.value_of("color").unwrap(), "other");
45 | }
46 |
47 | #[test]
48 | fn opts_using_mixed() {
49 | let m = App::new("opts")
50 | .args(vec![
51 | Arg::from_usage("-f, --flag [flag] 'some flag'"),
52 | Arg::from_usage("-c, --color [color] 'some other flag'")
53 | ])
54 | .get_matches_from(vec!["", "-f", "some", "--color", "other"]);
55 | assert!(m.is_present("flag"));
56 | assert_eq!(m.value_of("flag").unwrap(), "some");
57 | assert!(m.is_present("color"));
58 | assert_eq!(m.value_of("color").unwrap(), "other");
59 |
60 | let m = App::new("opts")
61 | .args(vec![
62 | Arg::from_usage("-f, --flag [flag] 'some flag'"),
63 | Arg::from_usage("-c, --color [color] 'some other flag'")
64 | ])
65 | .get_matches_from(vec!["", "--flag=some", "-c", "other"]);
66 | assert!(m.is_present("flag"));
67 | assert_eq!(m.value_of("flag").unwrap(), "some");
68 | assert!(m.is_present("color"));
69 | assert_eq!(m.value_of("color").unwrap(), "other");
70 | }
--------------------------------------------------------------------------------
/tests/app.yml:
--------------------------------------------------------------------------------
1 | name: claptests
2 | version: 1.0
3 | about: tests clap library
4 | author: Kevin K.
5 | settings:
6 | - ArgRequiredElseHelp
7 | args:
8 | - opt:
9 | short: o
10 | long: option
11 | multiple: true
12 | help: tests options
13 | - positional:
14 | help: tests positionals
15 | index: 1
16 | - positional2:
17 | help: tests positionals with exclusions
18 | index: 2
19 | - flag:
20 | short: f
21 | long: flag
22 | multiple: true
23 | help: tests flags
24 | global: true
25 | - flag2:
26 | short: F
27 | help: tests flags with exclusions
28 | conflicts_with:
29 | - flag
30 | requires:
31 | - option2
32 | - option2:
33 | long: long-option-2
34 | help: tests long options with exclusions
35 | conflicts_with:
36 | - option
37 | requires:
38 | - positional2
39 | - option3:
40 | short: O
41 | long: Option
42 | help: tests options with specific value sets
43 | takes_value: true
44 | possible_values:
45 | - fast
46 | - slow
47 | - positional3:
48 | index: 3
49 | help: tests positionals with specific values
50 | possible_values: [ vi, emacs ]
51 | - multvals:
52 | long: multvals
53 | help: Tests mutliple values, not mult occs
54 | value_names:
55 | - one
56 | - two
57 | - multvalsmo:
58 | long: multvalsmo
59 | multiple: true
60 | help: Tests mutliple values, not mult occs
61 | value_names: [one, two]
62 | - minvals2:
63 | long: minvals2
64 | multiple: true
65 | help: Tests 2 min vals
66 | min_values: 2
67 | - maxvals3:
68 | long: maxvals3
69 | multiple: true
70 | help: Tests 3 max vals
71 | max_values: 3
72 | arg_groups:
73 | - test:
74 | args:
75 | - maxvals3
76 | - minmals2
77 | conflicts_with:
78 | - option3
79 | requires:
80 | - multvals
81 | subcommands:
82 | - subcmd:
83 | about: tests subcommands
84 | version: 0.1
85 | author: Kevin K.
86 | args:
87 | - scoption:
88 | short: o
89 | long: option
90 | multiple: true
91 | help: tests options
92 | takes_value: true
93 | - scpositional:
94 | help: tests positionals
95 | index: 1
96 |
--------------------------------------------------------------------------------
/examples/04_using_matches.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg};
4 |
5 | fn main() {
6 |
7 | // Once all App settings (including all arguments) have been set, you call get_matches() which
8 | // parses the string provided by the user, and returns all the valid matches to the ones you
9 | // specified.
10 | //
11 | // You can then query the matches struct to get information about how the user ran the program
12 | // at startup.
13 | //
14 | // For this example, let's assume you created an App which accepts three arguments (plus two
15 | // generated by clap), a flag to display debugging information triggered with "-d" or
16 | // "--debug" as well as an option argument which specifies a custom configuration file to use
17 | // triggered with "-c file" or "--config file" or "--config=file" and finally a positional
18 | // argument which is the input file we want to work with, this will be the only required
19 | // argument.
20 | let matches = App::new("MyApp")
21 | .about("Parses an input file to do awesome things")
22 | .version("1.0")
23 | .author("Kevin K. ")
24 | .arg(Arg::with_name("debug")
25 | .help("turn on debugging information")
26 | .short("d")
27 | .long("debug"))
28 | .arg(Arg::with_name("config")
29 | .help("sets the config file to use")
30 | .short("c")
31 | .long("config"))
32 | .arg(Arg::with_name("input")
33 | .help("the input file to use")
34 | .index(1)
35 | .required(true))
36 | .get_matches();
37 |
38 | // We can find out whether or not debugging was turned on
39 | if matches.is_present("debug") {
40 | println!("Debugging is turned on");
41 | }
42 |
43 | // If we wanted to some custom initialization based off some configuration file provided
44 | // by the user, we could get the file (A string of the file)
45 | if let Some(ref file) = matches.value_of("config") {
46 | println!("Using config file: {}", file);
47 | }
48 |
49 | // Because "input" is required we can safely call unwrap() because had the user NOT
50 | // specified a value, clap would have explained the error the user, and exited.
51 | println!("Doing real work with file: {}", matches.value_of("input").unwrap() );
52 |
53 | // Continued program logic goes here...
54 | }
55 |
--------------------------------------------------------------------------------
/tests/positionals.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg, ClapErrorType};
4 |
5 | #[test]
6 | fn positional() {
7 | let m = App::new("positional")
8 | .args(vec![
9 | Arg::from_usage("-f, --flag 'some flag'"),
10 | Arg::with_name("positional")
11 | .index(1)
12 | ])
13 | .get_matches_from(vec!["", "-f", "test"]);
14 | assert!(m.is_present("positional"));
15 | assert!(m.is_present("flag"));
16 | assert_eq!(m.value_of("positional").unwrap(), "test");
17 |
18 | let m = App::new("positional")
19 | .args(vec![
20 | Arg::from_usage("-f, --flag 'some flag'"),
21 | Arg::with_name("positional")
22 | .index(1)
23 | ])
24 | .get_matches_from(vec!["", "test", "--flag"]);
25 | assert!(m.is_present("positional"));
26 | assert!(m.is_present("flag"));
27 | assert_eq!(m.value_of("positional").unwrap(), "test");
28 | }
29 |
30 | #[test]
31 | fn positional_multiple() {
32 | let m = App::new("positional_multiple")
33 | .args(vec![
34 | Arg::from_usage("-f, --flag 'some flag'"),
35 | Arg::with_name("positional")
36 | .index(1)
37 | .multiple(true)
38 | ])
39 | .get_matches_from(vec!["", "-f", "test1", "test2", "test3"]);
40 | assert!(m.is_present("positional"));
41 | assert!(m.is_present("flag"));
42 | assert_eq!(m.values_of("positional").unwrap(), vec!["test1", "test2", "test3"]);
43 |
44 | let m = App::new("positional_multiple")
45 | .args(vec![
46 | Arg::from_usage("-f, --flag 'some flag'"),
47 | Arg::with_name("positional")
48 | .index(1)
49 | .multiple(true)
50 | ])
51 | .get_matches_from(vec!["", "test1", "test2", "test3", "--flag"]);
52 | assert!(m.is_present("positional"));
53 | assert!(m.is_present("flag"));
54 | assert_eq!(m.values_of("positional").unwrap(), vec!["test1", "test2", "test3"]);
55 | }
56 |
57 | #[test]
58 | fn positional_multiple_2() {
59 | let result = App::new("positional_multiple")
60 | .args(vec![
61 | Arg::from_usage("-f, --flag 'some flag'"),
62 | Arg::with_name("positional")
63 | .index(1)
64 | ])
65 | .get_matches_from_safe(vec!["", "-f", "test1", "test2", "test3"]);
66 | assert!(result.is_err());
67 | let err = result.err().unwrap();
68 | assert_eq!(err.error_type, ClapErrorType::UnexpectedArgument);
69 | }
70 |
71 | #[test]
72 | fn positional_possible_values() {
73 | let m = App::new("positional_possible_values")
74 | .args(vec![
75 | Arg::from_usage("-f, --flag 'some flag'"),
76 | Arg::with_name("positional")
77 | .index(1)
78 | .possible_value("test123")
79 | ])
80 | .get_matches_from(vec!["", "-f", "test123"]);
81 | assert!(m.is_present("positional"));
82 | assert!(m.is_present("flag"));
83 | assert_eq!(m.values_of("positional").unwrap(), vec!["test123"]);
84 | }
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | Contributions are always welcome! Please use the following guidelines when contributing to `clap`
4 |
5 | 1. Fork `clap`
6 | 2. Clone your fork (`git clone https://github.com/$YOUR_USERNAME/clap-rs && cd clap-rs`)
7 | 3. Create new branch (`git checkout -b new-branch`)
8 | 4. Make your changes, and commit (`git commit -am "your message"`)
9 | * I use a [conventional](https://github.com/ajoslin/conventional-changelog/blob/a5505865ff3dd710cf757f50530e73ef0ca641da/conventions/angular.md) changelog format so I can update my changelog using [clog](https://github.com/thoughtram/clog)
10 | * In addition to the conventions defined above, I also use `imp`, `wip`, `examples`.
11 | * Format your commit subject line using the following format: `TYPE(COMPONENT): MESSAGE` where `TYPE` is one of the following:
12 | - `feat` - A new feature
13 | - `imp` - An improvement to an existing feature
14 | - `perf` - A performance improvement
15 | - `docs` - Changes to documentation only
16 | - `tests` - Changes to the testing framework or tests only
17 | - `fix` - A bug fix
18 | - `refactor` - Code functionality doesn't change, but underlying structure may
19 | - `style` - Stylistic changes only, no functionality changes
20 | - `wip` - A work in progress commit (Should typically be `git rebase`'ed away)
21 | - `chore` - Catch all or things that have to do with the build system, etc
22 | - `examples` - Changes to existing example, or a new example
23 | * The `COMPONENT` is optional, and may be a single file, directory, or logical component. Can be omitted if commit applies globally
24 | 5. Run the tests (`cargo test --features yaml && make -C clap-tests test`)
25 | 6. `git rebase` into concise commits and remove `--fixup`s (`git rebase -i HEAD~NUM` where `NUM` is number of commits back)
26 | 7. Push your changes back to your fork (`git push origin $your-branch`)
27 | 8. Create a pull request! (You can also create the pull request first, and we'll merge when ready. This a good way to discuss proposed changes.)
28 |
29 | Another really great way to help is if you find an interesting, or helpful way in which to use `clap`. You can either add it to the `examples/` directory, or file an issue and tell me. I'm all about giving credit where credit is due :)
30 |
31 | ## Goals
32 |
33 | There are a few goals of `clap` that I'd like to maintain throughout contributions.
34 |
35 | * Remain backwards compatible when possible
36 | - If backwards compatibility *must* be broken, use deprecation warnings if at all possible before removing legacy code
37 | - This does not apply for security concerns
38 | * Parse arguments quickly
39 | - Parsing of arguments shouldn't slow down usage of the main program
40 | - This is also true of generating help and usage information (although *slightly* less stringent, as the program is about to exit)
41 | * Try to be cognizant of memory usage
42 | - Once parsing is complete, the memory footprint of `clap` should be low since the main program is the star of the show
43 | * `panic!` on *developer* error, exit gracefully on *end-user* error
44 |
--------------------------------------------------------------------------------
/examples/08_subcommands.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg, SubCommand};
4 |
5 | fn main() {
6 |
7 | // SubCommands function exactly like sub-Apps, because that's exactly what they are. Each
8 | // instance of a SubCommand can have it's own version, author(s), Args, and even it's own
9 | // subcommands.
10 | //
11 | // # Help and Version
12 | // Just like Apps, each subcommand will get it's own "help" and "version" flags automatically
13 | // generated. Also, like Apps, you can override "-V" or "-h" safely and still get "--help" and
14 | // "--version" auto generated.
15 | //
16 | // NOTE: If you specify a subcommand for your App, clap will also autogenerate a "help"
17 | // subcommand along with "-h" and "--help" (applies to sub-subcommands as well).
18 | //
19 | // Just like arg() and args(), subcommands can be specified one at a time via subcommand() or
20 | // multiple ones at once with a Vec provided to subcommands().
21 | let matches = App::new("MyApp")
22 | // Normal App and Arg configuration goes here...
23 |
24 | // In the following example assume we wanted an application which
25 | // supported an "add" subcommand, this "add" subcommand also took
26 | // one positional argument of a file to add:
27 | .subcommand(SubCommand::with_name("add") // The name we call argument with
28 | .about("Adds files to myapp") // The message displayed in "myapp -h"
29 | // or "myapp help"
30 | .version("0.1") // Subcommands can have independent version
31 | .author("Kevin K.") // And authors
32 | .arg(Arg::with_name("input") // And their own arguments
33 | .help("the file to add")
34 | .index(1)
35 | .required(true)))
36 | .get_matches();
37 |
38 | // You can check if a subcommand was used like normal
39 | if matches.is_present("add") {
40 | println!("'myapp add' was run.");
41 | }
42 |
43 | // You can get the independent subcommand matches (which function exactly like App matches)
44 | if let Some(ref matches) = matches.subcommand_matches("add") {
45 | // Safe to use unwrap() because of the required() option
46 | println!("Adding file: {}", matches.value_of("input").unwrap());
47 | }
48 |
49 | // You can also match on a subcommand's name
50 | match matches.subcommand_name() {
51 | Some("add") => println!("'myapp add' was used"),
52 | None => println!("No subcommand was used"),
53 | _ => println!("Some other subcommand was used"),
54 | }
55 |
56 | // Continued program logic goes here...
57 | }
58 |
--------------------------------------------------------------------------------
/examples/18_builder_macro.rs:
--------------------------------------------------------------------------------
1 | #[macro_use] extern crate clap;
2 |
3 | // No use imports from clap. #[macro_use] gives us `clap_app!` which internally uses `$crate::`
4 |
5 | fn main() {
6 |
7 | // Validation example testing that a file exists
8 | let file_exists = |path| {
9 | if std::fs::metadata(path).is_ok() {
10 | Ok(())
11 | } else {
12 | Err(String::from("File doesn't exist"))
13 | }
14 | };
15 |
16 | // External module may contain this subcommand. If this exists in another module, a function is
17 | // required to access it. Recommend `fn clap() -> Clap::SubCommand`.
18 | let external_sub_command = clap_app!( @subcommand foo =>
19 | (@arg bar: -b "Bar")
20 | );
21 |
22 | let matches = clap_app!(MyApp =>
23 | (@setting SubcommandRequiredElseHelp)
24 | (version: "1.0")
25 | (author: "Alice")
26 | (about: "Does awesome things")
27 | (@arg config: -c --config #{1, 2} {file_exists} "Sets a custom config file")
28 | (@arg input: * "Input file")
29 | (@group test =>
30 | (@attributes +required)
31 | (@arg output: "Sets an optional output file")
32 | (@arg debug: -d ... "Turn debugging information on")
33 | )
34 | (subcommand: external_sub_command)
35 | (@subcommand test =>
36 | (about: "does testing things")
37 | (version: "2.5")
38 | (@arg list: -l "Lists test values")
39 | (@arg test_req: -r requires[list] "Tests requirement for listing")
40 | (@arg aaaa: --aaaa +takes_value {
41 | |a| if a.contains("a") {
42 | Ok(())
43 | } else {
44 | Err(String::from("string does not contain at least one a"))
45 | }
46 | } "Test if the argument contains an a")
47 | )
48 | ).get_matches();
49 |
50 | // You can check the value provided by positional arguments, or option arguments
51 | if let Some(o) = matches.value_of("output") {
52 | println!("Value for output: {}", o);
53 | }
54 |
55 | if let Some(c) = matches.value_of("config") {
56 | println!("Value for config: {}", c);
57 | }
58 |
59 | // You can see how many times a particular flag or argument occurred
60 | // Note, only flags can have multiple occurrences
61 | match matches.occurrences_of("debug") {
62 | 0 => println!("Debug mode is off"),
63 | 1 => println!("Debug mode is kind of on"),
64 | 2 => println!("Debug mode is on"),
65 | 3 | _ => println!("Don't be crazy"),
66 | }
67 |
68 | // You can check for the existence of subcommands, and if found use their
69 | // matches just as you would the top level app
70 | if let Some(ref matches) = matches.subcommand_matches("test") {
71 | // "$ myapp test" was run
72 | if matches.is_present("list") {
73 | // "$ myapp test -l" was run
74 | println!("Printing testing lists...");
75 | } else {
76 | println!("Not printing testing lists...");
77 | }
78 | }
79 |
80 |
81 | // Continued program logic goes here...
82 | }
83 |
--------------------------------------------------------------------------------
/examples/05_flag_args.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg};
4 |
5 | fn main() {
6 |
7 | // Of the three argument types, flags are the most simple. Flags are simple switches which can
8 | // be either "on" or "off"
9 | //
10 | // clap also supports multiple occurrences of flags, the common example is "verbosity" where a
11 | // user could want a little information with "-v" or tons of information with "-v -v" or "-vv"
12 | let matches = App::new("MyApp")
13 | // Regular App configuration goes here...
14 |
15 | // We'll add a flag that represents an awesome meter...
16 | //
17 | // I'll explain each possible setting that "flags" accept. Keep in mind
18 | // that you DO NOT need to set each of these for every flag, only the ones
19 | // you want for your individual case.
20 | .arg(Arg::with_name("awesome")
21 | .help("turns up the awesome") // Displayed when showing help info
22 | .short("a") // Trigger this arg with "-a"
23 | .long("awesome") // Trigger this arg with "--awesome"
24 | .multiple(true) // This flag should allow multiple
25 | // occurrences such as "-aaa" or "-a -a"
26 | .requires("config") // Says, "If the user uses -a, they MUST
27 | // also use this other 'config' arg too"
28 | // Can also specifiy a list using
29 | // requires_all(Vec<&str>)
30 | .conflicts_with("output") // Opposite of requires(), says "if the
31 | // user uses -a, they CANNOT use 'output'"
32 | // also has a mutually_excludes_all(Vec<&str>)
33 | )
34 | // NOTE: In order to compile this example, comment out requres() and
35 | // mutually_excludes() because we have not defined an "output" or "config"
36 | // argument.
37 | .get_matches();
38 |
39 | // We can find out whether or not awesome was used
40 | if matches.is_present("awesome") {
41 | println!("Awesomeness is turned on");
42 | }
43 |
44 | // If we set the mutliple() option of a flag we can check how many times the user specified
45 | //
46 | // Note: if we did not specify the multiple() option, and the user used "awesome" we would get
47 | // a 1 (no matter how many times they actually used it), or a 0 if they didn't use it at all
48 | match matches.occurrences_of("awesome") {
49 | 0 => println!("Nothing is awesome"),
50 | 1 => println!("Some things are awesome"),
51 | 2 => println!("Lots of things are awesome"),
52 | 3 | _ => println!("EVERYTHING is awesome!"),
53 | }
54 |
55 | // Continued program logic goes here...
56 | }
57 |
--------------------------------------------------------------------------------
/src/args/argbuilder/positional.rs:
--------------------------------------------------------------------------------
1 | use std::fmt::{Display, Formatter, Result};
2 | use std::result::Result as StdResult;
3 | use std::rc::Rc;
4 |
5 | pub struct PosBuilder<'n> {
6 | pub name: &'n str,
7 | /// The string of text that will displayed to the user when the application's
8 | /// `help` text is displayed
9 | pub help: Option<&'n str>,
10 | /// If this is a required by default when using the command line program
11 | /// i.e. a configuration file that's required for the program to function
12 | /// **NOTE:** required by default means, it is required *until* mutually
13 | /// exclusive arguments are evaluated.
14 | pub required: bool,
15 | /// Allow multiple occurrences of an option argument such as "-c some -c other"
16 | pub multiple: bool,
17 | /// A list of names of other arguments that are *required* to be used when
18 | /// this flag is used
19 | pub requires: Option>,
20 | /// A list of names for other arguments that *may not* be used with this flag
21 | pub blacklist: Option>,
22 | /// A list of possible values for this argument
23 | pub possible_vals: Option>,
24 | /// The index of the argument
25 | pub index: u8,
26 | pub num_vals: Option,
27 | pub max_vals: Option,
28 | pub min_vals: Option,
29 | pub empty_vals: bool,
30 | pub global: bool,
31 | pub validator: Option StdResult<(), String>>>,
32 | /// A list of names for other arguments that *mutually override* this flag
33 | pub overrides: Option>,
34 | pub hidden: bool
35 | }
36 |
37 | impl<'n> Display for PosBuilder<'n> {
38 | fn fmt(&self,
39 | f: &mut Formatter)
40 | -> Result {
41 | if self.required {
42 | try!(write!(f, "<{}>", self.name));
43 | } else {
44 | try!(write!(f, "[{}]", self.name));
45 | }
46 | if self.multiple {
47 | try!(write!(f, "..."));
48 | }
49 |
50 | Ok(())
51 | }
52 | }
53 | #[cfg(test)]
54 | mod test {
55 | use super::PosBuilder;
56 |
57 | #[test]
58 | fn posbuilder_display() {
59 | let p = PosBuilder {
60 | name: "pos",
61 | help: None,
62 | multiple: true,
63 | blacklist: None,
64 | required: false,
65 | possible_vals: None,
66 | requires: None,
67 | num_vals: None,
68 | min_vals: None,
69 | max_vals: None,
70 | index: 1,
71 | empty_vals: true,
72 | global: false,
73 | validator: None,
74 | overrides: None,
75 | hidden: false,
76 | };
77 |
78 | assert_eq!(&*format!("{}", p), "[pos]...");
79 |
80 | let p2 = PosBuilder {
81 | name: "pos",
82 | help: None,
83 | multiple: false,
84 | blacklist: None,
85 | required: true,
86 | possible_vals: None,
87 | requires: None,
88 | num_vals: None,
89 | min_vals: None,
90 | max_vals: None,
91 | index: 1,
92 | empty_vals: true,
93 | global: false,
94 | validator: None,
95 | overrides: None,
96 | hidden: false,
97 | };
98 |
99 | assert_eq!(&*format!("{}", p2), "");
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/examples/17_yaml.yml:
--------------------------------------------------------------------------------
1 | name: yml_app
2 | version: 1.0
3 | about: an example using a .yml file to build a CLI
4 | author: Kevin K.
5 |
6 | # AppSettings can be defined as a list and are **not** ascii case sensitive
7 | settings:
8 | - ArgRequiredElseHelp
9 |
10 | # All Args must be defined in the 'args:' list where the name of the arg, is the
11 | # key to a Hash object
12 | args:
13 | # The name of this argument, is 'opt' which will be used to access the value
14 | # later in your Rust code
15 | - opt:
16 | help: example option argument from yaml
17 | short: o
18 | long: option
19 | multiple: true
20 | takes_value: true
21 | - pos:
22 | help: example positional argument from yaml
23 | index: 1
24 | # A list of possible values can be defined as a list
25 | possible_values:
26 | - fast
27 | - slow
28 | - flag:
29 | help: demo flag argument
30 | short: F
31 | multiple: true
32 | global: true
33 | # Conflicts, mutual overrides, and requirements can all be defined as a
34 | # list, where the key is the name of the other argument
35 | conflicts_with:
36 | - opt
37 | requires:
38 | - pos
39 | - mode:
40 | long: mode
41 | help: shows an option with specific values
42 | # possible_values can also be defined in this list format
43 | possible_values: [ vi, emacs ]
44 | takes_value: true
45 | - mvals:
46 | long: mult-vals
47 | help: demos an option which has two named values
48 | # value names can be described in a list, where the help will be shown
49 | # --mult-vals
50 | value_names:
51 | - one
52 | - two
53 | - minvals:
54 | long: min-vals
55 | multiple: true
56 | help: you must supply at least two values to satisfy me
57 | min_values: 2
58 | - maxvals:
59 | long: max-vals
60 | multiple: true
61 | help: you can only supply a max of 3 values for me!
62 | max_values: 3
63 |
64 | # All subcommands must be listed in the 'subcommand:' object, where the key to
65 | # the list is the name of the subcommand, and all settings for that command are
66 | # are part of a Hash object
67 | subcommands:
68 | # The nae of this subcommand will be 'subcmd' which can be accessed in your
69 | # Rust code later
70 | - subcmd:
71 | about: demos subcommands from yaml
72 | version: 0.1
73 | author: Kevin K.
74 | # Subcommand args are exactly like App args
75 | args:
76 | - scopt:
77 | short: B
78 | multiple: true
79 | help: example subcommand option
80 | takes_value: true
81 | - scpos1:
82 | help: example subcommand positional
83 | index: 1
84 |
85 | # ArgGroups are supported as well, and must be sepcified in the 'arg_groups:'
86 | # object of this file
87 | arg_groups:
88 | # the name of the ArgGoup is specified here
89 | - min-max-vals:
90 | # All args and groups that are a part of this group are set here
91 | args:
92 | - minvals
93 | - maxvals
94 | # setting conflicts is done the same manner as setting 'args:'
95 | #
96 | # to make this group required, you could set 'required: true' but for
97 | # this example we won't do that.
98 |
--------------------------------------------------------------------------------
/examples/06_positional_args.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg};
4 |
5 | fn main() {
6 |
7 | // Positional arguments are those values after the program name which are not preceded by any
8 | // identifier (such as "myapp some_file"). Positionals support many of the same options as
9 | // flags, as well as a few additional ones.
10 | let matches = App::new("MyApp")
11 | // Regular App configuration goes here...
12 |
13 | // We'll add two positional arguments, a input file, and a config file.
14 | //
15 | // I'll explain each possible setting that "positionals" accept. Keep in
16 | // mind that you DO NOT need to set each of these for every flag, only the
17 | // ones that apply to your individual case.
18 | .arg(Arg::with_name("input")
19 | .help("the input file to use") // Displayed when showing help info
20 | .index(1) // Set the order in which the user must
21 | // specify this argument (Starts at 1)
22 | .requires("config") // Says, "If the user uses "input", they MUST
23 | // also use this other 'config' arg too"
24 | // Can also specifiy a list using
25 | // requires_all(Vec<&str>)
26 | .conflicts_with("output") // Opposite of requires(), says "if the
27 | // user uses -a, they CANNOT use 'output'"
28 | // also has a mutually_excludes_all(Vec<&str>)
29 | .required(true) // By default this argument MUST be present
30 | // NOTE: mutual exclusions take precedence over
31 | // required arguments
32 | )
33 | .arg(Arg::with_name("config")
34 | .help("the config file to use")
35 | .index(2)) // Note, we do not need to specify required(true)
36 | // if we don't want to, because "input" already
37 | // requires "config"
38 | // Note, we also do not need to specify requires("input")
39 | // because requires lists are automatically two-way
40 |
41 | // NOTE: In order to compile this example, comment out mutually_excludes()
42 | // because we have not defined an "output" argument.
43 | .get_matches();
44 |
45 | // We can find out whether or not "input" or "config" were used
46 | if matches.is_present("input") {
47 | println!("An input file was specified");
48 | }
49 |
50 | // We can also get the values for those arguments
51 | if let Some(ref in_file) = matches.value_of("input") {
52 | // It's safe to call unwrap() because of the required options we set above
53 | println!("Doing work with {} and {}", in_file, matches.value_of("config").unwrap());
54 | }
55 | // Continued program logic goes here...
56 | }
57 |
--------------------------------------------------------------------------------
/examples/01c_quick_example.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | extern crate clap;
3 |
4 | fn main() {
5 | // This example shows how to create an application with several arguments using macro builder.
6 | // It combines the simplicity of the from_usage methods and the performance of the Builder Pattern.
7 | //
8 | // The example below is functionally identical to the one in 01a_quick_example.rs and 01b_quick_example.rs
9 | //
10 | // Create an application with 5 possible arguments (2 auto generated) and 2 subcommands (1 auto generated)
11 | // - A config file
12 | // + Uses "-c filename" or "--config filename"
13 | // - An output file
14 | // + A positional argument (i.e. "$ myapp output_filename")
15 | // - A debug flag
16 | // + Uses "-d" or "--debug"
17 | // + Allows multiple occurrences of such as "-dd" (for vary levels of debugging, as an example)
18 | // - A help flag (automatically generated by clap)
19 | // + Uses "-h" or "--help" (Only autogenerated if you do NOT specify your own "-h" or "--help")
20 | // - A version flag (automatically generated by clap)
21 | // + Uses "-V" or "--version" (Only autogenerated if you do NOT specify your own "-V" or "--version")
22 | // - A subcommand "test" (subcommands behave like their own apps, with their own arguments
23 | // + Used by "$ myapp test" with the following arguments
24 | // > A list flag
25 | // = Uses "-l" (usage is "$ myapp test -l"
26 | // > A help flag (automatically generated by clap
27 | // = Uses "-h" or "--help" (full usage "$ myapp test -h" or "$ myapp test --help")
28 | // > A version flag (automatically generated by clap
29 | // = Uses "-V" or "--version" (full usage "$ myapp test -V" or "$ myapp test --version")
30 | // - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own)
31 | // + Used by "$ myapp help" (same functionality as "-h" or "--help")
32 | let matches = clap_app!(myapp =>
33 | (version: "1.0")
34 | (author: "Kevin K. ")
35 | (about: "Does awesome things")
36 | (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
37 | (@arg INPUT: +required "Sets the input file to use")
38 | (@arg debug: -d ... "Sets the level of debugging information")
39 | (@subcommand test =>
40 | (about: "controls testing features")
41 | (version: "1.3")
42 | (author: "Someone E. ")
43 | (@arg verbose: -v --verbose "Print test information verbosely")
44 | )
45 | ).get_matches();
46 |
47 | // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't
48 | // required we could have used an 'if let' to conditionally get the value)
49 | println!("Using input file: {}", matches.value_of("INPUT").unwrap());
50 |
51 | // Gets a value for config if supplied by user, or defaults to "default.conf"
52 | let config = matches.value_of("CONFIG").unwrap_or("default.conf");
53 | println!("Value for config: {}", config);
54 |
55 | // Vary the output based on how many times the user used the "debug" flag
56 | // (i.e. 'myapp -d -d -d' or 'myapp -ddd' vs 'myapp -d'
57 | match matches.occurrences_of("debug") {
58 | 0 => println!("Debug mode is off"),
59 | 1 => println!("Debug mode is kind of on"),
60 | 2 => println!("Debug mode is on"),
61 | 3 | _ => println!("Don't be crazy"),
62 | }
63 |
64 | // You can information about subcommands by requesting their matches by name
65 | // (as below), requesting just the name used, or both at the same time
66 | if let Some(matches) = matches.subcommand_matches("test") {
67 | if matches.is_present("verbose") {
68 | println!("Printing verbosely...");
69 | } else {
70 | println!("Printing normally...");
71 | }
72 | }
73 |
74 | // more porgram logic goes here...
75 | }
76 |
--------------------------------------------------------------------------------
/examples/01a_quick_example.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, SubCommand};
4 |
5 | fn main() {
6 |
7 | // This example shows how to create an application with several arguments using usage strings, which can be
8 | // far less verbose that shown in 01b_QuickExample.rs, but is more readable. The downside is you cannot set
9 | // the more advanced configuration options using this method (well...actually you can, you'll see ;) )
10 | //
11 | // The example below is functionally identical to the 01b_quick_example.rs and 01c_quick_example.rs
12 | //
13 | // Create an application with 5 possible arguments (2 auto generated) and 2 subcommands (1 auto generated)
14 | // - A config file
15 | // + Uses "-c filename" or "--config filename"
16 | // - An output file
17 | // + A positional argument (i.e. "$ myapp output_filename")
18 | // - A debug flag
19 | // + Uses "-d" or "--debug"
20 | // + Allows multiple occurrences of such as "-dd" (for vary levels of debugging, as an example)
21 | // - A help flag (automatically generated by clap)
22 | // + Uses "-h" or "--help" (Only autogenerated if you do NOT specify your own "-h" or "--help")
23 | // - A version flag (automatically generated by clap)
24 | // + Uses "-V" or "--version" (Only autogenerated if you do NOT specify your own "-V" or "--version")
25 | // - A subcommand "test" (subcommands behave like their own apps, with their own arguments
26 | // + Used by "$ myapp test" with the following arguments
27 | // > A list flag
28 | // = Uses "-l" (usage is "$ myapp test -l"
29 | // > A help flag (automatically generated by clap
30 | // = Uses "-h" or "--help" (full usage "$ myapp test -h" or "$ myapp test --help")
31 | // > A version flag (automatically generated by clap
32 | // = Uses "-V" or "--version" (full usage "$ myapp test -V" or "$ myapp test --version")
33 | // - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own)
34 | // + Used by "$ myapp help" (same functionality as "-h" or "--help")
35 | let matches = App::new("MyApp")
36 | .version("1.0")
37 | .author("Kevin K. ")
38 | .about("Does awesome things")
39 | .args_from_usage("-c --config=[conf] 'Sets a custom config file'
40 | [output] 'Sets an optional output file'
41 | [debug]... -d 'Turn debugging information on'")
42 | .subcommand(SubCommand::with_name("test")
43 | .about("does testing things")
44 | .arg_from_usage("[list] -l 'lists test values'"))
45 | .get_matches();
46 |
47 | // You can check the value provided by positional arguments, or option arguments
48 | if let Some(o) = matches.value_of("output") {
49 | println!("Value for output: {}", o);
50 | }
51 |
52 | if let Some(c) = matches.value_of("config") {
53 | println!("Value for config: {}", c);
54 | }
55 |
56 | // You can see how many times a particular flag or argument occurred
57 | // Note, only flags can have multiple occurrences
58 | match matches.occurrences_of("debug") {
59 | 0 => println!("Debug mode is off"),
60 | 1 => println!("Debug mode is kind of on"),
61 | 2 => println!("Debug mode is on"),
62 | 3 | _ => println!("Don't be crazy"),
63 | }
64 |
65 | // You can check for the existence of subcommands, and if found use their
66 | // matches just as you would the top level app
67 | if let Some(ref matches) = matches.subcommand_matches("test") {
68 | // "$ myapp test" was run
69 | if matches.is_present("list") {
70 | // "$ myapp test -l" was run
71 | println!("Printing testing lists...");
72 | } else {
73 | println!("Not printing testing lists...");
74 | }
75 | }
76 |
77 |
78 | // Continued program logic goes here...
79 | }
80 |
--------------------------------------------------------------------------------
/examples/07_option_args.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg};
4 |
5 | fn main() {
6 |
7 | // Option arguments are those that take an additional value, such as "-c value". In clap they
8 | // support three types of specification, those with short() as "-o some", or those with long()
9 | // as "--option value" or "--option=value"
10 | //
11 | // Options also support a multiple setting, which is discussed in the example below.
12 | let matches = App::new("MyApp")
13 | // Regular App configuration goes here...
14 |
15 | // Assume we an application that accepts an input file via the "-i file"
16 | // or the "--input file" (as wel as "--input=file").
17 | // Below every setting supported by option arguments is discussed.
18 | // NOTE: You DO NOT need to specify each setting, only those which apply
19 | // to your particular case.
20 | .arg(Arg::with_name("input")
21 | .help("the input file to use") // Displayed when showing help info
22 | .takes_value(true) // MUST be set to true in order to be an "option" argument
23 | .short("i") // This argument is triggered with "-i"
24 | .long("input") // This argument is triggered with "--input"
25 | .multiple(true) // Set to true if you wish to allow multiple occurrences
26 | // such as "-i file -i other_file -i third_file"
27 | .required(true) // By default this argument MUST be present
28 | // NOTE: mutual exclusions take precedence over
29 | // required arguments
30 | .requires("config") // Says, "If the user uses "input", they MUST
31 | // also use this other 'config' arg too"
32 | // Can also specifiy a list using
33 | // requires_all(Vec<&str>)
34 | .conflicts_with("output") // Opposite of requires(), says "if the
35 | // user uses -a, they CANNOT use 'output'"
36 | // also has a conflicts_with_all(Vec<&str>)
37 | )
38 | // NOTE: In order to compile this example, comment out conflicts_with()
39 | // and requires() because we have not defined an "output" or "config"
40 | // argument.
41 | .get_matches();
42 |
43 | // We can find out whether or not "input" was used
44 | if matches.is_present("input") {
45 | println!("An input file was specified");
46 | }
47 |
48 | // We can also get the value for "input"
49 | //
50 | // NOTE: If we specified multiple(), this will only return the _FIRST_
51 | // occurrence
52 | if let Some(ref in_file) = matches.value_of("input") {
53 | println!("An input file: {}", in_file);
54 | }
55 |
56 | // If we specified the multiple() setting we can get all the values
57 | if let Some(ref in_v) = matches.values_of("input") {
58 | for in_file in in_v.iter() {
59 | println!("An input file: {}", in_file);
60 | }
61 | }
62 |
63 | // We can see how many times the option was used with the occurrences_of() method
64 | //
65 | // NOTE: Just like with flags, if we did not specify the multiple() setting this will only
66 | // return 1 no matter how many times the argument was used (unless it wasn't used at all, in
67 | // in which case 0 is returned)
68 | println!("The \"input\" argument was used {} times", matches.occurrences_of("input"));
69 |
70 | // Continued program logic goes here...
71 | }
72 |
--------------------------------------------------------------------------------
/examples/14_groups.rs:
--------------------------------------------------------------------------------
1 | /// `ArgGroup`s are a family of related arguments and way for you to say, "Any of these arguments".
2 | /// By placing arguments in a logical group, you can make easier requirement and exclusion rules
3 | /// intead of having to list each individually, or when you want a rule to apply "any but not all"
4 | /// arguments.
5 | ///
6 | /// For instance, you can make an entire ArgGroup required, this means that one (and *only* one)
7 | /// argument. from that group must be present. Using more than one argument from an ArgGroup causes
8 | /// a failure (graceful exit).
9 | ///
10 | /// You can also do things such as name an ArgGroup as a confliction or requirement, meaning any
11 | /// of the arguments that belong to that group will cause a failure if present, or must present
12 | /// respectively.
13 | ///
14 | /// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
15 | /// present out of a given set. Imagine that you had multiple arguments, and you want one of them to
16 | /// be required, but making all of them required isn't feasible because perhaps they conflict with
17 | /// each other. For example, lets say that you were building an application where one could set a
18 | /// given version number by supplying a string with an option argument, i.e. `--set-ver v1.2.3`, you
19 | /// also wanted to support automatically using a previous version number and simply incrementing one
20 | /// of the three numbers. So you create three flags `--major`, `--minor`, and `--patch`. All of
21 | /// these arguments shouldn't be used at one time but you want to specify that *at least one* of
22 | /// them is used. For this, you can create a group.
23 |
24 | extern crate clap;
25 |
26 | use clap::{App, Arg, ArgGroup};
27 |
28 | fn main() {
29 | // Create application like normal
30 | let matches = App::new("myapp")
31 | // Add the version arguments
32 | .args_from_usage("--set-ver [ver] 'set version manually'
33 | --major 'auto inc major'
34 | --minor 'auto inc minor'
35 | --patch 'auto inc patch'")
36 | // Create a group, make it required, and add the above arguments
37 | .arg_group(ArgGroup::with_name("vers")
38 | .required(true)
39 | .add_all(&["vers", "major", "minor", "patch"]))
40 | // Arguments can also be added to a group individually, these two arguments
41 | // are part of the "input" group which is not required
42 | .arg(Arg::from_usage("[INPUT_FILE] 'some regular input'").group("input"))
43 | .arg(Arg::from_usage("--spec-in [SPEC_IN] 'some special input argument'").group("input"))
44 | // Now let's assume we have a -c [config] argument which requires one of
45 | // (but **not** both) the "input" arguments
46 | .arg(Arg::with_name("config").short("c").takes_value(true).requires("input"))
47 | .get_matches();
48 |
49 | // Let's assume the old version 1.2.3
50 | let mut major = 1;
51 | let mut minor = 2;
52 | let mut patch = 3;
53 |
54 | // See if --set-ver was used to set the version manually
55 | let version = if let Some(ver) = matches.value_of("ver") {
56 | format!("{}", ver)
57 | } else {
58 | // Increment the one requested (in a real program, we'd reset the lower numbers)
59 | let (maj, min, pat) = (matches.is_present("major"),
60 | matches.is_present("minor"),
61 | matches.is_present("patch"));
62 | match (maj, min, pat) {
63 | (true, _, _) => major += 1,
64 | (_, true, _) => minor += 1,
65 | (_, _, true) => patch += 1,
66 | _ => unreachable!(),
67 | };
68 | format!("{}.{}.{}", major, minor, patch)
69 | };
70 |
71 | println!("Version: {}", version);
72 |
73 | // Check for usage of -c
74 | if matches.is_present("config") {
75 | let input = matches.value_of("INPUT_FILE").unwrap_or(matches.value_of("SPEC_IN").unwrap());
76 | println!("Doing work using input {} and config {}",
77 | input,
78 | matches.value_of("config").unwrap());
79 | }
80 |
81 |
82 | }
--------------------------------------------------------------------------------
/src/args/argbuilder/option.rs:
--------------------------------------------------------------------------------
1 | use std::rc::Rc;
2 | use std::collections::BTreeSet;
3 | use std::fmt::{Display, Formatter, Result};
4 | use std::result::Result as StdResult;
5 |
6 | pub struct OptBuilder<'n> {
7 | pub name: &'n str,
8 | /// The short version (i.e. single character) of the argument, no preceding `-`
9 | pub short: Option,
10 | /// The long version of the flag (i.e. word) without the preceding `--`
11 | pub long: Option<&'n str>,
12 | /// The string of text that will displayed to the user when the application's
13 | /// `help` text is displayed
14 | pub help: Option<&'n str>,
15 | /// Allow multiple occurrences of an option argument such as "-c some -c other"
16 | pub multiple: bool,
17 | /// A list of names for other arguments that *may not* be used with this flag
18 | pub blacklist: Option>,
19 | /// If this is a required by default when using the command line program
20 | /// i.e. a configuration file that's required for the program to function
21 | /// **NOTE:** required by default means, it is required *until* mutually
22 | /// exclusive arguments are evaluated.
23 | pub required: bool,
24 | /// A list of possible values for this argument
25 | pub possible_vals: Option>,
26 | /// A list of names of other arguments that are *required* to be used when
27 | /// this flag is used
28 | pub requires: Option>,
29 | pub num_vals: Option,
30 | pub min_vals: Option,
31 | pub max_vals: Option,
32 | pub val_names: Option>,
33 | pub empty_vals: bool,
34 | pub global: bool,
35 | pub validator: Option StdResult<(), String>>>,
36 | /// A list of names for other arguments that *mutually override* this flag
37 | pub overrides: Option>,
38 | pub hidden: bool
39 | }
40 |
41 | impl<'n> Display for OptBuilder<'n> {
42 | fn fmt(&self,
43 | f: &mut Formatter)
44 | -> Result {
45 | // Write the name such --long or -l
46 | if let Some(l) = self.long {
47 | try!(write!(f, "--{}", l));
48 | } else {
49 | try!(write!(f, "-{}", self.short.unwrap()));
50 | }
51 |
52 | // Write the values such as
53 | if let Some(ref vec) = self.val_names {
54 | for n in vec.iter() {
55 | try!(write!(f, " <{}>", n));
56 | }
57 | } else {
58 | let num = self.num_vals.unwrap_or(1);
59 | for _ in (0..num) {
60 | try!(write!(f, " <{}>", self.name));
61 | }
62 | if self.multiple && num == 1 {
63 | try!(write!(f, "..."));
64 | }
65 | }
66 |
67 | Ok(())
68 | }
69 | }
70 |
71 | #[cfg(test)]
72 | mod test {
73 | use super::OptBuilder;
74 | use std::collections::BTreeSet;
75 |
76 | #[test]
77 | fn optbuilder_display() {
78 | let o = OptBuilder {
79 | name: "opt",
80 | short: None,
81 | long: Some("option"),
82 | help: None,
83 | multiple: true,
84 | blacklist: None,
85 | required: false,
86 | possible_vals: None,
87 | requires: None,
88 | num_vals: None,
89 | min_vals: None,
90 | max_vals: None,
91 | val_names: None,
92 | empty_vals: true,
93 | global: false,
94 | validator: None,
95 | overrides: None,
96 | hidden: false,
97 | };
98 |
99 | assert_eq!(&*format!("{}", o), "--option ...");
100 |
101 | let mut v_names = BTreeSet::new();
102 | v_names.insert("file");
103 | v_names.insert("name");
104 |
105 | let o2 = OptBuilder {
106 | name: "opt",
107 | short: Some('o'),
108 | long: None,
109 | help: None,
110 | multiple: false,
111 | blacklist: None,
112 | required: false,
113 | possible_vals: None,
114 | requires: None,
115 | num_vals: None,
116 | min_vals: None,
117 | max_vals: None,
118 | val_names: Some(v_names),
119 | empty_vals: true,
120 | global: false,
121 | validator: None,
122 | overrides: None,
123 | hidden: false,
124 | };
125 |
126 | assert_eq!(&*format!("{}", o2), "-o ");
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/examples/01b_quick_example.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg, SubCommand};
4 |
5 | fn main() {
6 |
7 | // This method shows the traditional, and slightly more configurable way to set up arguments. This method is
8 | // more verbose, but allows setting more configuration options, and even supports easier dynamic generation.
9 | //
10 | // The example below is functionally identical to the 01a_quick_example.rs and 01c_quick_example.rs
11 | //
12 | // *NOTE:* You can actually achieve the best of both worlds by using Arg::from_usage() (instead of Arg::with_name())
13 | // and *then* setting any additional properties.
14 | //
15 | // Create an application with 5 possible arguments (2 auto generated) and 2 subcommands (1 auto generated)
16 | // - A config file
17 | // + Uses "-c filename" or "--config filename"
18 | // - An output file
19 | // + A positional argument (i.e. "$ myapp output_filename")
20 | // - A debug flag
21 | // + Uses "-d" or "--debug"
22 | // + Allows multiple occurrences of such as "-dd" (for vary levels of debugging, as an example)
23 | // - A help flag (automatically generated by clap)
24 | // + Uses "-h" or "--help" (Only autogenerated if you do NOT specify your own "-h" or "--help")
25 | // - A version flag (automatically generated by clap)
26 | // + Uses "-V" or "--version" (Only autogenerated if you do NOT specify your own "-V" or "--version")
27 | // - A subcommand "test" (subcommands behave like their own apps, with their own arguments
28 | // + Used by "$ myapp test" with the following arguments
29 | // > A list flag
30 | // = Uses "-l" (usage is "$ myapp test -l"
31 | // > A help flag (automatically generated by clap
32 | // = Uses "-h" or "--help" (full usage "$ myapp test -h" or "$ myapp test --help")
33 | // > A version flag (automatically generated by clap
34 | // = Uses "-V" or "--version" (full usage "$ myapp test -V" or "$ myapp test --version")
35 | // - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own)
36 | // + Used by "$ myapp help" (same functionality as "-h" or "--help")
37 | let matches = App::new("MyApp")
38 | .version("1.0")
39 | .author("Kevin K. ")
40 | .about("Does awesome things")
41 | .arg(Arg::with_name("config")
42 | .short("c")
43 | .long("config")
44 | .help("Sets a custom config file")
45 | .takes_value(true))
46 | .arg(Arg::with_name("output")
47 | .help("Sets an optional output file")
48 | .index(1))
49 | .arg(Arg::with_name("debug")
50 | .short("d")
51 | .multiple(true)
52 | .help("Turn debugging information on"))
53 | .subcommand(SubCommand::with_name("test")
54 | .about("does testing things")
55 | .arg(Arg::with_name("list")
56 | .short("l")
57 | .help("lists test values")))
58 | .get_matches();
59 |
60 | // You can check the value provided by positional arguments, or option arguments
61 | if let Some(o) = matches.value_of("output") {
62 | println!("Value for output: {}", o);
63 | }
64 |
65 | if let Some(c) = matches.value_of("config") {
66 | println!("Value for config: {}", c);
67 | }
68 |
69 | // You can see how many times a particular flag or argument occurred
70 | // Note, only flags can have multiple occurrences
71 | match matches.occurrences_of("debug") {
72 | 0 => println!("Debug mode is off"),
73 | 1 => println!("Debug mode is kind of on"),
74 | 2 => println!("Debug mode is on"),
75 | 3 | _ => println!("Don't be crazy"),
76 | }
77 |
78 | // You can check for the existence of subcommands, and if found use their
79 | // matches just as you would the top level app
80 | if let Some(ref matches) = matches.subcommand_matches("test") {
81 | // "$ myapp test" was run
82 | if matches.is_present("list") {
83 | // "$ myapp test -l" was run
84 | println!("Printing testing lists...");
85 | } else {
86 | println!("Not printing testing lists...");
87 | }
88 | }
89 |
90 |
91 | // Continued program logic goes here...
92 | }
93 |
--------------------------------------------------------------------------------
/examples/03_args.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg};
4 |
5 | fn main() {
6 | // Args describe a possible valid argument which may be supplied by the user at runtime. There
7 | // are three different types of arguments (flags, options, and positional) as well as a fourth
8 | // special type of argument, called SubCommands (which will be discussed separately).
9 | //
10 | // Args are described in the same manner as Apps using the "builder pattern" with multiple
11 | // methods describing various settings for the individual arguments. Or by supplying a "usage"
12 | // string. Both methods have their pros and cons.
13 | //
14 | // Arguments can be added to applications in two manners, one at a time with the arg(), and
15 | // arg_from_usage() method, or multiple arguments at once via a Vec inside the args() method,
16 | // or a single &str describing multiple Args (one per line) supplied to args_from_usage().
17 | //
18 | // There are various options which can be set for a given argument, some apply to any of the
19 | // three types of arguments, some only apply one or two of the types. *NOTE* if you set
20 | // incompatible options on a single argument, clap will panic! at runtime. This is by design,
21 | // so that you know right away an error was made by the developer, not the end user.
22 | //
23 | // # Help and Version
24 | // clap automatically generates a help and version flag for you, unless you specificy your
25 | // own. By default help uses "-h" and "--help", and version uses "-V" and "--version". You can
26 | // safely overide "-V" and "-h" to your own arguments, and "--help" and "--version" will stil
27 | // be automatically generated for you.
28 | let matches = App::new("MyApp")
29 | // All application settings go here...
30 |
31 | // A simple "Flag" argument example (i.e. "-d") using the builder pattern
32 | .arg(Arg::with_name("debug")
33 | .help("turn on debugging information")
34 | .short("d"))
35 |
36 | // Two arguments, one "Option" argument (i.e. one that takes a value) such
37 | // as "-c some", and one positional argument (i.e. "myapp some_file")
38 | .args( vec![
39 | Arg::with_name("config")
40 | .help("sets the config file to use")
41 | .takes_value(true)
42 | .short("c")
43 | .long("config"),
44 | Arg::with_name("input")
45 | .help("the input file to use")
46 | .index(1)
47 | .required(true)
48 | ])
49 |
50 | // *Note* the following two examples are convienience methods, if you wish
51 | // to still get the full configurability of Arg::with_name() and the readability
52 | // of arg_from_usage(), you can instantiate a new Arg with Arg::from_usage() and
53 | // still be able to set all the additional properties, just like Arg::with_name()
54 | //
55 | //
56 | // One "Flag" using a usage string
57 | .arg_from_usage("--license 'display the license file'")
58 |
59 | // Two args, one "Positional", and one "Option" using a usage string
60 | .args_from_usage("[output] 'Supply an output file to use'
61 | -i --int=[interface] 'Set an interface to use'")
62 | .get_matches();
63 |
64 | // Here are some examples of using the arguments defined above. Keep in mind that this is only
65 | // an example, and may be somewhat contrived
66 | //
67 | // First we check if debugging should be on or not
68 | println!("Debugging mode is: {}", if matches.is_present("debug") { "ON" } else { "OFF" });
69 |
70 | // Next we print the config file we're using, if any was defined with either -c or
71 | // --config
72 | if let Some(config) = matches.value_of("config") {
73 | println!("A config file was passed in: {}", config);
74 | }
75 |
76 | // Let's print the file the user passed in. We can use .unwrap() here becase the arg is
77 | // required, and parsing would have failed if the user forgot it
78 | println!("Using input file: {}", matches.value_of("input").unwrap());
79 |
80 | // We could continue checking for and using arguments in this manner, such as "license",
81 | // "output", and "interface". Keep in mind that "output" and "interface" are optional, so you
82 | // shouldn't call .unwrap(), instead prefer using an 'if let' expression as we did with
83 | // "config"
84 | }
85 |
--------------------------------------------------------------------------------
/src/usageparser.rs:
--------------------------------------------------------------------------------
1 | use std::str::Chars;
2 |
3 | pub enum UsageToken<'u> {
4 | Name(&'u str, Option),
5 | Short(char),
6 | Long(&'u str),
7 | Help(&'u str),
8 | Multiple,
9 | }
10 |
11 | pub struct UsageParser<'u> {
12 | usage: &'u str,
13 | chars: Chars<'u>,
14 | s: usize,
15 | e: usize,
16 | }
17 |
18 | impl<'u> UsageParser<'u> {
19 | pub fn with_usage(u: &'u str) -> UsageParser<'u> {
20 | UsageParser {
21 | usage: u,
22 | chars: u.chars(),
23 | s: 0,
24 | e: 0,
25 | }
26 | }
27 |
28 |
29 | }
30 |
31 | impl<'u> Iterator for UsageParser<'u> {
32 | type Item = UsageToken<'u>;
33 |
34 | fn next(&mut self) -> Option> {
35 | loop {
36 | match self.chars.next() {
37 | Some(c) if c == '[' || c == '<' => {
38 | // self.s = self.e + 1;
39 | if self.e != 0 {
40 | self.e += 1;
41 | }
42 | self.s = self.e + 1;
43 | let closing = match c {
44 | '[' => ']',
45 | '<' => '>',
46 | _ => unreachable!(),
47 | };
48 | while let Some(c) = self.chars.next() {
49 | self.e += 1;
50 | if c == closing {
51 | break
52 | }
53 | }
54 | if self.e > self.usage.len() {
55 | return None
56 | }
57 |
58 | let name = &self.usage[self.s..self.e];
59 |
60 | return Some(UsageToken::Name(name, if c == '<' { Some(true) } else { None }));
61 | }
62 | Some('\'') => {
63 | self.s = self.e + 2;
64 | self.e = self.usage.len() - 1;
65 |
66 | while let Some(_) = self.chars.next() {
67 | continue
68 | }
69 |
70 | return Some(UsageToken::Help(&self.usage[self.s..self.e]));
71 | }
72 | Some('-') => {
73 | self.e += 1;
74 | match self.chars.next() {
75 | Some('-') => {
76 | if self.e != 1 {
77 | self.e += 1;
78 | }
79 |
80 | self.s = self.e + 1;
81 |
82 | while let Some(c) = self.chars.next() {
83 | self.e += 1;
84 | if c == ' ' || c == '=' || c == '.' {
85 | break
86 | }
87 | }
88 | if self.e > self.usage.len() {
89 | return None
90 | }
91 |
92 | if self.e == self.usage.len() - 1 {
93 | return Some(UsageToken::Long(&self.usage[self.s..]))
94 | }
95 | return Some(UsageToken::Long(&self.usage[self.s..self.e]))
96 | }
97 | Some(c) => {
98 | // When short is first don't increment e
99 | if self.e != 1 {
100 | self.e += 1;
101 | }
102 | // Short
103 | if !c.is_alphanumeric() {
104 | return None
105 | }
106 | return Some(UsageToken::Short(c))
107 | }
108 | _ => {
109 | return None
110 | }
111 | }
112 | }
113 | Some('.') => {
114 | self.e += 1;
115 | let mut mult = false;
116 | for _ in 0..2 {
117 | self.e += 1;
118 | match self.chars.next() {
119 | // longs consume one '.' so they match '.. ' whereas shorts can
120 | // match '...'
121 | Some('.') | Some(' ') => {
122 | mult = true;
123 | }
124 | _ => {
125 | // if there is no help or following space all we can match is '..'
126 | if self.e == self.usage.len() - 1 {
127 | mult = true;
128 | }
129 | break;
130 | }
131 | }
132 | }
133 | if mult {
134 | return Some(UsageToken::Multiple)
135 | }
136 | }
137 | Some(' ') | Some('=') | Some(']') | Some('>') | Some('\t') | Some(',') => {
138 | self.e += 1;
139 | continue
140 | }
141 | None => {
142 | return None
143 | }
144 | Some(c) => panic!("Usage parser error, unexpected \
145 | \"{}\" at \"{}\", check from_usage call", c, self.usage),
146 | }
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/tests/require.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg, ClapErrorType, ArgGroup};
4 |
5 | #[test]
6 | fn flag_required() {
7 | let result = App::new("flag_required")
8 | .arg(Arg::from_usage("-f, --flag 'some flag'")
9 | .requires("color"))
10 | .arg(Arg::from_usage("-c, --color 'third flag'"))
11 | .get_matches_from_safe(vec!["", "-f"]);
12 | assert!(result.is_err());
13 | let err = result.err().unwrap();
14 | assert_eq!(err.error_type, ClapErrorType::MissingRequiredArgument);
15 | }
16 |
17 | #[test]
18 | fn flag_required_2() {
19 | let m = App::new("flag_required")
20 | .arg(Arg::from_usage("-f, --flag 'some flag'")
21 | .requires("color"))
22 | .arg(Arg::from_usage("-c, --color 'third flag'"))
23 | .get_matches_from(vec!["", "-f", "-c"]);
24 | assert!(m.is_present("color"));
25 | assert!(m.is_present("flag"));
26 | }
27 |
28 | #[test]
29 | fn option_required() {
30 | let result = App::new("option_required")
31 | .arg(Arg::from_usage("-f [flag] 'some flag'")
32 | .requires("color"))
33 | .arg(Arg::from_usage("-c [color] 'third flag'"))
34 | .get_matches_from_safe(vec!["", "-f", "val"]);
35 | assert!(result.is_err());
36 | let err = result.err().unwrap();
37 | assert_eq!(err.error_type, ClapErrorType::MissingRequiredArgument);
38 | }
39 |
40 | #[test]
41 | fn option_required_2() {
42 | let m = App::new("option_required")
43 | .arg(Arg::from_usage("-f [flag] 'some flag'")
44 | .requires("color"))
45 | .arg(Arg::from_usage("-c [color] 'third flag'"))
46 | .get_matches_from(vec!["", "-f", "val", "-c", "other_val"]);
47 | assert!(m.is_present("color"));
48 | assert_eq!(m.value_of("color").unwrap(), "other_val");
49 | assert!(m.is_present("flag"));
50 | assert_eq!(m.value_of("flag").unwrap(), "val");
51 | }
52 |
53 | #[test]
54 | fn positional_required() {
55 | let result = App::new("positional_required")
56 | .arg(Arg::with_name("flag")
57 | .index(1)
58 | .required(true))
59 | .get_matches_from_safe(vec![""]);
60 | assert!(result.is_err());
61 | let err = result.err().unwrap();
62 | assert_eq!(err.error_type, ClapErrorType::MissingRequiredArgument);
63 | }
64 |
65 | #[test]
66 | fn positional_required_2() {
67 | let m = App::new("positional_required")
68 | .arg(Arg::with_name("flag")
69 | .index(1)
70 | .required(true))
71 | .get_matches_from(vec!["", "someval"]);
72 | assert!(m.is_present("flag"));
73 | assert_eq!(m.value_of("flag").unwrap(), "someval");
74 | }
75 |
76 | #[test]
77 | fn group_required() {
78 | let result = App::new("group_required")
79 | .arg(Arg::from_usage("-f, --flag 'some flag'"))
80 | .arg_group(ArgGroup::with_name("gr")
81 | .required(true)
82 | .add("some")
83 | .add("other"))
84 | .arg(Arg::from_usage("--some 'some arg'"))
85 | .arg(Arg::from_usage("--other 'other arg'"))
86 | .get_matches_from_safe(vec!["", "-f"]);
87 | assert!(result.is_err());
88 | let err = result.err().unwrap();
89 | assert_eq!(err.error_type, ClapErrorType::MissingRequiredArgument);
90 | }
91 |
92 | #[test]
93 | fn group_required_2() {
94 | let m = App::new("group_required")
95 | .arg(Arg::from_usage("-f, --flag 'some flag'"))
96 | .arg_group(ArgGroup::with_name("gr")
97 | .required(true)
98 | .add("some")
99 | .add("other"))
100 | .arg(Arg::from_usage("--some 'some arg'"))
101 | .arg(Arg::from_usage("--other 'other arg'"))
102 | .get_matches_from(vec!["", "-f", "--some"]);
103 | assert!(m.is_present("some"));
104 | assert!(!m.is_present("other"));
105 | assert!(m.is_present("flag"));
106 | }
107 |
108 | #[test]
109 | fn group_required_3() {
110 | let m = App::new("group_required")
111 | .arg(Arg::from_usage("-f, --flag 'some flag'"))
112 | .arg_group(ArgGroup::with_name("gr")
113 | .required(true)
114 | .add("some")
115 | .add("other"))
116 | .arg(Arg::from_usage("--some 'some arg'"))
117 | .arg(Arg::from_usage("--other 'other arg'"))
118 | .get_matches_from(vec!["", "-f", "--other"]);
119 | assert!(!m.is_present("some"));
120 | assert!(m.is_present("other"));
121 | assert!(m.is_present("flag"));
122 | }
123 |
124 | #[test]
125 | fn arg_require_group() {
126 | let result = App::new("arg_require_group")
127 | .arg(Arg::from_usage("-f, --flag 'some flag'")
128 | .requires("gr"))
129 | .arg_group(ArgGroup::with_name("gr")
130 | .add("some")
131 | .add("other"))
132 | .arg(Arg::from_usage("--some 'some arg'"))
133 | .arg(Arg::from_usage("--other 'other arg'"))
134 | .get_matches_from_safe(vec!["", "-f"]);
135 | assert!(result.is_err());
136 | let err = result.err().unwrap();
137 | assert_eq!(err.error_type, ClapErrorType::MissingRequiredArgument);
138 | }
139 |
140 | #[test]
141 | fn arg_require_group_2() {
142 | let m = App::new("arg_require_group")
143 | .arg(Arg::from_usage("-f, --flag 'some flag'")
144 | .requires("gr"))
145 | .arg_group(ArgGroup::with_name("gr")
146 | .add("some")
147 | .add("other"))
148 | .arg(Arg::from_usage("--some 'some arg'"))
149 | .arg(Arg::from_usage("--other 'other arg'"))
150 | .get_matches_from(vec!["", "-f", "--some"]);
151 | assert!(m.is_present("some"));
152 | assert!(!m.is_present("other"));
153 | assert!(m.is_present("flag"));
154 | }
155 |
156 | #[test]
157 | fn arg_require_group_3() {
158 | let m = App::new("arg_require_group")
159 | .arg(Arg::from_usage("-f, --flag 'some flag'")
160 | .requires("gr"))
161 | .arg_group(ArgGroup::with_name("gr")
162 | .add("some")
163 | .add("other"))
164 | .arg(Arg::from_usage("--some 'some arg'"))
165 | .arg(Arg::from_usage("--other 'other arg'"))
166 | .get_matches_from(vec!["", "-f", "--other"]);
167 | assert!(!m.is_present("some"));
168 | assert!(m.is_present("other"));
169 | assert!(m.is_present("flag"));
170 | }
--------------------------------------------------------------------------------
/clap-tests/src/main.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | extern crate clap;
3 |
4 | use clap::{App, Arg, SubCommand};
5 |
6 |
7 | fn main() {
8 | let m_val_names = ["one", "two"];
9 | let args = "-o --option=[opt]... 'tests options'
10 | [positional] 'tests positionals'";
11 | let opt3_vals = ["fast", "slow"];
12 | let pos3_vals = ["vi", "emacs"];
13 | let matches = App::new("claptests")
14 | // Test version from Cargo.toml
15 | .version(&crate_version!()[..])
16 | .about("tests clap library")
17 | .author("Kevin K. ")
18 | .args_from_usage(args)
19 | .arg(Arg::from_usage("-f --flag... 'tests flags'")
20 | .global(true))
21 | .args(vec![
22 | Arg::from_usage("[flag2] -F 'tests flags with exclusions'").conflicts_with("flag").requires("option2"),
23 | Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").conflicts_with("option").requires("positional2"),
24 | Arg::from_usage("[positional2] 'tests positionals with exclusions'"),
25 | Arg::from_usage("-O --Option [option3] 'tests options with specific value sets'").possible_values(&opt3_vals),
26 | Arg::from_usage("[positional3]... 'tests positionals with specific values'").possible_values(&pos3_vals),
27 | Arg::from_usage("--multvals [multvals] 'Tests mutliple values, not mult occs'").value_names(&m_val_names),
28 | Arg::from_usage("--multvalsmo [multvalsmo]... 'Tests mutliple values, not mult occs'").value_names(&m_val_names),
29 | Arg::from_usage("--minvals2 [minvals]... 'Tests 2 min vals'").min_values(2),
30 | Arg::from_usage("--maxvals3 [maxvals]... 'Tests 3 max vals'").max_values(3)
31 | ])
32 | .subcommand(SubCommand::with_name("subcmd")
33 | .about("tests subcommands")
34 | .version("0.1")
35 | .author("Kevin K. ")
36 | .arg_from_usage("-o --option [scoption]... 'tests options'")
37 | .arg_from_usage("[scpositional] 'tests positionals'"))
38 | .get_matches();
39 |
40 | if matches.is_present("flag") {
41 | println!("flag present {} times", matches.occurrences_of("flag"));
42 | } else {
43 | println!("flag NOT present");
44 | }
45 |
46 | if matches.is_present("opt") {
47 | if let Some(v) = matches.value_of("opt") {
48 | println!("option present {} times with value: {}",matches.occurrences_of("opt"), v);
49 | }
50 | if let Some(ref ov) = matches.values_of("opt") {
51 | for o in ov {
52 | println!("An option: {}", o);
53 | }
54 | }
55 | } else {
56 | println!("option NOT present");
57 | }
58 |
59 | if let Some(p) = matches.value_of("positional") {
60 | println!("positional present with value: {}", p);
61 | } else {
62 | println!("positional NOT present");
63 | }
64 |
65 | if matches.is_present("flag2") {
66 | println!("flag2 present");
67 | println!("option2 present with value of: {}", matches.value_of("option2").unwrap());
68 | println!("positional2 present with value of: {}", matches.value_of("positional2").unwrap());
69 | } else {
70 | println!("flag2 NOT present");
71 | println!("option2 maybe present with value of: {}", matches.value_of("option2").unwrap_or("Nothing"));
72 | println!("positional2 maybe present with value of: {}", matches.value_of("positional2").unwrap_or("Nothing"));
73 | }
74 |
75 | match matches.value_of("option3").unwrap_or("") {
76 | "fast" => println!("option3 present quickly"),
77 | "slow" => println!("option3 present slowly"),
78 | _ => println!("option3 NOT present")
79 | }
80 |
81 | match matches.value_of("positional3").unwrap_or("") {
82 | "vi" => println!("positional3 present in vi mode"),
83 | "emacs" => println!("positional3 present in emacs mode"),
84 | _ => println!("positional3 NOT present")
85 | }
86 |
87 | if matches.is_present("opt") {
88 | if let Some(v) = matches.value_of("opt") {
89 | println!("option present {} times with value: {}",matches.occurrences_of("opt"), v);
90 | }
91 | if let Some(ref ov) = matches.values_of("opt") {
92 | for o in ov {
93 | println!("An option: {}", o);
94 | }
95 | }
96 | } else {
97 | println!("option NOT present");
98 | }
99 |
100 | if let Some(p) = matches.value_of("positional") {
101 | println!("positional present with value: {}", p);
102 | } else {
103 | println!("positional NOT present");
104 | }
105 | if matches.is_present("subcmd") {
106 | println!("subcmd present");
107 | if let Some(matches) = matches.subcommand_matches("subcmd") {
108 | if matches.is_present("flag") {
109 | println!("flag present {} times", matches.occurrences_of("flag"));
110 | } else {
111 | println!("flag NOT present");
112 | }
113 |
114 | if matches.is_present("scoption") {
115 | if let Some(v) = matches.value_of("scoption") {
116 | println!("scoption present with value: {}", v);
117 | }
118 | if let Some(ref ov) = matches.values_of("scoption") {
119 | for o in ov {
120 | println!("An scoption: {}", o);
121 | }
122 | }
123 | } else {
124 | println!("scoption NOT present");
125 | }
126 |
127 | if let Some(p) = matches.value_of("scpositional") {
128 | println!("scpositional present with value: {}", p);
129 | }
130 | }
131 | } else {
132 | println!("subcmd NOT present");
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/app/settings.rs:
--------------------------------------------------------------------------------
1 | use std::str::FromStr;
2 | use std::ascii::AsciiExt;
3 |
4 | /// Application level settings, which affect how `App` operates
5 | #[derive(PartialEq, Debug)]
6 | pub enum AppSettings {
7 | /// Allows subcommands to override all requirements of the parent (this command). For example
8 | /// if you had a subcommand or even top level application which had a required arguments that
9 | /// are only required as long as there is no subcommand present.
10 | ///
11 | /// **NOTE:** This defaults to false (using subcommand does *not* negate requirements)
12 | ///
13 | /// # Example
14 | ///
15 | /// ```no_run
16 | /// # use clap::{App, AppSettings};
17 | /// App::new("myprog")
18 | /// .setting(AppSettings::SubcommandsNegateReqs)
19 | /// # ;
20 | /// ```
21 | SubcommandsNegateReqs,
22 | /// Allows specifying that if no subcommand is present at runtime, error and exit gracefully
23 | ///
24 | /// **NOTE:** This defaults to false (subcommands do *not* need to be present)
25 | ///
26 | /// # Example
27 | ///
28 | /// ```no_run
29 | /// # use clap::{App, AppSettings};
30 | /// App::new("myprog")
31 | /// .setting(AppSettings::SubcommandRequired)
32 | /// # ;
33 | /// ```
34 | SubcommandRequired,
35 | /// Specifies that the help text sould be displayed (and then exit gracefully), if no
36 | /// arguments are present at runtime (i.e. an empty run such as, `$ myprog`.
37 | ///
38 | /// **NOTE:** Subcommands count as arguments
39 | ///
40 | /// # Example
41 | ///
42 | /// ```no_run
43 | /// # use clap::{App, AppSettings};
44 | /// App::new("myprog")
45 | /// .setting(AppSettings::ArgRequiredElseHelp)
46 | /// # ;
47 | /// ```
48 | ArgRequiredElseHelp,
49 | /// Uses version of the current command for all subcommands. (Defaults to false; subcommands
50 | /// have independant version strings)
51 | ///
52 | /// **NOTE:** The version for the current command and this setting must be set **prior** to
53 | /// adding any subcommands
54 | ///
55 | /// # Example
56 | ///
57 | /// ```no_run
58 | /// # use clap::{App, Arg, SubCommand, AppSettings};
59 | /// App::new("myprog")
60 | /// .version("v1.1")
61 | /// .setting(AppSettings::GlobalVersion)
62 | /// .subcommand(SubCommand::with_name("test"))
63 | /// .get_matches();
64 | /// // running `myprog test --version` will display
65 | /// // "myprog-test v1.1"
66 | /// ```
67 | GlobalVersion,
68 | /// Disables `-V` and `--version` for all subcommands (Defaults to false; subcommands have
69 | /// version flags)
70 | ///
71 | /// **NOTE:** This setting must be set **prior** adding any subcommands
72 | ///
73 | /// **NOTE:** Do not set this value to false, it will have undesired results!
74 | ///
75 | /// # Example
76 | ///
77 | /// ```no_run
78 | /// # use clap::{App, Arg, SubCommand, AppSettings};
79 | /// App::new("myprog")
80 | /// .version("v1.1")
81 | /// .setting(AppSettings::VersionlessSubcommands)
82 | /// .subcommand(SubCommand::with_name("test"))
83 | /// .get_matches();
84 | /// // running `myprog test --version` will display unknown argument error
85 | /// ```
86 | VersionlessSubcommands,
87 | /// By default the auto-generated help message groups flags, options, and positional arguments
88 | /// separately. This setting disable that and groups flags and options together presenting a
89 | /// more unified help message (a la getopts or docopt style).
90 | ///
91 | /// **NOTE:** This setting is cosmetic only and does not affect any functionality.
92 | ///
93 | /// # Example
94 | ///
95 | /// ```no_run
96 | /// # use clap::{App, Arg, SubCommand, AppSettings};
97 | /// App::new("myprog")
98 | /// .setting(AppSettings::UnifiedHelpMessage)
99 | /// .get_matches();
100 | /// // running `myprog --help` will display a unified "docopt" or "getopts" style help message
101 | /// ```
102 | UnifiedHelpMessage,
103 | /// Will display a message "Press [ENTER]/[RETURN] to continue..." and wait user before
104 | /// exiting
105 | ///
106 | /// This is most useful when writing an application which is run from a GUI shortcut, or on
107 | /// Windows where a user tries to open the binary by double-clicking instead of using the
108 | /// command line (i.e. set `.arg_required_else_help(true)` and `.wait_on_error(true)` to
109 | /// display the help in such a case).
110 | ///
111 | /// **NOTE:** This setting is **not** recursive with subcommands, meaning if you wish this
112 | /// behavior for all subcommands, you must set this on each command (needing this is extremely
113 | /// rare)
114 | ///
115 | /// # Example
116 | ///
117 | /// ```no_run
118 | /// # use clap::{App, Arg, AppSettings};
119 | /// App::new("myprog")
120 | /// .setting(AppSettings::WaitOnError)
121 | /// # ;
122 | /// ```
123 | WaitOnError,
124 | /// Specifies that the help text sould be displayed (and then exit gracefully), if no
125 | /// subcommands are present at runtime (i.e. an empty run such as, `$ myprog`.
126 | ///
127 | /// **NOTE:** This should *not* be used with `.subcommand_required()` as they do the same
128 | /// thing, except one prints the help text, and one prints an error.
129 | ///
130 | /// **NOTE:** If the user specifies arguments at runtime, but no subcommand the help text will
131 | /// still be displayed and exit. If this is *not* the desired result, consider using
132 | /// `.arg_required_else_help()`
133 | ///
134 | /// # Example
135 | ///
136 | /// ```no_run
137 | /// # use clap::{App, Arg, AppSettings};
138 | /// App::new("myprog")
139 | /// .setting(AppSettings::SubcommandRequiredElseHelp)
140 | /// # ;
141 | /// ```
142 | SubcommandRequiredElseHelp,
143 | }
144 |
145 | impl FromStr for AppSettings {
146 | type Err = String;
147 | fn from_str(s: &str) -> Result::Err> {
148 | match &*s.to_ascii_lowercase() {
149 | "subcommandsnegatereqs" => Ok(AppSettings::SubcommandsNegateReqs),
150 | "subcommandsrequired" => Ok(AppSettings::SubcommandRequired),
151 | "argrequiredelsehelp" => Ok(AppSettings::ArgRequiredElseHelp),
152 | "globalversion" => Ok(AppSettings::GlobalVersion),
153 | "versionlesssubcommands" => Ok(AppSettings::VersionlessSubcommands),
154 | "unifiedhelpmessage" => Ok(AppSettings::UnifiedHelpMessage),
155 | "waitonerror" => Ok(AppSettings::WaitOnError),
156 | "subcommandrequiredelsehelp" => Ok(AppSettings::SubcommandRequiredElseHelp),
157 | _ => Err("unknown AppSetting, cannot convert from str".to_owned())
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/app/errors.rs:
--------------------------------------------------------------------------------
1 | use std::process;
2 | use std::error::Error;
3 | use std::fmt;
4 |
5 | /// Command line argument parser error types
6 | #[derive(PartialEq, Debug)]
7 | pub enum ClapErrorType {
8 | /// Error occurs when some possible values were set, but clap found unexpected value
9 | ///
10 | ///
11 | /// # Example
12 | ///
13 | /// ```no_run
14 | /// # use clap::{App, Arg};
15 | /// let result = App::new("myprog")
16 | /// .arg(Arg::with_name("debug").index(1)
17 | /// .possible_value("fast")
18 | /// .possible_value("slow"))
19 | /// .get_matches_from_safe(vec!["", "other"]);
20 | /// ```
21 | InvalidValue,
22 | /// Error occurs when clap found unexpected flag or option
23 | ///
24 | ///
25 | /// # Example
26 | ///
27 | /// ```no_run
28 | /// # use clap::{App, Arg};
29 | /// let result = App::new("myprog")
30 | /// .arg(Arg::from_usage("-f, --flag 'some flag'"))
31 | /// .get_matches_from_safe(vec!["", "--other"]);
32 | /// ```
33 | InvalidArgument,
34 | /// Error occurs when clap found unexpected subcommand
35 | ///
36 | ///
37 | /// # Example
38 | ///
39 | /// ```no_run
40 | /// # use clap::{App, Arg, SubCommand};
41 | /// let result = App::new("myprog")
42 | /// .subcommand(SubCommand::with_name("conifg")
43 | /// .about("Used for configuration")
44 | /// .arg(Arg::with_name("config_file")
45 | /// .help("The configuration file to use")
46 | /// .index(1)))
47 | /// .get_matches_from_safe(vec!["", "other"]);
48 | /// ```
49 | InvalidSubcommand,
50 | /// Error occurs when option does not allow empty values but some was found
51 | ///
52 | ///
53 | /// # Example
54 | ///
55 | /// ```no_run
56 | /// # use clap::{App, Arg};
57 | /// let result = App::new("myprog")
58 | /// .arg(Arg::with_name("debug")
59 | /// .empty_values(false))
60 | /// .arg(Arg::with_name("color"))
61 | /// .get_matches_from_safe(vec!["", "--debug", "--color"]);
62 | /// ```
63 | EmptyValue,
64 | /// Parser inner error
65 | OptionError,
66 | /// Parser inner error
67 | ArgumentError,
68 | /// Parser inner error
69 | ValueError,
70 | /// Error occurs when argument got more values then were expected
71 | ///
72 | ///
73 | /// # Example
74 | ///
75 | /// ```no_run
76 | /// # use clap::{App, Arg};
77 | /// let result = App::new("myprog")
78 | /// .arg(Arg::with_name("debug").index(1)
79 | /// .max_values(2))
80 | /// .get_matches_from_safe(vec!["", "too", "much", "values"]);
81 | /// ```
82 | TooMuchValues,
83 | /// Error occurs when argument got less values then were expected
84 | ///
85 | ///
86 | /// # Example
87 | ///
88 | /// ```no_run
89 | /// # use clap::{App, Arg};
90 | /// let result = App::new("myprog")
91 | /// .arg(Arg::with_name("debug").index(1)
92 | /// .min_values(3))
93 | /// .get_matches_from_safe(vec!["", "too", "few"]);
94 | /// ```
95 | TooFewValues,
96 | /// Error occurs when clap find two ore more conflicting arguments
97 | ///
98 | ///
99 | /// # Example
100 | ///
101 | /// ```no_run
102 | /// # use clap::{App, Arg};
103 | /// let result = App::new("myprog")
104 | /// .arg(Arg::with_name("debug")
105 | /// .conflicts_with("color"))
106 | /// .get_matches_from_safe(vec!["", "--debug", "--color"]);
107 | /// ```
108 | ArgumentConflict,
109 | /// Error occurs when one or more required arguments missing
110 | ///
111 | ///
112 | /// # Example
113 | ///
114 | /// ```no_run
115 | /// # use clap::{App, Arg};
116 | /// let result = App::new("myprog")
117 | /// .arg(Arg::with_name("debug")
118 | /// .required(true))
119 | /// .get_matches_from_safe(vec![""]);
120 | /// ```
121 | MissingRequiredArgument,
122 | /// Error occurs when required subcommand missing
123 | ///
124 | ///
125 | /// # Example
126 | ///
127 | /// ```no_run
128 | /// # use clap::{App, Arg, AppSettings, SubCommand};
129 | /// let result = App::new("myprog")
130 | /// .setting(AppSettings::SubcommandRequired)
131 | /// .subcommand(SubCommand::with_name("conifg")
132 | /// .about("Used for configuration")
133 | /// .arg(Arg::with_name("config_file")
134 | /// .help("The configuration file to use")
135 | /// .index(1)))
136 | /// .get_matches_from_safe(vec![""]);
137 | /// ```
138 | MissingSubcommand,
139 | /// Occurs when no argument or subcommand has been supplied and
140 | /// `AppSettings::ArgRequiredElseHelp` was used
141 | ///
142 | ///
143 | /// # Example
144 | ///
145 | /// ```no_run
146 | /// # use clap::{App, Arg, AppSettings, SubCommand};
147 | /// let result = App::new("myprog")
148 | /// .setting(AppSettings::ArgRequiredElseHelp)
149 | /// .subcommand(SubCommand::with_name("conifg")
150 | /// .about("Used for configuration")
151 | /// .arg(Arg::with_name("config_file")
152 | /// .help("The configuration file to use")
153 | /// .index(1)))
154 | /// .get_matches_from_safe(vec![""]);
155 | /// ```
156 | MissingArgumentOrSubcommand,
157 | /// Error occurs when clap find argument while is was not expecting any
158 | ///
159 | ///
160 | /// # Example
161 | ///
162 | /// ```no_run
163 | /// # use clap::{App};
164 | /// let result = App::new("myprog")
165 | /// .get_matches_from_safe(vec!["", "--arg"]);
166 | /// ```
167 | UnexpectedArgument,
168 | /// Error occurs when argument was used multiple times and was not set as multiple.
169 | ///
170 | ///
171 | /// # Example
172 | ///
173 | /// ```no_run
174 | /// # use clap::{App, Arg};
175 | /// let result = App::new("myprog")
176 | /// .arg(Arg::with_name("debug")
177 | /// .multiple(false))
178 | /// .get_matches_from_safe(vec!["", "--debug", "--debug"]);
179 | /// ```
180 | UnexpectedMultipleUsage,
181 | }
182 |
183 | /// Command line argument parser error
184 | #[derive(Debug)]
185 | pub struct ClapError {
186 | /// Formated error message
187 | pub error: String,
188 | /// Command line argument parser error type
189 | pub error_type: ClapErrorType,
190 | }
191 |
192 | impl ClapError {
193 | /// Prints the error to `stderr` and exits with a status of `1`
194 | pub fn exit(&self) -> ! {
195 | wlnerr!("{}", self.error);
196 | process::exit(1);
197 | }
198 | }
199 |
200 | impl Error for ClapError {
201 | fn description(&self) -> &str {
202 | &*self.error
203 | }
204 | }
205 |
206 | impl fmt::Display for ClapError {
207 | fn fmt(&self,
208 | f: &mut fmt::Formatter)
209 | -> fmt::Result {
210 | write!(f, "{}", self.error)
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/tests/posix_compatible.rs:
--------------------------------------------------------------------------------
1 | extern crate clap;
2 |
3 | use clap::{App, Arg, ClapErrorType};
4 |
5 | #[test]
6 | fn posix_compatible_flags_long() {
7 | let m = App::new("posix")
8 | .arg(Arg::from_usage("--flag 'some flag'").mutually_overrides_with("color"))
9 | .arg(Arg::from_usage("--color 'some other flag'"))
10 | .get_matches_from(vec!["", "--flag", "--color"]);
11 | assert!(m.is_present("color"));
12 | assert!(!m.is_present("flag"));
13 |
14 | let m = App::new("posix")
15 | .arg(Arg::from_usage("--flag 'some flag'").mutually_overrides_with("color"))
16 | .arg(Arg::from_usage("--color 'some other flag'"))
17 | .get_matches_from(vec!["", "--color", "--flag"]);
18 | assert!(!m.is_present("color"));
19 | assert!(m.is_present("flag"));
20 | }
21 |
22 | #[test]
23 | fn posix_compatible_flags_short() {
24 | let m = App::new("posix")
25 | .arg(Arg::from_usage("-f, --flag 'some flag'").mutually_overrides_with("color"))
26 | .arg(Arg::from_usage("-c, --color 'some other flag'"))
27 | .get_matches_from(vec!["", "-f", "-c"]);
28 | assert!(m.is_present("color"));
29 | assert!(!m.is_present("flag"));
30 |
31 | let m = App::new("posix")
32 | .arg(Arg::from_usage("-f, --flag 'some flag'").mutually_overrides_with("color"))
33 | .arg(Arg::from_usage("-c, --color 'some other flag'"))
34 | .get_matches_from(vec!["", "-c", "-f"]);
35 | assert!(!m.is_present("color"));
36 | assert!(m.is_present("flag"));
37 | }
38 |
39 | #[test]
40 | fn posix_compatible_opts_long() {
41 | let m = App::new("posix")
42 | .arg(Arg::from_usage("--flag [flag] 'some flag'").mutually_overrides_with("color"))
43 | .arg(Arg::from_usage("--color [color] 'some other flag'"))
44 | .get_matches_from(vec!["", "--flag", "some" ,"--color", "other"]);
45 | assert!(m.is_present("color"));
46 | assert_eq!(m.value_of("color").unwrap(), "other");
47 | assert!(!m.is_present("flag"));
48 |
49 | let m = App::new("posix")
50 | .arg(Arg::from_usage("--flag [flag] 'some flag'").mutually_overrides_with("color"))
51 | .arg(Arg::from_usage("--color [color] 'some other flag'"))
52 | .get_matches_from(vec!["", "--color", "some" ,"--flag", "other"]);
53 | assert!(!m.is_present("color"));
54 | assert!(m.is_present("flag"));
55 | assert_eq!(m.value_of("flag").unwrap(), "other");
56 | }
57 |
58 | #[test]
59 | fn posix_compatible_opts_long_equals() {
60 | let m = App::new("posix")
61 | .arg(Arg::from_usage("--flag [flag] 'some flag'").mutually_overrides_with("color"))
62 | .arg(Arg::from_usage("--color [color] 'some other flag'"))
63 | .get_matches_from(vec!["", "--flag=some" ,"--color=other"]);
64 | assert!(m.is_present("color"));
65 | assert_eq!(m.value_of("color").unwrap(), "other");
66 | assert!(!m.is_present("flag"));
67 |
68 | let m = App::new("posix")
69 | .arg(Arg::from_usage("--flag [flag] 'some flag'").mutually_overrides_with("color"))
70 | .arg(Arg::from_usage("--color [color] 'some other flag'"))
71 | .get_matches_from(vec!["", "--color=some" ,"--flag=other"]);
72 | assert!(!m.is_present("color"));
73 | assert!(m.is_present("flag"));
74 | assert_eq!(m.value_of("flag").unwrap(), "other");
75 | }
76 |
77 | #[test]
78 | fn posix_compatible_opts_short() {
79 | let m = App::new("posix")
80 | .arg(Arg::from_usage("-f [flag] 'some flag'").mutually_overrides_with("color"))
81 | .arg(Arg::from_usage("-c [color] 'some other flag'"))
82 | .get_matches_from(vec!["", "-f", "some", "-c", "other"]);
83 | assert!(m.is_present("color"));
84 | assert_eq!(m.value_of("color").unwrap(), "other");
85 | assert!(!m.is_present("flag"));
86 |
87 | let m = App::new("posix")
88 | .arg(Arg::from_usage("-f [flag] 'some flag'").mutually_overrides_with("color"))
89 | .arg(Arg::from_usage("-c [color] 'some other flag'"))
90 | .get_matches_from(vec!["", "-c", "some", "-f", "other"]);
91 | assert!(!m.is_present("color"));
92 | assert!(m.is_present("flag"));
93 | assert_eq!(m.value_of("flag").unwrap(), "other");
94 | }
95 |
96 | #[test]
97 | fn conflict_overriden() {
98 | let m = App::new("conflict_overriden")
99 | .arg(Arg::from_usage("-f, --flag 'some flag'")
100 | .conflicts_with("debug"))
101 | .arg(Arg::from_usage("-d, --debug 'other flag'"))
102 | .arg(Arg::from_usage("-c, --color 'third flag'")
103 | .mutually_overrides_with("flag"))
104 | .get_matches_from(vec!["", "-f", "-c", "-d"]);
105 | assert!(m.is_present("color"));
106 | assert!(!m.is_present("flag"));
107 | assert!(m.is_present("debug"));
108 | }
109 |
110 | #[test]
111 | fn conflict_overriden_2() {
112 | let result = App::new("conflict_overriden")
113 | .arg(Arg::from_usage("-f, --flag 'some flag'")
114 | .conflicts_with("debug"))
115 | .arg(Arg::from_usage("-d, --debug 'other flag'"))
116 | .arg(Arg::from_usage("-c, --color 'third flag'")
117 | .mutually_overrides_with("flag"))
118 | .get_matches_from_safe(vec!["", "-f", "-d", "-c"]);
119 | assert!(result.is_err());
120 | let err = result.err().unwrap();
121 | assert_eq!(err.error_type, ClapErrorType::ArgumentConflict);
122 | }
123 |
124 | #[test]
125 | fn conflict_overriden_3() {
126 | let result = App::new("conflict_overriden")
127 | .arg(Arg::from_usage("-f, --flag 'some flag'")
128 | .conflicts_with("debug"))
129 | .arg(Arg::from_usage("-d, --debug 'other flag'"))
130 | .arg(Arg::from_usage("-c, --color 'third flag'")
131 | .mutually_overrides_with("flag"))
132 | .get_matches_from_safe(vec!["", "-d", "-c", "-f"]);
133 | assert!(result.is_err());
134 | let err = result.err().unwrap();
135 | assert_eq!(err.error_type, ClapErrorType::ArgumentConflict);
136 | }
137 |
138 | #[test]
139 | fn conflict_overriden_4() {
140 | let m = App::new("conflict_overriden")
141 | .arg(Arg::from_usage("-f, --flag 'some flag'")
142 | .conflicts_with("debug"))
143 | .arg(Arg::from_usage("-d, --debug 'other flag'"))
144 | .arg(Arg::from_usage("-c, --color 'third flag'")
145 | .mutually_overrides_with("flag"))
146 | .get_matches_from(vec!["", "-d", "-f", "-c"]);
147 | assert!(m.is_present("color"));
148 | assert!(!m.is_present("flag"));
149 | assert!(m.is_present("debug"));
150 | }
151 |
152 | #[test]
153 | fn require_overriden() {
154 | let result = App::new("require_overriden")
155 | .arg(Arg::with_name("flag")
156 | .index(1)
157 | .required(true))
158 | .arg(Arg::from_usage("-c, --color 'other flag'")
159 | .mutually_overrides_with("flag"))
160 | .get_matches_from_safe(vec!["", "flag", "-c"]);
161 | assert!(result.is_err());
162 | let err = result.err().unwrap();
163 | assert_eq!(err.error_type, ClapErrorType::MissingRequiredArgument);
164 | }
165 |
166 | #[test]
167 | fn require_overriden_2() {
168 | let m = App::new("require_overriden")
169 | .arg(Arg::with_name("flag")
170 | .index(1)
171 | .required(true))
172 | .arg(Arg::from_usage("-c, --color 'other flag'")
173 | .mutually_overrides_with("flag"))
174 | .get_matches_from(vec!["", "-c", "flag"]);
175 | assert!(!m.is_present("color"));
176 | assert!(m.is_present("flag"));
177 | }
178 |
179 | #[test]
180 | fn require_overriden_3() {
181 | let m = App::new("require_overriden")
182 | .arg(Arg::from_usage("-f, --flag 'some flag'")
183 | .requires("debug"))
184 | .arg(Arg::from_usage("-d, --debug 'other flag'"))
185 | .arg(Arg::from_usage("-c, --color 'third flag'")
186 | .mutually_overrides_with("flag"))
187 | .get_matches_from(vec!["", "-f", "-c"]);
188 | assert!(m.is_present("color"));
189 | assert!(!m.is_present("flag"));
190 | assert!(!m.is_present("debug"));
191 | }
192 |
193 | #[test]
194 | fn require_overriden_4() {
195 | let result = App::new("require_overriden")
196 | .arg(Arg::from_usage("-f, --flag 'some flag'")
197 | .requires("debug"))
198 | .arg(Arg::from_usage("-d, --debug 'other flag'"))
199 | .arg(Arg::from_usage("-c, --color 'third flag'")
200 | .mutually_overrides_with("flag"))
201 | .get_matches_from_safe(vec!["", "-c", "-f"]);
202 | assert!(result.is_err());
203 | let err = result.err().unwrap();
204 | assert_eq!(err.error_type, ClapErrorType::MissingRequiredArgument);
205 | }
--------------------------------------------------------------------------------
/benches/03_complex.rs:
--------------------------------------------------------------------------------
1 | #![feature(test)]
2 |
3 | #[macro_use]
4 | extern crate clap;
5 | extern crate test;
6 |
7 | use clap::{App, Arg, SubCommand};
8 |
9 | use test::Bencher;
10 |
11 | static M_VAL_NAMES: [&'static str; 2] = ["one", "two"];
12 | static ARGS: &'static str = "-o --option=[opt]... 'tests options'
13 | [positional] 'tests positionals'";
14 | static OPT3_VALS: [&'static str; 2] = ["fast", "slow"];
15 | static POS3_VALS: [&'static str; 2] = ["vi", "emacs"];
16 |
17 | macro_rules! create_app {
18 | () => ({
19 | App::new("claptests")
20 | .version("0.1")
21 | .about("tests clap library")
22 | .author("Kevin K. ")
23 | .args_from_usage(ARGS)
24 | .arg(Arg::from_usage("-f --flag... 'tests flags'")
25 | .global(true))
26 | .args(vec![
27 | Arg::from_usage("[flag2] -F 'tests flags with exclusions'").conflicts_with("flag").requires("option2"),
28 | Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").conflicts_with("option").requires("positional2"),
29 | Arg::from_usage("[positional2] 'tests positionals with exclusions'"),
30 | Arg::from_usage("-O --Option [option3] 'tests options with specific value sets'").possible_values(&OPT3_VALS),
31 | Arg::from_usage("[positional3]... 'tests positionals with specific values'").possible_values(&POS3_VALS),
32 | Arg::from_usage("--multvals [multvals] 'Tests mutliple values, not mult occs'").value_names(&M_VAL_NAMES),
33 | Arg::from_usage("--multvalsmo [multvalsmo]... 'Tests mutliple values, not mult occs'").value_names(&M_VAL_NAMES),
34 | Arg::from_usage("--minvals2 [minvals]... 'Tests 2 min vals'").min_values(2),
35 | Arg::from_usage("--maxvals3 [maxvals]... 'Tests 3 max vals'").max_values(3)
36 | ])
37 | .subcommand(SubCommand::with_name("subcmd")
38 | .about("tests subcommands")
39 | .version("0.1")
40 | .author("Kevin K. ")
41 | .arg_from_usage("-o --option [scoption]... 'tests options'")
42 | .arg_from_usage("[scpositional] 'tests positionals'"))
43 | })
44 | }
45 |
46 | #[bench]
47 | fn create_app_from_usage(b: &mut Bencher) {
48 |
49 | b.iter(|| create_app!());
50 | }
51 |
52 | #[bench]
53 | fn create_app_builder(b: &mut Bencher) {
54 | b.iter(|| {
55 | App::new("claptests")
56 | .version("0.1")
57 | .about("tests clap library")
58 | .author("Kevin K. ")
59 | .arg(Arg::with_name("opt")
60 | .help("tests options")
61 | .short("o")
62 | .long("option")
63 | .takes_value(true)
64 | .multiple(true))
65 | .arg(Arg::with_name("positional")
66 | .help("tests positionals")
67 | .index(1))
68 | .arg(Arg::with_name("flag")
69 | .short("f")
70 | .help("tests flags")
71 | .long("flag")
72 | .multiple(true)
73 | .global(true))
74 | .arg(Arg::with_name("flag2")
75 | .short("F")
76 | .help("tests flags with exclusions")
77 | .conflicts_with("flag")
78 | .requires("option2"))
79 | .arg(Arg::with_name("option2")
80 | .help("tests long options with exclusions")
81 | .conflicts_with("option")
82 | .requires("positional2")
83 | .takes_value(true)
84 | .long("long-option-2"))
85 | .arg(Arg::with_name("positional2")
86 | .index(3)
87 | .help("tests positionals with exclusions"))
88 | .arg(Arg::with_name("option3")
89 | .short("O")
90 | .long("Option")
91 | .takes_value(true)
92 | .help("tests options with specific value sets")
93 | .possible_values(&OPT3_VALS))
94 | .arg(Arg::with_name("positional3")
95 | .multiple(true)
96 | .help("tests positionals with specific values")
97 | .index(4)
98 | .possible_values(&POS3_VALS))
99 | .arg(Arg::with_name("multvals")
100 | .long("multvals")
101 | .takes_value(true)
102 | .help("Tests mutliple values, not mult occs")
103 | .value_names(&M_VAL_NAMES))
104 | .arg(Arg::with_name("multvalsmo")
105 | .long("multvalsmo")
106 | .takes_value(true)
107 | .multiple(true)
108 | .help("Tests mutliple values, not mult occs")
109 | .value_names(&M_VAL_NAMES))
110 | .arg(Arg::with_name("minvals")
111 | .long("minvals2")
112 | .multiple(true)
113 | .takes_value(true)
114 | .help("Tests 2 min vals")
115 | .min_values(2))
116 | .arg(Arg::with_name("maxvals")
117 | .long("maxvals3")
118 | .takes_value(true)
119 | .multiple(true)
120 | .help("Tests 3 max vals")
121 | .max_values(3))
122 | .subcommand(SubCommand::with_name("subcmd")
123 | .about("tests subcommands")
124 | .version("0.1")
125 | .author("Kevin K. ")
126 | .arg(Arg::with_name("scoption")
127 | .short("o")
128 | .long("option")
129 | .multiple(true)
130 | .takes_value(true)
131 | .help("tests options"))
132 | .arg(Arg::with_name("scpositional")
133 | .index(1)
134 | .help("tests positionals")));
135 | });
136 | }
137 |
138 | #[bench]
139 | fn create_app_macros(b: &mut Bencher) {
140 | b.iter(|| {
141 | clap_app!(claptests =>
142 | (version: "0.1")
143 | (about: "tests clap library")
144 | (author: "Kevin K. ")
145 | (@arg opt: -o --option +takes_value ... "tests options")
146 | (@arg positional: index(1) "tests positionals")
147 | (@arg flag: -f --flag ... +global "tests flags")
148 | (@arg flag2: -F conflicts_with[flag] requires[option2]
149 | "tests flags with exclusions")
150 | (@arg option2: --long_option_2 conflicts_with[option] requires[positional2]
151 | "tests long options with exclusions")
152 | (@arg positional2: index(2) "tests positionals with exclusions")
153 | (@arg option3: -O --Option +takes_value possible_value[fast slow]
154 | "tests options with specific value sets")
155 | (@arg positional3: index(3) ... possible_value[vi emacs]
156 | "tests positionals with specific values")
157 | (@arg multvals: --multvals +takes_value value_name[one two]
158 | "Tests mutliple values, not mult occs")
159 | (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
160 | "Tests mutliple values, not mult occs")
161 | (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
162 | (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
163 | (@subcommand subcmd =>
164 | (about: "tests subcommands")
165 | (version: "0.1")
166 | (author: "Kevin K. ")
167 | (@arg scoption: -o --option ... +takes_value "tests options")
168 | (@arg scpositional: index(1) "tests positionals"))
169 | );
170 | });
171 | }
172 |
173 | #[bench]
174 | fn parse_clean(b: &mut Bencher) {
175 | b.iter(|| create_app!().get_matches_from(vec![""]));
176 | }
177 |
178 | #[bench]
179 | fn parse_flag(b: &mut Bencher) {
180 | b.iter(|| create_app!().get_matches_from(vec!["", "-f"]));
181 | }
182 |
183 | #[bench]
184 | fn parse_option(b: &mut Bencher) {
185 | b.iter(|| create_app!().get_matches_from(vec!["", "-o", "option1"]));
186 | }
187 |
188 | #[bench]
189 | fn parse_positional(b: &mut Bencher) {
190 | b.iter(|| create_app!().get_matches_from(vec!["", "arg1"]));
191 | }
192 |
193 | #[bench]
194 | fn parse_sc_clean(b: &mut Bencher) {
195 | b.iter(|| create_app!().get_matches_from(vec!["", "subcmd"]));
196 | }
197 |
198 | #[bench]
199 | fn parse_sc_flag(b: &mut Bencher) {
200 | b.iter(|| create_app!().get_matches_from(vec!["", "subcmd", "-f"]));
201 | }
202 |
203 | #[bench]
204 | fn parse_sc_option(b: &mut Bencher) {
205 | b.iter(|| create_app!().get_matches_from(vec!["", "subcmd", "-o", "option1"]));
206 | }
207 |
208 | #[bench]
209 | fn parse_sc_positional(b: &mut Bencher) {
210 | b.iter(|| create_app!().get_matches_from(vec!["", "subcmd", "arg1"]));
211 | }
212 |
213 | #[bench]
214 | fn parse_complex1(b: &mut Bencher) {
215 | b.iter(|| create_app!().get_matches_from(vec!["", "-ff", "-o", "option1", "arg1", "-O", "fast", "arg2", "--multvals", "one", "two", "three"]));
216 | }
217 |
218 | #[bench]
219 | fn parse_complex2(b: &mut Bencher) {
220 | b.iter(|| create_app!().get_matches_from(vec!["", "arg1", "-f", "arg2", "--long-option-2", "some", "-O", "slow", "--multvalsmo", "one", "two", "--minvals2", "3", "2", "1"]));
221 | }
222 |
223 |
224 | #[bench]
225 | fn parse_sc_complex(b: &mut Bencher) {
226 | b.iter(|| create_app!().get_matches_from(vec!["", "subcmd", "-f", "-o", "option1", "arg1"]));
227 | }
228 |
--------------------------------------------------------------------------------
/src/args/argmatches.rs:
--------------------------------------------------------------------------------
1 | use std::collections::HashMap;
2 |
3 | use args::SubCommand;
4 | use args::MatchedArg;
5 |
6 | /// Used to get information about the arguments that where supplied to the program at runtime by
7 | /// the user. To get a new instance of this struct you use `.get_matches()` of the `App` struct.
8 | ///
9 | ///
10 | /// # Example
11 | ///
12 | /// ```no_run
13 | /// # use clap::{App, Arg};
14 | /// let matches = App::new("MyApp")
15 | /// // adding of arguments and configuration goes here...
16 | /// # .arg(Arg::with_name("config")
17 | /// # .long("config")
18 | /// # .required(true)
19 | /// # .takes_value(true))
20 | /// # .arg(Arg::with_name("debug")
21 | /// # .short("d")
22 | /// # .multiple(true))
23 | /// .get_matches();
24 | /// // if you had an argument named "output" that takes a value
25 | /// if let Some(o) = matches.value_of("output") {
26 | /// println!("Value for output: {}", o);
27 | /// }
28 | ///
29 | /// // If you have a required argument you can call .unwrap() because the program will exit long
30 | /// // before this point if the user didn't specify it at runtime.
31 | /// println!("Config file: {}", matches.value_of("config").unwrap());
32 | ///
33 | /// // You can check the presence of an argument
34 | /// if matches.is_present("debug") {
35 | /// // Another way to check if an argument was present, or if it occurred multiple times is to
36 | /// // use occurrences_of() which returns 0 if an argument isn't found at runtime, or the
37 | /// // number of times that it occurred, if it was. To allow an argument to appear more than
38 | /// // once, you must use the .multiple(true) method, otherwise it will only return 1 or 0.
39 | /// if matches.occurrences_of("debug") > 2 {
40 | /// println!("Debug mode is REALLY on");
41 | /// } else {
42 | /// println!("Debug mode kind of on");
43 | /// }
44 | /// }
45 | ///
46 | /// // You can get the sub-matches of a particular subcommand (in this case "test")
47 | /// // If "test" had it's own "-l" flag you could check for it's presence accordingly
48 | /// if let Some(ref matches) = matches.subcommand_matches("test") {
49 | /// if matches.is_present("list") {
50 | /// println!("Printing testing lists...");
51 | /// } else {
52 | /// println!("Not printing testing lists...");
53 | /// }
54 | /// }
55 | pub struct ArgMatches<'n, 'a> {
56 | #[doc(hidden)]
57 | pub args: HashMap<&'a str, MatchedArg>,
58 | #[doc(hidden)]
59 | pub subcommand: Option>>,
60 | #[doc(hidden)]
61 | pub usage: Option,
62 | }
63 |
64 | impl<'n, 'a> ArgMatches<'n, 'a> {
65 | /// Creates a new instance of `ArgMatches`. This ins't called directly, but
66 | /// through the `.get_matches()` method of `App`
67 | ///
68 | /// # Example
69 | ///
70 | /// ```no_run
71 | /// # use clap::{App, Arg};
72 | /// let matches = App::new("myprog").get_matches();
73 | /// ```
74 | #[doc(hidden)]
75 | pub fn new() -> ArgMatches<'n, 'a> {
76 | ArgMatches {
77 | args: HashMap::new(),
78 | subcommand: None,
79 | usage: None
80 | }
81 | }
82 |
83 | /// Gets the value of a specific option or positional argument (i.e. an argument that takes
84 | /// an additional value at runtime). If the option wasn't present at runtime
85 | /// it returns `None`.
86 | ///
87 | /// *NOTE:* If getting a value for an option or positional argument that allows multiples,
88 | /// prefer `values_of()` as `value_of()` will only return the _*first*_ value.
89 | ///
90 | /// # Example
91 | ///
92 | /// ```no_run
93 | /// # use clap::{App, Arg};
94 | /// # let matches = App::new("myapp")
95 | /// # .arg(Arg::with_name("output")
96 | /// # .takes_value(true))
97 | /// # .get_matches();
98 | /// if let Some(o) = matches.value_of("output") {
99 | /// println!("Value for output: {}", o);
100 | /// }
101 | /// ```
102 | pub fn value_of(&self,
103 | name: &str)
104 | -> Option<&str> {
105 | if let Some(ref arg) = self.args.get(name) {
106 | if let Some(ref vals) = arg.values {
107 | if let Some(ref val) = vals.values().nth(0) {
108 | return Some(&val[..]);
109 | }
110 | }
111 | }
112 | None
113 | }
114 |
115 | /// Gets the values of a specific option or positional argument in a vector (i.e. an argument
116 | /// that takes multiple values at runtime). If the option wasn't present at runtime it
117 | /// returns `None`
118 | ///
119 | /// # Example
120 | ///
121 | /// ```no_run
122 | /// # use clap::{App, Arg};
123 | /// # let matches = App::new("myapp")
124 | /// # .arg(Arg::with_name("output").takes_value(true)).get_matches();
125 | /// // If the program had option "-c" that took a value and was run
126 | /// // via "myapp -o some -o other -o file"
127 | /// // values_of() would return a [&str; 3] ("some", "other", "file")
128 | /// if let Some(os) = matches.values_of("output") {
129 | /// for o in os {
130 | /// println!("A value for output: {}", o);
131 | /// }
132 | /// }
133 | /// ```
134 | pub fn values_of(&'a self,
135 | name: &str)
136 | -> Option> {
137 | if let Some(ref arg) = self.args.get(name) {
138 | if let Some(ref vals) = arg.values {
139 | return Some(vals.values().map(|s| &s[..]).collect::>());
140 | }
141 | }
142 | None
143 | }
144 |
145 | /// Returns if an argument was present at runtime.
146 | ///
147 | ///
148 | /// # Example
149 | ///
150 | /// ```no_run
151 | /// # use clap::{App, Arg};
152 | /// # let matches = App::new("myapp")
153 | /// # .arg(Arg::with_name("output").takes_value(true)).get_matches();
154 | /// if matches.is_present("output") {
155 | /// println!("The output argument was used!");
156 | /// }
157 | /// ```
158 | pub fn is_present(&self,
159 | name: &str)
160 | -> bool {
161 | if let Some(ref sc) = self.subcommand {
162 | if sc.name == name {
163 | return true;
164 | }
165 | }
166 | if self.args.contains_key(name) {
167 | return true;
168 | }
169 | false
170 | }
171 |
172 | /// Returns the number of occurrences of an option, flag, or positional argument at runtime.
173 | /// If an argument isn't present it will return `0`. Can be used on arguments which *don't*
174 | /// allow multiple occurrences, but will obviously only return `0` or `1`.
175 | ///
176 | ///
177 | /// # Example
178 | ///
179 | /// ```no_run
180 | /// # use clap::{App, Arg};
181 | /// # let matches = App::new("myapp")
182 | /// # .arg(Arg::with_name("output").takes_value(true)).get_matches();
183 | /// if matches.occurrences_of("debug") > 1 {
184 | /// println!("Debug mode is REALLY on");
185 | /// } else {
186 | /// println!("Debug mode kind of on");
187 | /// }
188 | /// ```
189 | pub fn occurrences_of(&self,
190 | name: &str)
191 | -> u8 {
192 | if let Some(ref arg) = self.args.get(name) {
193 | return arg.occurrences;
194 | }
195 | 0
196 | }
197 |
198 | /// Returns the `ArgMatches` for a particular subcommand or None if the subcommand wasn't
199 | /// present at runtime.
200 | ///
201 | ///
202 | /// # Example
203 | ///
204 | /// ```no_run
205 | /// # use clap::{App, Arg, SubCommand};
206 | /// # let app_matches = App::new("myapp")
207 | /// # .subcommand(SubCommand::with_name("test")).get_matches();
208 | /// if let Some(matches) = app_matches.subcommand_matches("test") {
209 | /// // Use matches as normal
210 | /// }
211 | /// ```
212 | pub fn subcommand_matches<'na>(&self,
213 | name: &'na str)
214 | -> Option<&ArgMatches> {
215 | if let Some( ref sc) = self.subcommand {
216 | if sc.name != name {
217 | return None;
218 | }
219 | return Some(&sc.matches);
220 | }
221 | None
222 | }
223 |
224 | /// Returns the name of the subcommand used of the parent `App`, or `None` if one wasn't found
225 | ///
226 | /// *NOTE*: Only a single subcommand may be present per `App` at runtime, does *NOT* check for
227 | /// the name of sub-subcommand's names
228 | ///
229 | ///
230 | /// # Example
231 | ///
232 | /// ```no_run
233 | /// # use clap::{App, Arg, SubCommand};
234 | /// # let app_matches = App::new("myapp")
235 | /// # .subcommand(SubCommand::with_name("test")).get_matches();
236 | /// match app_matches.subcommand_name() {
237 | /// Some("test") => {}, // test was used
238 | /// Some("config") => {}, // config was used
239 | /// _ => {}, // Either no subcommand or one not tested for...
240 | /// }
241 | /// ```
242 | pub fn subcommand_name(&self) -> Option<&str> {
243 | if let Some( ref sc ) = self.subcommand {
244 | return Some(&sc.name[..]);
245 | }
246 | None
247 | }
248 |
249 | /// Returns the name and `ArgMatches` of the subcommand used at runtime or ("", None) if one
250 | /// wasn't found.
251 | ///
252 | ///
253 | /// # Example
254 | ///
255 | /// ```no_run
256 | /// # use clap::{App, Arg, SubCommand};
257 | /// # let app_matches = App::new("myapp")
258 | /// # .subcommand(SubCommand::with_name("test")).get_matches();
259 | /// match app_matches.subcommand() {
260 | /// ("test", Some(matches)) => {}, // test was used
261 | /// ("config", Some(matches)) => {}, // config was used
262 | /// _ => {}, // Either no subcommand or one not tested for...
263 | /// }
264 | /// ```
265 | pub fn subcommand(&self) -> (&str, Option<&ArgMatches>) {
266 | if let Some( ref sc ) = self.subcommand {
267 | return (&sc.name[..], Some(&sc.matches));
268 | }
269 | ("", None)
270 | }
271 |
272 | /// Returns a string slice of the usage statement for the `App` (or `SubCommand`)
273 | ///
274 | ///
275 | /// # Example
276 | ///
277 | /// ```no_run
278 | /// # use clap::{App, Arg, SubCommand};
279 | /// # let app_matches = App::new("myapp")
280 | /// # .subcommand(SubCommand::with_name("test")).get_matches();
281 | /// println!("{}",app_matches.usage());
282 | /// ```
283 | pub fn usage(&self) -> &str {
284 | if let Some( ref u ) = self.usage {
285 | return &u[..];
286 | }
287 |
288 | // Should be un-reachable
289 | ""
290 | }
291 | }
292 |
--------------------------------------------------------------------------------
/clap-tests/run_tests.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import sys
3 | import subprocess
4 | import re
5 |
6 | failed = False
7 |
8 | _ansi = re.compile(r'\x1b[^m]*m')
9 |
10 | _help = '''claptests 0.0.1
11 | Kevin K.
12 | tests clap library
13 |
14 | USAGE:
15 | \tclaptests [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]
16 |
17 | FLAGS:
18 | -f, --flag tests flags
19 | -F tests flags with exclusions
20 | -h, --help Prints help information
21 | -V, --version Prints version information
22 |
23 | OPTIONS:
24 | --maxvals3 ... Tests 3 max vals
25 | --minvals2 ... Tests 2 min vals
26 | --multvals Tests mutliple values, not mult occs
27 | --multvalsmo Tests mutliple values, not mult occs
28 | -o, --option ... tests options
29 | --long-option-2 tests long options with exclusions
30 | -O, --Option tests options with specific value sets [values: fast slow]
31 |
32 | ARGS:
33 | positional tests positionals
34 | positional2 tests positionals with exclusions
35 | positional3... tests positionals with specific values
36 |
37 | SUBCOMMANDS:
38 | help Prints this message
39 | subcmd tests subcommands'''
40 |
41 | _sc_dym_usage = '''error: The subcommand 'subcm' isn't valid
42 | Did you mean 'subcmd' ?
43 |
44 | If you received this message in error, try re-running with 'claptests -- subcm'
45 |
46 | USAGE:
47 | claptests [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]
48 |
49 | For more information try --help'''
50 |
51 | _arg_dym_usage = '''error: The argument '--optio' isn't valid
52 | Did you mean --option ?
53 |
54 | USAGE:
55 | claptests --option ...
56 |
57 | For more information try --help'''
58 |
59 | _pv_dym_usage = '''error: 'slo' isn't a valid value for '--Option '
60 | [valid values: fast slow]
61 |
62 | Did you mean 'slow' ?
63 |
64 | USAGE:
65 | claptests --Option
66 |
67 | For more information try --help'''
68 |
69 | _excluded = '''error: The argument '--flag' cannot be used with '-F'
70 |
71 | USAGE:
72 | \tclaptests [positional2] -F --long-option-2
73 |
74 | For more information try --help'''
75 |
76 | _excluded_l = '''error: The argument '-f' cannot be used '-F'
77 |
78 | USAGE:
79 | claptests [positional2] -F --long-option-2
80 |
81 | For more information try --help'''
82 |
83 | _required = '''error: The following required arguments were not supplied:
84 | \t'[positional2]'
85 | \t'--long-option-2 '
86 |
87 | USAGE:
88 | \tclaptests [positional2] -F --long-option-2
89 |
90 | For more information try --help'''
91 |
92 | _fop = '''flag present 1 times
93 | option present 1 times with value: some
94 | An option: some
95 | positional present with value: value
96 | flag2 NOT present
97 | option2 maybe present with value of: Nothing
98 | positional2 maybe present with value of: Nothing
99 | option3 NOT present
100 | positional3 NOT present
101 | option present 1 times with value: some
102 | An option: some
103 | positional present with value: value
104 | subcmd NOT present'''
105 |
106 | _f2op = '''flag present 2 times
107 | option present 1 times with value: some
108 | An option: some
109 | positional present with value: value
110 | flag2 NOT present
111 | option2 maybe present with value of: Nothing
112 | positional2 maybe present with value of: Nothing
113 | option3 NOT present
114 | positional3 NOT present
115 | option present 1 times with value: some
116 | An option: some
117 | positional present with value: value
118 | subcmd NOT present'''
119 |
120 | _o2p = '''flag NOT present
121 | option present 2 times with value: some
122 | An option: some
123 | An option: other
124 | positional present with value: value
125 | flag2 NOT present
126 | option2 maybe present with value of: Nothing
127 | positional2 maybe present with value of: Nothing
128 | option3 NOT present
129 | positional3 NOT present
130 | option present 2 times with value: some
131 | An option: some
132 | An option: other
133 | positional present with value: value
134 | subcmd NOT present'''
135 |
136 | _schelp = '''claptests-subcmd 0.1
137 | Kevin K.
138 | tests subcommands
139 |
140 | USAGE:
141 | \tclaptests subcmd [FLAGS] [OPTIONS] [--] [ARGS]
142 |
143 | FLAGS:
144 | -f, --flag tests flags
145 | -h, --help Prints help information
146 | -V, --version Prints version information
147 |
148 | OPTIONS:
149 | -o, --option ... tests options
150 |
151 | ARGS:
152 | scpositional tests positionals'''
153 |
154 | _scfop = '''flag NOT present
155 | option NOT present
156 | positional NOT present
157 | flag2 NOT present
158 | option2 maybe present with value of: Nothing
159 | positional2 maybe present with value of: Nothing
160 | option3 NOT present
161 | positional3 NOT present
162 | option NOT present
163 | positional NOT present
164 | subcmd present
165 | flag present 1 times
166 | scoption present with value: some
167 | An scoption: some
168 | scpositional present with value: value'''
169 |
170 | _scf2op = '''flag NOT present
171 | option NOT present
172 | positional NOT present
173 | flag2 NOT present
174 | option2 maybe present with value of: Nothing
175 | positional2 maybe present with value of: Nothing
176 | option3 NOT present
177 | positional3 NOT present
178 | option NOT present
179 | positional NOT present
180 | subcmd present
181 | flag present 2 times
182 | scoption present with value: some
183 | An scoption: some
184 | scpositional present with value: value'''
185 |
186 | _min_vals_few = '''error: The argument '--minvals2 ...' requires at least 2 values, but 1 was provided
187 |
188 | USAGE:
189 | \tclaptests --minvals2 ...
190 |
191 | For more information try --help'''
192 |
193 | _exact = '''flag NOT present
194 | option NOT present
195 | positional NOT present
196 | flag2 NOT present
197 | option2 maybe present with value of: Nothing
198 | positional2 maybe present with value of: Nothing
199 | option3 NOT present
200 | positional3 NOT present
201 | option NOT present
202 | positional NOT present
203 | subcmd NOT present'''
204 |
205 | _max_vals_more = '''flag NOT present
206 | option NOT present
207 | positional present with value: too
208 | flag2 NOT present
209 | option2 maybe present with value of: Nothing
210 | positional2 maybe present with value of: Nothing
211 | option3 NOT present
212 | positional3 NOT present
213 | option NOT present
214 | positional present with value: too
215 | subcmd NOT present'''
216 |
217 | _mult_vals_more = '''error: The argument '--multvals' was supplied more than once, but does not support multiple values
218 |
219 | USAGE:
220 | \tclaptests --multvals
221 |
222 | For more information try --help'''
223 |
224 | _mult_vals_few = '''error: The argument '--multvals ' requires a value but none was supplied
225 |
226 | USAGE:
227 | \tclaptests --multvals
228 |
229 | For more information try --help'''
230 |
231 | _mult_vals_2m1 = '''error: The argument '--multvalsmo ' requires 2 values, but 1 was provided
232 |
233 | USAGE:
234 | claptests --multvalsmo
235 |
236 | For more information try --help'''
237 |
238 | _bin = './target/release/claptests'
239 |
240 | cmds = {#'help short: ': ['{} -h'.format(_bin), _help],
241 | #'help long: ': ['{} --help'.format(_bin), _help],
242 | 'help subcmd: ': ['{} help'.format(_bin), _help],
243 | #'excluded first: ': ['{} -f -F'.format(_bin), _excluded],
244 | #'excluded last: ': ['{} -F -f'.format(_bin), _excluded_l],
245 | 'missing required: ': ['{} -F'.format(_bin), _required],
246 | 'max_vals too many: ': ['{} --maxvals3 some other value too'.format(_bin), _max_vals_more],
247 | 'max_vals exact: ': ['{} --maxvals3 some other value'.format(_bin), _exact],
248 | 'max_vals less: ': ['{} --maxvals3 some other'.format(_bin), _exact],
249 | 'min_vals more: ': ['{} --minvals2 some other value too'.format(_bin), _exact],
250 | 'min_vals exact: ': ['{} --minvals2 some value'.format(_bin), _exact],
251 | 'min_vals too few: ': ['{} --minvals2 some'.format(_bin), _min_vals_few],
252 | 'mult_vals too many: ': ['{} --multvals some other --multvals some other'.format(_bin), _mult_vals_more],
253 | 'mult_vals too few: ': ['{} --multvals some'.format(_bin), _mult_vals_few],
254 | 'mult_vals exact: ': ['{} --multvals some other'.format(_bin), _exact],
255 | 'mult_valsmo x2: ': ['{} --multvalsmo some other --multvalsmo some other'.format(_bin), _exact],
256 | 'mult_valsmo x2-1: ': ['{} --multvalsmo some other --multvalsmo some'.format(_bin), _mult_vals_2m1],
257 | 'mult_valsmo x1: ': ['{} --multvalsmo some other'.format(_bin), _exact],
258 | 'F2(ss),O(s),P: ': ['{} value -f -f -o some'.format(_bin), _f2op],
259 | 'arg dym: ': ['{} --optio=foo'.format(_bin), _arg_dym_usage],
260 | #'pv dym: ': ['{} --Option slo'.format(_bin), _pv_dym_usage],
261 | #'pv dym(=): ': ['{} --Option=slo'.format(_bin), _pv_dym_usage],
262 | 'O2(ll)P: ': ['{} value --option some --option other'.format(_bin), _o2p],
263 | 'O2(l=l=)P: ': ['{} value --option=some --option=other'.format(_bin), _o2p],
264 | 'O2(ss)P: ': ['{} value -o some -o other'.format(_bin), _o2p],
265 | 'F2(s2),O(s),P: ': ['{} value -ff -o some'.format(_bin), _f2op],
266 | 'F(s),O(s),P: ': ['{} value -f -o some'.format(_bin), _fop],
267 | 'F(l),O(l),P: ': ['{} value --flag --option some'.format(_bin), _fop],
268 | 'F(l),O(l=),P: ': ['{} value --flag --option=some'.format(_bin), _fop],
269 | 'sc dym: ': ['{} subcm'.format(_bin), _sc_dym_usage],
270 | 'sc help short: ': ['{} subcmd -h'.format(_bin), _schelp],
271 | 'sc help long: ': ['{} subcmd --help'.format(_bin), _schelp],
272 | 'scF(l),O(l),P: ': ['{} subcmd value --flag --option some'.format(_bin), _scfop],
273 | 'scF(l),O(s),P: ': ['{} subcmd value --flag -o some'.format(_bin), _scfop],
274 | 'scF(l),O(l=),P: ': ['{} subcmd value --flag --option=some'.format(_bin), _scfop],
275 | 'scF(s),O(l),P: ': ['{} subcmd value -f --option some'.format(_bin), _scfop],
276 | 'scF(s),O(s),P: ': ['{} subcmd value -f -o some'.format(_bin), _scfop],
277 | 'scF(s),O(l=),P: ': ['{} subcmd value -f --option=some'.format(_bin), _scfop],
278 | 'scF2(s),O(l),P: ': ['{} subcmd value -ff --option some'.format(_bin), _scf2op],
279 | 'scF2(s),O(s),P: ': ['{} subcmd value -ff -o some'.format(_bin), _scf2op],
280 | 'scF2(s),O(l=),P: ': ['{} subcmd value -ff --option=some'.format(_bin), _scf2op],
281 | 'scF2(l2),O(l),P: ': ['{} subcmd value --flag --flag --option some'.format(_bin), _scf2op],
282 | 'scF2(l2),O(s),P: ': ['{} subcmd value --flag --flag -o some'.format(_bin), _scf2op],
283 | 'scF2(l2),O(l=),P: ': ['{} subcmd value --flag --flag --option=some'.format(_bin), _scf2op],
284 | 'scF2(s2),O(l),P: ': ['{} subcmd value -f -f --option some'.format(_bin), _scf2op],
285 | 'scF2(s2),O(s),P: ': ['{} subcmd value -f -f -o some'.format(_bin), _scf2op],
286 | 'scF2(s2),O(l=),P: ': ['{} subcmd value -f -f --option=some'.format(_bin), _scf2op]
287 | }
288 |
289 | def pass_fail(name, check, good):
290 | global failed
291 | sys.stdout.write(name)
292 | if check == good:
293 | print('Pass')
294 | return
295 | failed = True
296 | print('Fail\n\tShould be: \n{}\n\tBut is: \n{}'.format(good, check))
297 |
298 |
299 | def main():
300 | for cmd, cmd_v in cmds.items():
301 | proc = subprocess.Popen(cmd_v[0], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
302 | out, err = proc.communicate()
303 | out = _ansi.sub('', out.strip())
304 | err = _ansi.sub('', err.strip())
305 | if out:
306 | pass_fail(cmd, out, cmd_v[1])
307 | else:
308 | pass_fail(cmd, err, cmd_v[1])
309 |
310 | if failed:
311 | print('One or more tests failed')
312 | return 1
313 | print('All tests passed!')
314 |
315 | if __name__ == '__main__':
316 | sys.exit(main())
317 |
--------------------------------------------------------------------------------
/src/args/group.rs:
--------------------------------------------------------------------------------
1 | #[cfg(feature = "yaml")]
2 | use std::collections::BTreeMap;
3 | use std::fmt::{Debug, Formatter, Result};
4 |
5 | #[cfg(feature = "yaml")]
6 | use yaml_rust::Yaml;
7 |
8 | /// `ArgGroup`s are a family of related arguments and way for you to say, "Any of these arguments".
9 | /// By placing arguments in a logical group, you can make easier requirement and exclusion rules
10 | /// intead of having to list each individually, or when you want a rule to apply "any but not all"
11 | /// arguments.
12 | ///
13 | /// For instance, you can make an entire ArgGroup required, this means that one (and *only* one)
14 | /// argument. from that group must be present. Using more than one argument from an ArgGroup causes
15 | /// a failure (graceful exit).
16 | ///
17 | /// You can also do things such as name an ArgGroup as a confliction or requirement, meaning any
18 | /// of the arguments that belong to that group will cause a failure if present, or must present
19 | /// respectively.
20 | ///
21 | /// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
22 | /// present out of a given set. Imagine that you had multiple arguments, and you want one of them
23 | /// to be required, but making all of them required isn't feasible because perhaps they conflict
24 | /// with each other. For example, lets say that you were building an application where one could
25 | /// set a given version number by supplying a string with an option argument, i.e.
26 | /// `--set-ver v1.2.3`, you also wanted to support automatically using a previous version number
27 | /// and simply incrementing one of the three numbers. So you create three flags `--major`,
28 | /// `--minor`, and `--patch`. All of these arguments shouldn't be used at one time but you want to
29 | /// specify that *at least one* of them is used. For this, you can create a group.
30 | ///
31 | /// # Example
32 | ///
33 | /// ```no_run
34 | /// # use clap::{App, ArgGroup};
35 | /// let _ = App::new("app")
36 | /// .args_from_usage("--set-ver [ver] 'set the version manually'
37 | /// --major 'auto increase major'
38 | /// --minor 'auto increase minor'
39 | /// --patch 'auto increase patch")
40 | /// .arg_group(ArgGroup::with_name("vers")
41 | /// .add_all(&["ver", "major", "minor","patch"])
42 | /// .required(true))
43 | /// # .get_matches();
44 | pub struct ArgGroup<'n, 'ar> {
45 | #[doc(hidden)]
46 | pub name: &'n str,
47 | #[doc(hidden)]
48 | pub args: Vec<&'ar str>,
49 | #[doc(hidden)]
50 | pub required: bool,
51 | #[doc(hidden)]
52 | pub requires: Option>,
53 | #[doc(hidden)]
54 | pub conflicts: Option>,
55 | }
56 |
57 | impl<'n, 'ar> ArgGroup<'n, 'ar> {
58 | /// Creates a new instace of `ArgGroup` using a unique string name.
59 | /// The name will only be used by the library consumer and not displayed to the use.
60 | ///
61 | /// # Example
62 | ///
63 | /// ```no_run
64 | /// # use clap::{App, ArgGroup};
65 | /// # let matches = App::new("myprog")
66 | /// # .arg_group(
67 | /// ArgGroup::with_name("conifg")
68 | /// # ).get_matches();
69 | pub fn with_name(n: &'n str) -> Self {
70 | ArgGroup {
71 | name: n,
72 | required: false,
73 | args: vec![],
74 | requires: None,
75 | conflicts: None
76 | }
77 | }
78 |
79 | /// Creates a new instace of `ArgGroup` from a .yml (YAML) file.
80 | ///
81 | /// # Example
82 | ///
83 | /// ```ignore
84 | /// # use clap::ArgGroup;
85 | /// let yml = load_yaml!("group.yml");
86 | /// let ag = ArgGroup::from_yaml(yml);
87 | /// ```
88 | #[cfg(feature = "yaml")]
89 | pub fn from_yaml<'y>(y: &'y BTreeMap) -> ArgGroup<'y, 'y> {
90 | // We WANT this to panic on error...so expect() is good.
91 | let name_yml = y.keys().nth(0).unwrap();
92 | let name_str = name_yml.as_str().unwrap();
93 | let mut a = ArgGroup::with_name(name_str);
94 | let group_settings = y.get(name_yml).unwrap().as_hash().unwrap();
95 |
96 | for (k, v) in group_settings.iter() {
97 | a = match k.as_str().unwrap() {
98 | "required" => a.required(v.as_bool().unwrap()),
99 | "args" => {
100 | for ys in v.as_vec().unwrap() {
101 | if let Some(s) = ys.as_str() {
102 | a = a.add(s);
103 | }
104 | }
105 | a
106 | }
107 | "requires" => {
108 | for ys in v.as_vec().unwrap() {
109 | if let Some(s) = ys.as_str() {
110 | a = a.requires(s);
111 | }
112 | }
113 | a
114 | }
115 | "conflicts_with" => {
116 | for ys in v.as_vec().unwrap() {
117 | if let Some(s) = ys.as_str() {
118 | a = a.conflicts_with(s);
119 | }
120 | }
121 | a
122 | }
123 | s => panic!("Unknown ArgGroup setting '{}' in YAML file for \
124 | ArgGroup '{}'", s, name_str),
125 | }
126 | }
127 |
128 | a
129 | }
130 |
131 | /// Adds an argument to this group by name
132 | ///
133 | ///
134 | /// # Example
135 | ///
136 | /// ```no_run
137 | /// # use clap::{App, ArgGroup};
138 | /// # let matches = App::new("myprog")
139 | /// # .arg_group(
140 | /// # ArgGroup::with_name("conifg")
141 | /// .add("config")
142 | /// # ).get_matches();
143 | pub fn add(mut self,
144 | n: &'ar str)
145 | -> Self {
146 | self.args.push(n);
147 | self
148 | }
149 |
150 | /// Adds multiple arguments to this group by name
151 | ///
152 | ///
153 | /// # Example
154 | ///
155 | /// ```no_run
156 | /// # use clap::{App, ArgGroup};
157 | /// # let matches = App::new("myprog")
158 | /// # .arg_group(
159 | /// # ArgGroup::with_name("conifg")
160 | /// .add_all(&["config", "input", "output"])
161 | /// # ).get_matches();
162 | pub fn add_all(mut self,
163 | ns: &[&'ar str])
164 | -> Self {
165 | for n in ns {
166 | self = self.add(n);
167 | }
168 | self
169 | }
170 |
171 | /// Sets the requirement of this group. A required group will be displayed in the usage string
172 | /// of the application in the format `[arg|arg2|arg3]`. A required `ArgGroup` simply states
173 | /// that one, and only one argument from this group *must* be present at runtime (unless
174 | /// conflicting with another argument).
175 | ///
176 | ///
177 | /// # Example
178 | ///
179 | /// ```no_run
180 | /// # use clap::{App, ArgGroup};
181 | /// # let matches = App::new("myprog")
182 | /// # .arg_group(
183 | /// # ArgGroup::with_name("conifg")
184 | /// .required(true)
185 | /// # ).get_matches();
186 | pub fn required(mut self,
187 | r: bool)
188 | -> Self {
189 | self.required = r;
190 | self
191 | }
192 |
193 | /// Sets the requirement rules of this group. This is not to be confused with a required group.
194 | /// Requirement rules function just like argument requirement rules, you can name other
195 | /// arguments or groups that must be present when one of the arguments from this group is used.
196 | ///
197 | /// **NOTE:** The name provided may be an argument, or group name
198 | ///
199 | ///
200 | /// # Example
201 | ///
202 | /// ```no_run
203 | /// # use clap::{App, ArgGroup};
204 | /// # let matches = App::new("myprog")
205 | /// # .arg_group(
206 | /// # ArgGroup::with_name("conifg")
207 | /// .requires("config")
208 | /// # ).get_matches();
209 | pub fn requires(mut self,
210 | n: &'ar str)
211 | -> Self {
212 | if let Some(ref mut reqs) = self.requires {
213 | reqs.push(n);
214 | } else {
215 | self.requires = Some(vec![n]);
216 | }
217 | self
218 | }
219 |
220 | /// Sets the requirement rules of this group. This is not to be confused with a required group.
221 | /// Requirement rules function just like argument requirement rules, you can name other
222 | /// arguments or groups that must be present when one of the arguments from this group is used.
223 | ///
224 | /// **NOTE:** The names provided may be an argument, or group name
225 | ///
226 | ///
227 | /// # Example
228 | ///
229 | /// ```no_run
230 | /// # use clap::{App, ArgGroup};
231 | /// # let matches = App::new("myprog")
232 | /// # .arg_group(
233 | /// # ArgGroup::with_name("conifg")
234 | /// .requires_all(&["config", "input"])
235 | /// # ).get_matches();
236 | pub fn requires_all(mut self,
237 | ns: &[&'ar str])
238 | -> Self {
239 | for n in ns {
240 | self = self.requires(n);
241 | }
242 | self
243 | }
244 |
245 | /// Sets the exclusion rules of this group. Exclusion rules function just like argument
246 | /// exclusion rules, you can name other arguments or groups that must not be present when one
247 | /// of the arguments from this group are used.
248 | ///
249 | /// **NOTE:** The name provided may be an argument, or group name
250 | ///
251 | ///
252 | /// # Example
253 | ///
254 | /// ```no_run
255 | /// # use clap::{App, ArgGroup};
256 | /// # let matches = App::new("myprog")
257 | /// # .arg_group(
258 | /// # ArgGroup::with_name("conifg")
259 | /// .conflicts_with("config")
260 | /// # ).get_matches();
261 | pub fn conflicts_with(mut self,
262 | n: &'ar str)
263 | -> Self {
264 | if let Some(ref mut confs) = self.conflicts {
265 | confs.push(n);
266 | } else {
267 | self.conflicts = Some(vec![n]);
268 | }
269 | self
270 | }
271 |
272 | /// Sets the exclusion rules of this group. Exclusion rules function just like argument
273 | /// exclusion rules, you can name other arguments or groups that must not be present when one
274 | /// of the arguments from this group are used.
275 | ///
276 | /// **NOTE:** The names provided may be an argument, or group name
277 | ///
278 | ///
279 | /// # Example
280 | ///
281 | /// ```no_run
282 | /// # use clap::{App, ArgGroup};
283 | /// # let matches = App::new("myprog")
284 | /// # .arg_group(
285 | /// # ArgGroup::with_name("conifg")
286 | /// .conflicts_with_all(&["config", "input"])
287 | /// # ).get_matches();
288 | pub fn conflicts_with_all(mut self,
289 | ns: &[&'ar str])
290 | -> Self {
291 | for n in ns {
292 | self = self.conflicts_with(n);
293 | }
294 | self
295 | }
296 | }
297 |
298 | impl<'n, 'ar> Debug for ArgGroup<'n, 'ar> {
299 | fn fmt(&self,
300 | f: &mut Formatter)
301 | -> Result {
302 | write!(f, "{{
303 | name:{:?},
304 | args: {:?},
305 | required: {:?},
306 | requires: {:?},
307 | conflicts: {:?},
308 | }}", self.name, self.args, self.required, self.requires, self.conflicts)
309 | }
310 | }
311 |
312 | #[cfg(test)]
313 | mod test {
314 | use super::ArgGroup;
315 |
316 | #[test]
317 | fn groups() {
318 | let g = ArgGroup::with_name("test")
319 | .add("a1")
320 | .add_all(&["a2", "a3"])
321 | .add("a4")
322 | .required(true)
323 | .conflicts_with("c1")
324 | .conflicts_with_all(&["c2", "c3"])
325 | .conflicts_with("c4")
326 | .requires("r1")
327 | .requires_all(&["r2", "r3"])
328 | .requires("r4");
329 |
330 | let args = vec!["a1", "a2", "a3", "a4"];
331 | let reqs = vec!["r1", "r2", "r3", "r4"];
332 | let confs = vec!["c1", "c2", "c3", "c4"];
333 |
334 | assert_eq!(g.args, args);
335 | assert_eq!(g.requires.unwrap(), reqs);
336 | assert_eq!(g.conflicts.unwrap(), confs);
337 |
338 | }
339 | }
340 |
--------------------------------------------------------------------------------