2015-09-30 21:14:48 +00:00
|
|
|
#[allow(dead_code)]
|
2015-08-30 21:10:26 +00:00
|
|
|
mod settings;
|
2015-11-09 13:57:20 +00:00
|
|
|
#[macro_use]
|
|
|
|
mod macros;
|
2015-08-30 21:10:26 +00:00
|
|
|
|
|
|
|
pub use self::settings::AppSettings;
|
2015-11-09 08:48:49 +00:00
|
|
|
|
|
|
|
use std::collections::{BTreeMap, HashMap, VecDeque};
|
|
|
|
use std::env;
|
|
|
|
use std::io::{self, BufRead, BufWriter, Write};
|
|
|
|
use std::path::Path;
|
|
|
|
use std::process;
|
|
|
|
use std::ffi::OsStr;
|
|
|
|
use std::borrow::Borrow;
|
2015-11-09 12:21:28 +00:00
|
|
|
use std::fmt::Display;
|
2015-11-09 08:48:49 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "yaml")]
|
|
|
|
use yaml_rust::Yaml;
|
|
|
|
use vec_map::VecMap;
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
use args::{Arg, AnyArg, ArgGroup, ArgMatches, ArgMatcher, SubCommand};
|
2015-11-09 08:48:49 +00:00
|
|
|
use args::{FlagBuilder, OptBuilder, PosBuilder};
|
|
|
|
use args::settings::{ArgFlags, ArgSettings};
|
|
|
|
use fmt::Format;
|
|
|
|
use self::settings::AppFlags;
|
|
|
|
use suggestions;
|
|
|
|
use errors::{ClapError, ClapErrorType, ClapResult, error_builder};
|
|
|
|
|
|
|
|
const INTERNAL_ERROR_MSG: &'static str = "Fatal internal error. Please consider filing a bug \
|
|
|
|
report at https://github.com/kbknapp/clap-rs/issues";
|
|
|
|
|
|
|
|
/// Used to create a representation of a command line program and all possible command line
|
|
|
|
/// arguments.
|
|
|
|
///
|
|
|
|
/// Application settings are set using the "builder pattern" with `.get_matches()` being the
|
|
|
|
/// terminal method that starts the runtime-parsing process and returns information about
|
|
|
|
/// the user supplied arguments (or lack there of).
|
|
|
|
///
|
|
|
|
/// There aren't any mandatory "options" that one must set. The "options" may also appear in any
|
|
|
|
/// order (so long as `.get_matches()` is the last method called).
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// let matches = App::new("myprog")
|
|
|
|
/// .author("Me, me@mail.com")
|
|
|
|
/// .version("1.0.2")
|
|
|
|
/// .about("Explains in brief what the program does")
|
|
|
|
/// .arg(
|
|
|
|
/// Arg::with_name("in_file").index(1)
|
|
|
|
/// )
|
|
|
|
/// .after_help("Longer explaination to appear after the options when \
|
|
|
|
/// displaying the help information from --help or -h")
|
|
|
|
/// .get_matches();
|
|
|
|
///
|
|
|
|
/// // Your program logic starts here...
|
|
|
|
/// ```
|
|
|
|
#[allow(missing_debug_implementations)]
|
|
|
|
pub struct App<'a, 'v, 'ab, 'u, 'h, 'ar> {
|
|
|
|
// The name displayed to the user when showing version and help/usage information
|
|
|
|
name: String,
|
|
|
|
name_slice: &'ar str,
|
|
|
|
// A string of author(s) if desired. Displayed when showing help/usage information
|
|
|
|
author: Option<&'a str>,
|
|
|
|
// The version displayed to the user
|
|
|
|
version: Option<&'v str>,
|
|
|
|
// A brief explanation of the program that gets displayed to the user when shown
|
|
|
|
// help/usage
|
|
|
|
// information
|
|
|
|
about: Option<&'ab str>,
|
|
|
|
// Additional help information
|
|
|
|
more_help: Option<&'h str>,
|
|
|
|
// A list of possible flags
|
|
|
|
flags: Vec<FlagBuilder<'ar>>,
|
|
|
|
// A list of possible options
|
|
|
|
opts: Vec<OptBuilder<'ar>>,
|
|
|
|
// A list of positional arguments
|
|
|
|
positionals: VecMap<PosBuilder<'ar>>,
|
|
|
|
// A list of subcommands
|
|
|
|
subcommands: Vec<App<'a, 'v, 'ab, 'u, 'h, 'ar>>,
|
|
|
|
help_short: Option<char>,
|
|
|
|
version_short: Option<char>,
|
|
|
|
required: Vec<&'ar str>,
|
|
|
|
short_list: Vec<char>,
|
|
|
|
long_list: Vec<&'ar str>,
|
|
|
|
blacklist: Vec<&'ar str>,
|
|
|
|
usage_str: Option<&'u str>,
|
|
|
|
bin_name: Option<String>,
|
|
|
|
usage: Option<String>,
|
|
|
|
groups: HashMap<&'ar str, ArgGroup<'ar, 'ar>>,
|
|
|
|
global_args: Vec<Arg<'ar, 'ar, 'ar, 'ar, 'ar, 'ar>>,
|
|
|
|
help_str: Option<&'u str>,
|
|
|
|
settings: AppFlags,
|
|
|
|
overrides: Vec<&'ar str>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar> {
|
|
|
|
/// Creates a new instance of an application requiring a name (such as the binary). The name
|
|
|
|
/// will be displayed to the user when they request to print version or help and usage
|
|
|
|
/// information. The name should not contain spaces (hyphens '-' are ok).
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// let prog = App::new("myprog")
|
|
|
|
/// # .get_matches();
|
|
|
|
/// ```
|
|
|
|
pub fn new(n: &'ar str) -> Self {
|
|
|
|
App {
|
|
|
|
name: n.to_owned(),
|
|
|
|
name_slice: n,
|
|
|
|
author: None,
|
|
|
|
about: None,
|
|
|
|
more_help: None,
|
|
|
|
version: None,
|
|
|
|
flags: vec![],
|
|
|
|
opts: vec![],
|
|
|
|
positionals: VecMap::new(),
|
|
|
|
subcommands: vec![],
|
|
|
|
help_short: None,
|
|
|
|
version_short: None,
|
|
|
|
required: vec![],
|
|
|
|
short_list: vec![],
|
|
|
|
long_list: vec![],
|
|
|
|
usage_str: None,
|
|
|
|
usage: None,
|
|
|
|
blacklist: vec![],
|
|
|
|
bin_name: None,
|
|
|
|
groups: HashMap::new(),
|
|
|
|
global_args: vec![],
|
|
|
|
help_str: None,
|
|
|
|
overrides: vec![],
|
|
|
|
settings: AppFlags::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates a new instace of `App` from a .yml (YAML) file. The YAML file must be properly
|
|
|
|
/// formatted or this function will panic!(). A full example of supported YAML objects can be
|
|
|
|
/// found in `examples/17_yaml.rs` and `examples/17_yaml.yml`.
|
|
|
|
///
|
|
|
|
/// In order to use this function you must compile with the `features = ["yaml"]` in your
|
|
|
|
/// settings for `[dependencies.clap]` table of your `Cargo.toml`
|
|
|
|
///
|
|
|
|
/// Note, due to how the YAML objects are built there is a convienience macro for loading the
|
|
|
|
/// YAML file (relative to the current file, like modules work). That YAML object can then be
|
|
|
|
/// passed to this function.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```ignore
|
|
|
|
/// # use clap::App;
|
|
|
|
/// let yml = load_yaml!("app.yml");
|
|
|
|
/// let app = App::from_yaml(yml);
|
|
|
|
/// ```
|
|
|
|
#[cfg(feature = "yaml")]
|
|
|
|
pub fn from_yaml<'y>(mut yaml: &'y Yaml) -> App<'y, 'y, 'y, 'y, 'y, 'y> {
|
|
|
|
// We WANT this to panic on error...so expect() is good.
|
|
|
|
let mut is_sc = None;
|
|
|
|
let mut a = if let Some(name) = yaml["name"].as_str() {
|
|
|
|
App::new(name)
|
|
|
|
} else {
|
|
|
|
let yaml_hash = yaml.as_hash().unwrap();
|
|
|
|
let sc_key = yaml_hash.keys().nth(0).unwrap();
|
|
|
|
is_sc = Some(yaml_hash.get(sc_key).unwrap());
|
|
|
|
App::new(sc_key.as_str().unwrap())
|
|
|
|
};
|
|
|
|
yaml = if let Some(sc) = is_sc {
|
|
|
|
sc
|
|
|
|
} else {
|
|
|
|
yaml
|
|
|
|
};
|
|
|
|
if let Some(v) = yaml["version"].as_str() {
|
|
|
|
a = a.version(v);
|
|
|
|
}
|
|
|
|
if let Some(v) = yaml["author"].as_str() {
|
|
|
|
a = a.author(v);
|
|
|
|
}
|
|
|
|
if let Some(v) = yaml["bin_name"].as_str() {
|
|
|
|
a = a.bin_name(v);
|
|
|
|
}
|
|
|
|
if let Some(v) = yaml["about"].as_str() {
|
|
|
|
a = a.about(v);
|
|
|
|
}
|
|
|
|
if let Some(v) = yaml["after_help"].as_str() {
|
|
|
|
a = a.after_help(v);
|
|
|
|
}
|
|
|
|
if let Some(v) = yaml["usage"].as_str() {
|
|
|
|
a = a.usage(v);
|
|
|
|
}
|
|
|
|
if let Some(v) = yaml["help"].as_str() {
|
|
|
|
a = a.help(v);
|
|
|
|
}
|
|
|
|
if let Some(v) = yaml["help_short"].as_str() {
|
|
|
|
a = a.help_short(v);
|
|
|
|
}
|
|
|
|
if let Some(v) = yaml["version_short"].as_str() {
|
|
|
|
a = a.version_short(v);
|
|
|
|
}
|
|
|
|
if let Some(v) = yaml["settings"].as_vec() {
|
|
|
|
for ys in v {
|
|
|
|
if let Some(s) = ys.as_str() {
|
|
|
|
a = a.setting(s.parse().ok().expect("unknown AppSetting found in YAML file"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(v) = yaml["args"].as_vec() {
|
|
|
|
for arg_yaml in v {
|
|
|
|
a = a.arg(Arg::from_yaml(&arg_yaml.as_hash().unwrap()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(v) = yaml["subcommands"].as_vec() {
|
|
|
|
for sc_yaml in v {
|
|
|
|
a = a.subcommand(SubCommand::from_yaml(&sc_yaml));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(v) = yaml["arg_groups"].as_vec() {
|
|
|
|
for ag_yaml in v {
|
|
|
|
a = a.arg_group(ArgGroup::from_yaml(&ag_yaml.as_hash().unwrap()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
a
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets a string of author(s) and will be displayed to the user when they request the help
|
|
|
|
/// information with `--help` or `-h`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .author("Me, me@mymain.com")
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn author(mut self, a: &'a str) -> Self {
|
|
|
|
self.author = Some(a);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Overrides the system-determined binary name. This should only be used when absolutely
|
|
|
|
/// neccessary, such as the binary name for your application is misleading, or perhaps *not*
|
|
|
|
/// how the user should invoke your program.
|
|
|
|
///
|
|
|
|
/// **NOTE:** This command **should not** be used for SubCommands.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .bin_name("my_binary")
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn bin_name(mut self, a: &str) -> Self {
|
|
|
|
self.bin_name = Some(a.to_owned());
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets a string briefly describing what the program does and will be displayed when
|
|
|
|
/// displaying help information.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .about("Does really amazing things to great people")
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn about(mut self, a: &'ab str) -> Self {
|
|
|
|
self.about = Some(a);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds additional help information to be displayed in addition to and directly after
|
|
|
|
/// auto-generated help. This information is displayed **after** the auto-generated help
|
|
|
|
/// information. This additional help is often used to describe how to use the arguments,
|
|
|
|
/// or caveats to be noted.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::App;
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .after_help("Does really amazing things to great people")
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn after_help(mut self, h: &'h str) -> Self {
|
|
|
|
self.more_help = Some(h);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Allows subcommands to override all requirements of the parent (this command). For example
|
|
|
|
/// if you had a subcommand or even top level application which had a required arguments that
|
|
|
|
/// are only required as long as there is no subcommand present.
|
|
|
|
///
|
|
|
|
/// **Deprecated:** Use `App::setting()` with `AppSettings::SubcommandsNegateReqs` instead.
|
|
|
|
/// This method will be removed at 2.x
|
|
|
|
///
|
|
|
|
/// **NOTE:** This defaults to false (using subcommand does *not* negate requirements)
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::App;
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .subcommands_negate_reqs(true)
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn subcommands_negate_reqs(mut self, n: bool) -> Self {
|
|
|
|
if n {
|
|
|
|
self.settings.set(&AppSettings::SubcommandsNegateReqs);
|
|
|
|
} else {
|
|
|
|
self.settings.unset(&AppSettings::SubcommandsNegateReqs);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Allows specifying that if no subcommand is present at runtime, error and exit gracefully
|
|
|
|
///
|
|
|
|
/// **Deprecated:** Use `App::setting()` with `AppSettings::SubcommandRequired` instead. This
|
|
|
|
/// method will be removed at 2.x
|
|
|
|
///
|
|
|
|
/// **NOTE:** This defaults to false (subcommands do *not* need to be present)
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::App;
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .subcommand_required(true)
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn subcommand_required(mut self, n: bool) -> Self {
|
|
|
|
if n {
|
|
|
|
self.settings.set(&AppSettings::SubcommandRequired);
|
|
|
|
} else {
|
|
|
|
self.settings.unset(&AppSettings::SubcommandRequired);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets a string of the version number to be displayed when displaying version or help
|
|
|
|
/// information.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .version("v0.1.24")
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn version(mut self, v: &'v str) -> Self {
|
|
|
|
self.version = Some(v);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets a custom usage string to override the auto-generated usage string.
|
|
|
|
///
|
|
|
|
/// This will be displayed to the user when errors are found in argument parsing, or when you
|
2015-11-09 13:57:20 +00:00
|
|
|
/// call `ArgMatcher::usage()`
|
2015-11-09 08:48:49 +00:00
|
|
|
///
|
|
|
|
/// **NOTE:** You do not need to specify the "USAGE: \n\t" portion, as that will
|
|
|
|
/// still be applied by `clap`, you only need to specify the portion starting
|
|
|
|
/// with the binary name.
|
|
|
|
///
|
|
|
|
/// **NOTE:** This will not replace the entire help message, *only* the portion
|
|
|
|
/// showing the usage.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .usage("myapp [-clDas] <some_file>")
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn usage(mut self, u: &'u str) -> Self {
|
|
|
|
self.usage_str = Some(u);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets a custom help message and overrides the auto-generated one. This should only be used
|
|
|
|
/// when the auto-generated message does not suffice.
|
|
|
|
///
|
|
|
|
/// This will be displayed to the user when they use the default `--help` or `-h`
|
|
|
|
///
|
|
|
|
/// **NOTE:** This replaces the **entire** help message, so nothing will be auto-generated.
|
|
|
|
///
|
|
|
|
/// **NOTE:** This **only** replaces the help message for the current command, meaning if you
|
|
|
|
/// are using subcommands, those help messages will still be auto-generated unless you
|
|
|
|
/// specify a `.help()` for them as well.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myapp")
|
|
|
|
/// .help("myapp v1.0\n\
|
|
|
|
/// Does awesome things\n\
|
|
|
|
/// (C) me@mail.com\n\n\
|
|
|
|
///
|
|
|
|
/// USAGE: myapp <opts> <comamnd>\n\n\
|
|
|
|
///
|
|
|
|
/// Options:\n\
|
|
|
|
/// -h, --helpe Dispay this message\n\
|
|
|
|
/// -V, --version Display version info\n\
|
|
|
|
/// -s <stuff> Do something with stuff\n\
|
|
|
|
/// -v Be verbose\n\n\
|
|
|
|
///
|
|
|
|
/// Commmands:\n\
|
|
|
|
/// help Prints this message\n\
|
|
|
|
/// work Do some work")
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn help(mut self, h: &'u str) -> Self {
|
|
|
|
self.help_str = Some(h);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the short version of the `help` argument without the preceding `-`.
|
|
|
|
///
|
|
|
|
/// By default `clap` automatically assigns `h`, but this can be overridden
|
|
|
|
///
|
|
|
|
/// **NOTE:** Any leading `-` characters will be stripped, and only the first
|
|
|
|
/// non `-` chacter will be used as the `short` version
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// // Using an uppercase `H` instead of the default lowercase `h`
|
|
|
|
/// .help_short("H")
|
|
|
|
/// # ;
|
|
|
|
pub fn help_short(mut self, s: &str) -> Self {
|
|
|
|
self.help_short = s.trim_left_matches(|c| c == '-')
|
|
|
|
.chars()
|
|
|
|
.nth(0);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the short version of the `version` argument without the preceding `-`.
|
|
|
|
///
|
|
|
|
/// By default `clap` automatically assigns `V`, but this can be overridden
|
|
|
|
///
|
|
|
|
/// **NOTE:** Any leading `-` characters will be stripped, and only the first
|
|
|
|
/// non `-` chacter will be used as the `short` version
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// // Using a lowercase `v` instead of the default capital `V`
|
|
|
|
/// .version_short("v")
|
|
|
|
/// # ;
|
|
|
|
pub fn version_short(mut self, s: &str) -> Self {
|
|
|
|
self.version_short = s.trim_left_matches(|c| c == '-')
|
|
|
|
.chars()
|
|
|
|
.nth(0);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Specifies that the help text sould be displayed (and then exit gracefully), if no
|
|
|
|
/// arguments are present at runtime (i.e. an empty run such as, `$ myprog`.
|
|
|
|
///
|
|
|
|
/// **Deprecated:** Use `App::setting()` with `AppSettings::ArgRequiredElseHelp` instead. This
|
|
|
|
/// method will be removed at 2.x
|
|
|
|
///
|
|
|
|
/// **NOTE:** Subcommands count as arguments
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .arg_required_else_help(true)
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn arg_required_else_help(mut self, tf: bool) -> Self {
|
|
|
|
if tf {
|
|
|
|
self.settings.set(&AppSettings::ArgRequiredElseHelp);
|
|
|
|
} else {
|
|
|
|
self.settings.unset(&AppSettings::ArgRequiredElseHelp);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Hides a subcommand from help message output.
|
|
|
|
///
|
|
|
|
/// **NOTE:** This does **not** hide the subcommand from usage strings on error
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, SubCommand};
|
|
|
|
/// # let matches = App::new("myprog")
|
|
|
|
/// # .subcommand(
|
|
|
|
/// # SubCommand::with_name("debug")
|
|
|
|
/// .hidden(true)
|
|
|
|
/// # ).get_matches();
|
|
|
|
pub fn hidden(mut self, h: bool) -> Self {
|
|
|
|
if h {
|
|
|
|
self.settings.set(&AppSettings::Hidden);
|
|
|
|
} else {
|
|
|
|
self.settings.unset(&AppSettings::Hidden);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Uses version of the current command for all subcommands. (Defaults to false; subcommands
|
|
|
|
/// have independant version strings)
|
|
|
|
///
|
|
|
|
/// **Deprecated:** Use `App::setting()` with `AppSettings::GlobalVersion` instead. This
|
|
|
|
/// method will be removed at 2.x
|
|
|
|
///
|
|
|
|
/// **NOTE:** The version for the current command and this setting must be set **prior** to
|
|
|
|
/// adding any subcommands
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg, SubCommand};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .version("v1.1")
|
|
|
|
/// .global_version(true)
|
|
|
|
/// .subcommand(SubCommand::with_name("test"))
|
|
|
|
/// .get_matches();
|
|
|
|
/// // running `myprog test --version` will display
|
|
|
|
/// // "myprog-test v1.1"
|
|
|
|
/// ```
|
|
|
|
pub fn global_version(mut self, gv: bool) -> Self {
|
|
|
|
if gv {
|
|
|
|
self.settings.set(&AppSettings::GlobalVersion);
|
|
|
|
} else {
|
|
|
|
self.settings.unset(&AppSettings::GlobalVersion);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Disables `-V` and `--version` for all subcommands (Defaults to false; subcommands have
|
|
|
|
/// version flags)
|
|
|
|
///
|
|
|
|
/// **Deprecated:** Use `App::setting()` with `AppSettings::VersionlessSubcommands` instead.
|
|
|
|
/// This method will be removed at 2.x
|
|
|
|
///
|
|
|
|
/// **NOTE:** This setting must be set **prior** adding any subcommands
|
|
|
|
///
|
|
|
|
/// **NOTE:** Do not set this value to false, it will have undesired results!
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg, SubCommand};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .version("v1.1")
|
|
|
|
/// .versionless_subcommands(true)
|
|
|
|
/// .subcommand(SubCommand::with_name("test"))
|
|
|
|
/// .get_matches();
|
|
|
|
/// // running `myprog test --version` will display unknown argument error
|
|
|
|
/// ```
|
|
|
|
pub fn versionless_subcommands(mut self, vers: bool) -> Self {
|
|
|
|
if vers {
|
|
|
|
self.settings.set(&AppSettings::VersionlessSubcommands);
|
|
|
|
} else {
|
|
|
|
self.settings.unset(&AppSettings::VersionlessSubcommands);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// By default the auto-generated help message groups flags, options, and positional arguments
|
|
|
|
/// separately. This setting disable that and groups flags and options together presenting a
|
|
|
|
/// more unified help message (a la getopts or docopt style).
|
|
|
|
///
|
|
|
|
/// **Deprecated:** Use `App::setting()` with `AppSettings::UnifiedHelpMessage` instead. This
|
|
|
|
/// method will be removed at 2.x
|
|
|
|
///
|
|
|
|
/// **NOTE:** This setting is cosmetic only and does not affect any functionality.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg, SubCommand};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .unified_help_message(true)
|
|
|
|
/// .get_matches();
|
|
|
|
/// // running `myprog --help` will display a unified "docopt" or "getopts" style help message
|
|
|
|
/// ```
|
|
|
|
pub fn unified_help_message(mut self, uni_help: bool) -> Self {
|
|
|
|
if uni_help {
|
|
|
|
self.settings.set(&AppSettings::UnifiedHelpMessage);
|
|
|
|
} else {
|
|
|
|
self.settings.unset(&AppSettings::UnifiedHelpMessage);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Will display a message "Press [ENTER]/[RETURN] to continue..." and wait user before
|
|
|
|
/// exiting
|
|
|
|
///
|
|
|
|
/// This is most useful when writing an application which is run from a GUI shortcut, or on
|
|
|
|
/// Windows where a user tries to open the binary by double-clicking instead of using the
|
|
|
|
/// command line (i.e. set `.arg_required_else_help(true)` and `.wait_on_error(true)` to
|
|
|
|
/// display the help in such a case).
|
|
|
|
///
|
|
|
|
/// **Deprecated:** Use `App::setting()` with `AppSettings::WaitOnError` instead. This
|
|
|
|
/// method will be removed at 2.x
|
|
|
|
///
|
|
|
|
/// **NOTE:** This setting is **not** recursive with subcommands, meaning if you wish this
|
|
|
|
/// behavior for all subcommands, you must set this on each command (needing this is extremely
|
|
|
|
/// rare)
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .arg_required_else_help(true)
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn wait_on_error(mut self, w: bool) -> Self {
|
|
|
|
if w {
|
|
|
|
self.settings.set(&AppSettings::WaitOnError);
|
|
|
|
} else {
|
|
|
|
self.settings.unset(&AppSettings::WaitOnError);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Specifies that the help text sould be displayed (and then exit gracefully), if no
|
|
|
|
/// subcommands are present at runtime (i.e. an empty run such as, `$ myprog`.
|
|
|
|
///
|
|
|
|
/// **Deprecated:** Use `App::setting()` with `AppSettings::SubcommandRequiredElseHelp`
|
|
|
|
/// instead. This method will be removed at 2.x
|
|
|
|
///
|
|
|
|
/// **NOTE:** This should *not* be used with `.subcommand_required()` as they do the same
|
|
|
|
/// thing, except one prints the help text, and one prints an error.
|
|
|
|
///
|
|
|
|
/// **NOTE:** If the user specifies arguments at runtime, but no subcommand the help text will
|
|
|
|
/// still be displayed and exit. If this is *not* the desired result, consider using
|
|
|
|
/// `.arg_required_else_help()`
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .subcommand_required_else_help(true)
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn subcommand_required_else_help(mut self, tf: bool) -> Self {
|
|
|
|
if tf {
|
|
|
|
self.settings.set(&AppSettings::SubcommandRequiredElseHelp);
|
|
|
|
} else {
|
|
|
|
self.settings.unset(&AppSettings::SubcommandRequiredElseHelp);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Enables Application level settings, passed as argument
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg, AppSettings};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .setting(AppSettings::SubcommandRequired)
|
|
|
|
/// .setting(AppSettings::WaitOnError)
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn setting(mut self, setting: AppSettings) -> Self {
|
|
|
|
self.settings.set(&setting);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Enables multiple Application level settings, passed as argument
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg, AppSettings};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .settings( &[AppSettings::SubcommandRequired,
|
|
|
|
/// AppSettings::WaitOnError])
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn settings(mut self, settings: &[AppSettings]) -> Self {
|
|
|
|
for s in settings {
|
|
|
|
self.settings.set(s);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds an argument to the list of valid possibilties manually. This method allows you full
|
|
|
|
/// control over the arguments settings and options (as well as dynamic generation). It also
|
|
|
|
/// allows you specify several more advanced configuration options such as relational rules
|
|
|
|
/// (exclusions and requirements).
|
|
|
|
///
|
|
|
|
/// The only disadvantage to this method is that it's more verbose, and arguments must be added
|
|
|
|
/// one at a time. Using `Arg::from_usage` helps with the verbosity, and still allows full
|
|
|
|
/// control over the advanced configuration options.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// // Adding a single "flag" argument with a short and help text, using Arg::with_name()
|
|
|
|
/// .arg(
|
|
|
|
/// Arg::with_name("debug")
|
|
|
|
/// .short("d")
|
|
|
|
/// .help("turns on debugging mode")
|
|
|
|
/// )
|
|
|
|
/// // Adding a single "option" argument with a short, a long, and help text using the less
|
|
|
|
/// // verbose Arg::from_usage()
|
|
|
|
/// .arg(
|
|
|
|
/// Arg::from_usage("-c --config=[CONFIG] 'Optionally sets a config file to use'")
|
|
|
|
/// )
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn arg(mut self, a: Arg<'ar, 'ar, 'ar, 'ar, 'ar, 'ar>) -> Self {
|
|
|
|
self.add_arg(a);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
// actually adds the arguments
|
|
|
|
fn add_arg(&mut self, a: Arg<'ar, 'ar, 'ar, 'ar, 'ar, 'ar>) {
|
|
|
|
if self.flags.iter().any(|f| &f.name == &a.name) ||
|
|
|
|
self.opts.iter().any(|o| o.name == a.name) ||
|
|
|
|
self.positionals.values().any(|p| p.name == a.name) {
|
|
|
|
panic!("Non-unique argument name: {} is already in use", a.name);
|
|
|
|
}
|
|
|
|
if let Some(grp) = a.group {
|
|
|
|
let ag = self.groups.entry(grp).or_insert(ArgGroup::with_name(grp));
|
|
|
|
ag.args.push(a.name);
|
|
|
|
}
|
|
|
|
if let Some(s) = a.short {
|
|
|
|
if self.short_list.contains(&s) {
|
|
|
|
panic!("Argument short must be unique\n\n\t-{} is already in use",
|
|
|
|
s);
|
|
|
|
} else {
|
|
|
|
self.short_list.push(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(l) = a.long {
|
|
|
|
if self.long_list.contains(&l) {
|
|
|
|
panic!("Argument long must be unique\n\n\t--{} is already in use",
|
|
|
|
l);
|
|
|
|
} else {
|
|
|
|
self.long_list.push(l);
|
|
|
|
}
|
|
|
|
if l == "help" {
|
|
|
|
self.settings.set(&AppSettings::NeedsLongHelp);
|
|
|
|
} else if l == "version" {
|
|
|
|
self.settings.set(&AppSettings::NeedsLongVersion);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if a.required {
|
|
|
|
self.required.push(a.name);
|
|
|
|
}
|
|
|
|
if a.index.is_some() || (a.short.is_none() && a.long.is_none()) {
|
|
|
|
let i = if a.index.is_none() {
|
|
|
|
(self.positionals.len() + 1)
|
|
|
|
} else {
|
|
|
|
a.index.unwrap() as usize
|
|
|
|
};
|
|
|
|
if self.positionals.contains_key(&i) {
|
|
|
|
panic!("Argument \"{}\" has the same index as another positional \
|
|
|
|
argument\n\n\tPerhaps try .multiple(true) to allow one positional argument \
|
|
|
|
to take multiple values",
|
|
|
|
a.name);
|
|
|
|
}
|
|
|
|
let pb = PosBuilder::from_arg(&a, i as u8, &mut self.required);
|
|
|
|
// self.positionals_name.insert(pb.name, i);
|
|
|
|
self.positionals.insert(i, pb);
|
|
|
|
} else if a.takes_value {
|
|
|
|
let ob = OptBuilder::from_arg(&a, &mut self.required);
|
|
|
|
self.opts.push(ob);
|
|
|
|
} else {
|
|
|
|
let fb = FlagBuilder::from(&a);
|
|
|
|
self.flags.push(fb);
|
|
|
|
}
|
|
|
|
if a.global {
|
|
|
|
if a.required {
|
|
|
|
panic!("Global arguments cannot be required.\n\n\t'{}' is marked as global and \
|
|
|
|
required",
|
|
|
|
a.name);
|
|
|
|
}
|
|
|
|
self.global_args.push(a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds multiple arguments to the list of valid possibilties by iterating over a Vec of Args
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .args(
|
|
|
|
/// vec![Arg::from_usage("[debug] -d 'turns on debugging info"),
|
|
|
|
/// Arg::with_name("input").index(1).help("the input file to use")]
|
|
|
|
/// )
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn args(mut self, args: Vec<Arg<'ar, 'ar, 'ar, 'ar, 'ar, 'ar>>) -> Self {
|
|
|
|
for arg in args.into_iter() {
|
|
|
|
self = self.arg(arg);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A convienience method for adding a single basic argument (one without advanced
|
|
|
|
/// relational rules) from a usage type string. The string used follows the same rules and
|
|
|
|
/// syntax as `Arg::from_usage()`
|
|
|
|
///
|
|
|
|
/// The downside to using this method is that you can not set any additional properties of the
|
|
|
|
/// `Arg` other than what `Arg::from_usage()` supports.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .arg_from_usage("-c --conf=<config> 'Sets a configuration file to use'")
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn arg_from_usage(mut self, usage: &'ar str) -> Self {
|
|
|
|
self = self.arg(Arg::from_usage(usage));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds multiple arguments at once from a usage string, one per line. See `Arg::from_usage()`
|
|
|
|
/// for details on the syntax and rules supported.
|
|
|
|
///
|
|
|
|
/// Like `App::arg_from_usage()` the downside is you only set properties for the `Arg`s which
|
|
|
|
/// `Arg::from_usage()` supports. But here the benefit is pretty strong, as the readability is
|
|
|
|
/// greatly enhanced, especially if you don't need any of the more advanced configuration
|
|
|
|
/// options.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// App::new("myprog")
|
|
|
|
/// .args_from_usage(
|
|
|
|
/// "-c --conf=[config] 'Sets a configuration file to use'
|
|
|
|
/// [debug]... -d 'Sets the debugging level'
|
|
|
|
/// <input> 'The input file to use'"
|
|
|
|
/// )
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn args_from_usage(mut self, usage: &'ar str) -> Self {
|
|
|
|
for l in usage.lines() {
|
|
|
|
self = self.arg(Arg::from_usage(l.trim()));
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds an ArgGroup to the application. ArgGroups are a family of related arguments. By
|
|
|
|
/// placing them in a logical group, you make easier requirement and exclusion rules. For
|
|
|
|
/// instance, you can make an ArgGroup required, this means that one (and *only* one) argument
|
|
|
|
/// from that group must be present. Using more than one argument from an ArgGroup causes a
|
|
|
|
/// failure (graceful exit).
|
|
|
|
///
|
|
|
|
/// You can also do things such as name an ArgGroup as a confliction, meaning any of the
|
|
|
|
/// arguments that belong to that group will cause a failure if present.
|
|
|
|
///
|
|
|
|
/// Perhaps the most common use of ArgGroups is to require one and *only* one argument to be
|
|
|
|
/// present out of a given set. For example, lets say that you were building an application
|
|
|
|
/// where one could set a given version number by supplying a string using an option argument,
|
|
|
|
/// such as `--set-ver v1.2.3`, you also wanted to support automatically using a previous
|
|
|
|
/// version numer and simply incrementing one of the three numbers, so you create three flags
|
|
|
|
/// `--major`, `--minor`, and `--patch`. All of these arguments shouldn't be used at one time
|
|
|
|
/// but perhaps you want to specify that *at least one* of them is used. You can create a
|
|
|
|
/// group
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, ArgGroup};
|
|
|
|
/// # App::new("app")
|
|
|
|
/// .args_from_usage("--set-ver [ver] 'set the version manually'
|
|
|
|
/// --major 'auto increase major'
|
|
|
|
/// --minor 'auto increase minor'
|
|
|
|
/// --patch 'auto increase patch")
|
|
|
|
/// .arg_group(ArgGroup::with_name("vers")
|
|
|
|
/// .add_all(&["ver", "major", "minor","patch"])
|
|
|
|
/// .required(true))
|
|
|
|
/// # ;
|
|
|
|
pub fn arg_group(mut self, group: ArgGroup<'ar, 'ar>) -> Self {
|
|
|
|
if group.required {
|
|
|
|
self.required.push(group.name);
|
|
|
|
if let Some(ref reqs) = group.requires {
|
|
|
|
for r in reqs {
|
|
|
|
self.required.push(r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(ref bl) = group.conflicts {
|
|
|
|
for b in bl {
|
|
|
|
self.blacklist.push(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let mut found = false;
|
|
|
|
if let Some(ref mut grp) = self.groups.get_mut(group.name) {
|
|
|
|
for a in &group.args {
|
|
|
|
grp.args.push(a);
|
|
|
|
}
|
|
|
|
grp.requires = group.requires.clone();
|
|
|
|
grp.conflicts = group.conflicts.clone();
|
|
|
|
grp.required = group.required;
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
self.groups.insert(group.name, group);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds a ArgGroups to the application. ArgGroups are a family of related arguments. By
|
|
|
|
/// placing them in a logical group, you make easier requirement and exclusion rules. For
|
|
|
|
/// instance, you can make an ArgGroup required, this means that one (and *only* one) argument
|
|
|
|
/// from that group must be present. Using more than one argument from an ArgGroup causes a
|
|
|
|
/// failure (graceful exit).
|
|
|
|
///
|
|
|
|
/// You can also do things such as name an ArgGroup as a confliction, meaning any of the
|
|
|
|
/// arguments that belong to that group will cause a failure if present.
|
|
|
|
///
|
|
|
|
/// Perhaps the most common use of ArgGroups is to require one and *only* one argument to be
|
|
|
|
/// present out of a given set. For example, lets say that you were building an application
|
|
|
|
/// where one could set a given version number by supplying a string using an option argument,
|
|
|
|
/// such as `--set-ver v1.2.3`, you also wanted to support automatically using a previous
|
|
|
|
/// version numer and simply incrementing one of the three numbers, so you create three flags
|
|
|
|
/// `--major`, `--minor`, and `--patch`. All of these arguments shouldn't be used at one time
|
|
|
|
/// but perhaps you want to specify that *at least one* of them is used. You can create a
|
|
|
|
/// group
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, ArgGroup};
|
|
|
|
/// # App::new("app")
|
|
|
|
/// .args_from_usage("--set-ver [ver] 'set the version manually'
|
|
|
|
/// --major 'auto increase major'
|
|
|
|
/// --minor 'auto increase minor'
|
|
|
|
/// --patch 'auto increase patch")
|
|
|
|
/// .arg_group(ArgGroup::with_name("vers")
|
|
|
|
/// .add_all(&["ver", "major", "minor","patch"])
|
|
|
|
/// .required(true))
|
|
|
|
/// # ;
|
|
|
|
pub fn arg_groups(mut self, groups: Vec<ArgGroup<'ar, 'ar>>) -> Self {
|
|
|
|
for g in groups {
|
|
|
|
self = self.arg_group(g);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds a subcommand to the list of valid possibilties. Subcommands are effectively sub apps,
|
|
|
|
/// because they can contain their own arguments, subcommands, version, usage, etc. They also
|
|
|
|
/// function just like apps, in that they get their own auto generated help, version, and
|
|
|
|
/// usage.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg, SubCommand};
|
|
|
|
/// # App::new("myprog")
|
|
|
|
/// .subcommand(SubCommand::with_name("config")
|
|
|
|
/// .about("Controls configuration features")
|
|
|
|
/// .arg_from_usage("<config> 'Required configuration file to use'"))
|
|
|
|
/// // Additional subcommand configuration goes here, such as other arguments...
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn subcommand(mut self, mut subcmd: App<'a, 'v, 'ab, 'u, 'h, 'ar>) -> Self {
|
|
|
|
if subcmd.name == "help" {
|
|
|
|
self.settings.set(&AppSettings::NeedsSubcommandHelp);
|
|
|
|
}
|
|
|
|
if self.settings.is_set(&AppSettings::VersionlessSubcommands) {
|
|
|
|
subcmd.settings.set(&AppSettings::DisableVersion);
|
|
|
|
}
|
|
|
|
if self.settings.is_set(&AppSettings::GlobalVersion) && subcmd.version.is_none() &&
|
|
|
|
self.version.is_some() {
|
|
|
|
subcmd.version = Some(self.version.unwrap());
|
|
|
|
}
|
|
|
|
self.subcommands.push(subcmd);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds multiple subcommands to the list of valid possibilties by iterating over a Vec of
|
|
|
|
/// `SubCommand`s
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg, SubCommand};
|
|
|
|
/// # App::new("myprog")
|
|
|
|
/// .subcommands( vec![
|
|
|
|
/// SubCommand::with_name("config").about("Controls configuration functionality")
|
|
|
|
/// .arg(Arg::with_name("config_file").index(1)),
|
|
|
|
/// SubCommand::with_name("debug").about("Controls debug functionality")])
|
|
|
|
/// # ;
|
|
|
|
/// ```
|
|
|
|
pub fn subcommands(mut self, subcmds: Vec<App<'a, 'v, 'ab, 'u, 'h, 'ar>>) -> Self {
|
|
|
|
for subcmd in subcmds.into_iter() {
|
|
|
|
self = self.subcommand(subcmd);
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
// Creates a usage string if one was not provided by the user manually. This
|
|
|
|
// happens just
|
|
|
|
// after all arguments were parsed, but before any subcommands have been parsed
|
|
|
|
// (so as to
|
|
|
|
// give subcommands their own usage recursively)
|
2015-11-09 13:57:20 +00:00
|
|
|
fn create_usage(&self, matcher: &[&'ar str]) -> ClapResult<String> {
|
2015-11-09 08:48:49 +00:00
|
|
|
let mut usage = String::with_capacity(75);
|
|
|
|
usage.push_str("USAGE:\n\t");
|
|
|
|
if let Some(u) = self.usage_str {
|
|
|
|
usage.push_str(u);
|
2015-11-09 13:57:20 +00:00
|
|
|
} else if !matcher.is_empty() {
|
|
|
|
try!(self.usage_from_matcher(&mut usage, matcher));
|
2015-11-09 08:48:49 +00:00
|
|
|
} else {
|
|
|
|
usage.push_str(&*self.usage
|
|
|
|
.as_ref()
|
|
|
|
.unwrap_or(self.bin_name
|
|
|
|
.as_ref()
|
|
|
|
.unwrap_or(&self.name)));
|
|
|
|
|
|
|
|
let reqs = self.required.iter().map(|n| *n).collect::<Vec<_>>();
|
|
|
|
let req_strings = self.get_required_from(&reqs, None);
|
|
|
|
let req_string = req_strings.iter()
|
|
|
|
.fold(String::new(), |a, s| a + &format!(" {}", s)[..]);
|
|
|
|
|
|
|
|
if !self.flags.is_empty() && !self.settings.is_set(&AppSettings::UnifiedHelpMessage) {
|
|
|
|
usage.push_str(" [FLAGS]");
|
|
|
|
} else {
|
|
|
|
usage.push_str(" [OPTIONS]");
|
|
|
|
}
|
|
|
|
if !self.settings.is_set(&AppSettings::UnifiedHelpMessage) && !self.opts.is_empty() &&
|
|
|
|
self.opts.iter().any(|a| !a.settings.is_set(&ArgSettings::Required)) {
|
|
|
|
usage.push_str(" [OPTIONS]");
|
|
|
|
}
|
|
|
|
|
|
|
|
usage.push_str(&req_string[..]);
|
|
|
|
|
|
|
|
// places a '--' in the usage string if there are args and options
|
|
|
|
// supporting multiple values
|
|
|
|
if !self.positionals.is_empty() &&
|
|
|
|
(self.opts.iter().any(|a| a.settings.is_set(&ArgSettings::Multiple)) ||
|
|
|
|
self.positionals.values().any(|a| a.settings.is_set(&ArgSettings::Multiple))) &&
|
|
|
|
!self.opts.iter().any(|a| a.settings.is_set(&ArgSettings::Required)) &&
|
|
|
|
self.subcommands.is_empty() {
|
|
|
|
usage.push_str(" [--]")
|
|
|
|
}
|
|
|
|
if !self.positionals.is_empty() &&
|
|
|
|
self.positionals
|
|
|
|
.values()
|
|
|
|
.any(|a| !a.settings.is_set(&ArgSettings::Required)) {
|
|
|
|
usage.push_str(" [ARGS]");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if !self.subcommands.is_empty() &&
|
|
|
|
!self.settings.is_set(&AppSettings::SubcommandRequired) {
|
|
|
|
usage.push_str(" [SUBCOMMAND]");
|
|
|
|
} else if self.settings.is_set(&AppSettings::SubcommandRequired) &&
|
|
|
|
!self.subcommands.is_empty() {
|
|
|
|
usage.push_str(" <SUBCOMMAND>");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
usage.shrink_to_fit();
|
|
|
|
Ok(usage)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Creates a context aware usage string, or "smart usage" from currently used
|
|
|
|
// args, and
|
|
|
|
// requirements
|
2015-11-09 13:57:20 +00:00
|
|
|
fn usage_from_matcher(&self, usage: &mut String, matcher: &[&'ar str]) -> ClapResult<()> {
|
2015-11-09 08:48:49 +00:00
|
|
|
use std::fmt::Write;
|
|
|
|
let mut hs: Vec<&str> = self.required.iter().map(|n| *n).collect();
|
2015-11-09 13:57:20 +00:00
|
|
|
for n in matcher {
|
2015-11-09 08:48:49 +00:00
|
|
|
hs.push(*n);
|
|
|
|
}
|
|
|
|
let reqs = self.get_required_from(&hs, None);
|
|
|
|
|
|
|
|
let r_string = reqs.iter().fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
|
|
|
|
|
|
|
|
try!(write!(usage,
|
|
|
|
"{}{}",
|
|
|
|
self.usage
|
|
|
|
.as_ref()
|
|
|
|
.unwrap_or(self.bin_name.as_ref().unwrap_or(&self.name)),
|
|
|
|
r_string));
|
|
|
|
if self.settings.is_set(&AppSettings::SubcommandRequired) {
|
|
|
|
try!(write!(usage, " <SUBCOMMAND>"));
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Prints the full help message to `io::stdout()` using a `BufWriter`
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::App;
|
|
|
|
/// # use std::io;
|
|
|
|
/// let mut app = App::new("myprog");
|
|
|
|
/// let mut out = io::stdout();
|
|
|
|
/// app.write_help(&mut out).ok().expect("failed to write to stdout");
|
|
|
|
/// ```
|
|
|
|
pub fn print_help(&self) -> ClapResult<()> {
|
|
|
|
let out = io::stdout();
|
|
|
|
let mut buf_w = BufWriter::new(out.lock());
|
|
|
|
self.write_help(&mut buf_w)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Writes the full help message to the user to a `io::Write` object
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::App;
|
|
|
|
/// # use std::io;
|
|
|
|
/// let mut app = App::new("myprog");
|
|
|
|
/// let mut out = io::stdout();
|
|
|
|
/// app.write_help(&mut out).ok().expect("failed to write to stdout");
|
|
|
|
/// ```
|
|
|
|
pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
|
|
|
if let Some(h) = self.help_str {
|
|
|
|
return writeln!(w, "{}", h).map_err(ClapError::from);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print the version
|
|
|
|
try!(write!(w,
|
|
|
|
"{} {}\n",
|
|
|
|
&self.bin_name.as_ref().unwrap_or(&self.name)[..].replace(" ", "-"),
|
|
|
|
self.version.unwrap_or("")));
|
|
|
|
let flags = !self.flags.is_empty();
|
|
|
|
let pos = !self.positionals.is_empty();
|
|
|
|
let opts = !self.opts.is_empty();
|
|
|
|
let subcmds = !self.subcommands.is_empty();
|
|
|
|
let unified_help = self.settings.is_set(&AppSettings::UnifiedHelpMessage);
|
|
|
|
|
|
|
|
let mut longest_flag = 0;
|
|
|
|
for fl in self.flags
|
|
|
|
.iter()
|
|
|
|
.filter(|f| f.long.is_some() && !f.settings.is_set(&ArgSettings::Hidden))
|
|
|
|
.map(|a| a.to_string().len()) {
|
|
|
|
if fl > longest_flag {
|
|
|
|
longest_flag = fl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let mut longest_opt = 0;
|
|
|
|
for ol in self.opts
|
|
|
|
.iter()
|
|
|
|
.filter(|o| !o.settings.is_set(&ArgSettings::Hidden))
|
|
|
|
.map(|a| a.to_string().len()) {
|
|
|
|
if ol > longest_opt {
|
|
|
|
longest_opt = ol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let mut longest_pos = 0;
|
|
|
|
for pl in self.positionals
|
|
|
|
.values()
|
|
|
|
.filter(|p| !p.settings.is_set(&ArgSettings::Hidden))
|
|
|
|
.map(|f| f.to_string().len()) {
|
|
|
|
if pl > longest_pos {
|
|
|
|
longest_pos = pl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let mut longest_sc = 0;
|
|
|
|
for scl in self.subcommands
|
|
|
|
.iter()
|
|
|
|
.filter(|s| !s.settings.is_set(&AppSettings::Hidden))
|
|
|
|
.map(|f| f.name.len()) {
|
|
|
|
if scl > longest_sc {
|
|
|
|
longest_sc = scl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(author) = self.author {
|
|
|
|
try!(write!(w, "{}\n", author));
|
|
|
|
}
|
|
|
|
if let Some(about) = self.about {
|
|
|
|
try!(write!(w, "{}\n", about));
|
|
|
|
}
|
|
|
|
|
|
|
|
try!(write!(w, "\n{}", try!(self.create_usage(&[]))));
|
|
|
|
|
|
|
|
if flags || opts || pos || subcmds {
|
|
|
|
try!(write!(w, "\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
let tab = " ";
|
|
|
|
let longest = if !unified_help || longest_opt == 0 {
|
|
|
|
longest_flag
|
|
|
|
} else {
|
|
|
|
longest_opt
|
|
|
|
};
|
|
|
|
if unified_help && (flags || opts) {
|
|
|
|
try!(write!(w, "\nOPTIONS:\n"));
|
|
|
|
let mut combined = BTreeMap::new();
|
|
|
|
for f in self.flags.iter().filter(|f| !f.settings.is_set(&ArgSettings::Hidden)) {
|
|
|
|
let mut v = vec![];
|
|
|
|
try!(f.write_help(&mut v, tab, longest));
|
|
|
|
combined.insert(f.name, v);
|
|
|
|
}
|
|
|
|
for o in self.opts.iter().filter(|o| !o.settings.is_set(&ArgSettings::Hidden)) {
|
|
|
|
let mut v = vec![];
|
|
|
|
try!(o.write_help(&mut v, tab, longest));
|
|
|
|
combined.insert(o.name, v);
|
|
|
|
}
|
|
|
|
for (_, a) in combined {
|
|
|
|
try!(write!(w, "{}", String::from_utf8_lossy(&*a)));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if flags {
|
|
|
|
try!(write!(w, "\nFLAGS:\n"));
|
|
|
|
for (_, f) in self.flags
|
|
|
|
.iter()
|
|
|
|
.filter(|f| !f.settings.is_set(&ArgSettings::Hidden))
|
|
|
|
.map(|f| (f.name, f))
|
|
|
|
.collect::<BTreeMap<_, _>>() {
|
|
|
|
try!(f.write_help(w, tab, longest));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if opts {
|
|
|
|
try!(write!(w, "\nOPTIONS:\n"));
|
|
|
|
for (_, o) in self.opts
|
|
|
|
.iter()
|
|
|
|
.filter(|o| !o.settings.is_set(&ArgSettings::Hidden))
|
|
|
|
.map(|o| (o.name, o))
|
|
|
|
.collect::<BTreeMap<_, _>>() {
|
|
|
|
try!(o.write_help(w, tab, longest_opt));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if pos {
|
|
|
|
try!(write!(w, "\nARGS:\n"));
|
|
|
|
for v in self.positionals
|
|
|
|
.values()
|
|
|
|
.filter(|p| !p.settings.is_set(&ArgSettings::Hidden)) {
|
|
|
|
try!(v.write_help(w, tab, longest_pos));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if subcmds {
|
|
|
|
try!(write!(w, "\nSUBCOMMANDS:\n"));
|
|
|
|
for (name, sc) in self.subcommands
|
|
|
|
.iter()
|
|
|
|
.filter(|s| !s.settings.is_set(&AppSettings::Hidden))
|
|
|
|
.map(|s| (s.name_slice, s))
|
|
|
|
.collect::<BTreeMap<_, _>>() {
|
|
|
|
try!(write!(w, "{}{}", tab, name));
|
|
|
|
write_spaces!((longest_sc + 4) - (name.len()), w);
|
|
|
|
if let Some(a) = sc.about {
|
|
|
|
if a.contains("{n}") {
|
|
|
|
let mut ab = a.split("{n}");
|
|
|
|
while let Some(part) = ab.next() {
|
|
|
|
try!(write!(w, "{}\n", part));
|
|
|
|
write_spaces!(longest_sc + 8, w);
|
|
|
|
try!(write!(w, "{}", ab.next().unwrap_or("")));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
try!(write!(w, "{}", a));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try!(write!(w, "\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(h) = self.more_help {
|
|
|
|
try!(write!(w, "\n{}", h));
|
|
|
|
}
|
|
|
|
|
|
|
|
// flush the buffer
|
|
|
|
debugln!("Flushing the buffer...");
|
|
|
|
w.flush().map_err(ClapError::from)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts the parsing process. Called on top level parent app **ONLY** then recursively calls
|
|
|
|
/// the real parsing function for all subcommands
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// If any arguments contain invalid unicode characters. If this is not desired it is
|
|
|
|
/// recommended to use the `*_safe()` or `*_lossy()` versions of this method.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// let matches = App::new("myprog")
|
|
|
|
/// // Args and options go here...
|
|
|
|
/// .get_matches();
|
|
|
|
/// ```
|
|
|
|
pub fn get_matches(self) -> ArgMatches<'ar, 'ar> {
|
|
|
|
// Start the parsing
|
|
|
|
self.get_matches_from(env::args())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts the parsing process. Called on top level parent app **ONLY** then recursively calls
|
|
|
|
/// the real parsing function for all subcommands. Invalid unicode characters are replaced with
|
|
|
|
/// `U+FFFD REPLACEMENT CHARACTER`
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// let matches = App::new("myprog")
|
|
|
|
/// // Args and options go here...
|
|
|
|
/// .get_matches();
|
|
|
|
/// ```
|
|
|
|
pub fn get_matches_lossy(self) -> ArgMatches<'ar, 'ar> {
|
|
|
|
// Start the parsing
|
|
|
|
self.get_matches_from_lossy(env::args_os())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts the parsing process. Called on top level parent app **ONLY** then recursively calls
|
|
|
|
/// the real parsing function for all subcommands
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are
|
|
|
|
/// used. It will return an error, where the `error_type` is a `ClapErrorType::HelpDisplayed`
|
|
|
|
/// or `ClapErrorType::VersionDisplayed` respectively. You must call `error.exit()` or
|
|
|
|
/// perform a `std::process::exit` yourself.
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method should only be used when is absolutely necessary to handle errors
|
|
|
|
/// manually.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// let matches = App::new("myprog")
|
|
|
|
/// // Args and options go here...
|
|
|
|
/// .get_matches_safe()
|
|
|
|
/// .unwrap_or_else( |e| { panic!("An error occurs: {}", e) });
|
|
|
|
/// ```
|
|
|
|
pub fn get_matches_safe(self) -> ClapResult<ArgMatches<'ar, 'ar>> {
|
|
|
|
// Start the parsing
|
|
|
|
self.get_matches_from_safe(env::args_os())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts the parsing process. Called on top level parent app **ONLY** then recursively calls
|
|
|
|
/// the real parsing function for all subcommands. Invalid unicode characters are replaced with
|
|
|
|
/// `U+FFFD REPLACEMENT CHARACTER`
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are
|
|
|
|
/// used. It will return an error, where the `error_type` is a `ClapErrorType::HelpDisplayed`
|
|
|
|
/// or `ClapErrorType::VersionDisplayed` respectively. You must call `error.exit()` or
|
|
|
|
/// perform a `std::process::exit` yourself.
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method should only be used when is absolutely necessary to handle errors
|
|
|
|
/// manually.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// let matches = App::new("myprog")
|
|
|
|
/// // Args and options go here...
|
|
|
|
/// .get_matches_safe()
|
|
|
|
/// .unwrap_or_else( |e| { panic!("An error occurs: {}", e) });
|
|
|
|
/// ```
|
|
|
|
pub fn get_matches_safe_lossy(self) -> ClapResult<ArgMatches<'ar, 'ar>> {
|
|
|
|
// Start the parsing
|
|
|
|
self.get_matches_from_safe_lossy(env::args_os())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts the parsing process. Called on top level parent app **ONLY** then recursively calls
|
|
|
|
/// the real parsing function for all subcommands
|
|
|
|
///
|
|
|
|
/// **NOTE:** The first argument will be parsed as the binary name.
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method should only be used when absolutely necessary, such as needing to
|
|
|
|
/// parse arguments from something other than `std::env::args()`. If you are unsure, use
|
|
|
|
/// `App::get_matches()`
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"];
|
|
|
|
///
|
|
|
|
/// let matches = App::new("myprog")
|
|
|
|
/// // Args and options go here...
|
|
|
|
/// .get_matches_from(arg_vec);
|
|
|
|
/// ```
|
|
|
|
pub fn get_matches_from<I, T>(mut self, itr: I) -> ArgMatches<'ar, 'ar>
|
|
|
|
where I: IntoIterator<Item = T>,
|
|
|
|
T: AsRef<OsStr>
|
|
|
|
{
|
|
|
|
self.get_matches_from_safe_borrow(itr).unwrap_or_else(|e| {
|
|
|
|
// Otherwise, write to stderr and exit
|
|
|
|
self.maybe_wait_for_exit(e);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts the parsing process. Called on top level parent app **ONLY** then recursively calls
|
|
|
|
/// the real parsing function for all subcommands. Invalid unicode characters are replaced with
|
|
|
|
/// `U+FFFD REPLACEMENT CHARACTER`
|
|
|
|
///
|
|
|
|
/// **NOTE:** The first argument will be parsed as the binary name.
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method should only be used when absolutely necessary, such as needing to
|
|
|
|
/// parse arguments from something other than `std::env::args()`. If you are unsure, use
|
|
|
|
/// `App::get_matches()`
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"];
|
|
|
|
///
|
|
|
|
/// let matches = App::new("myprog")
|
|
|
|
/// // Args and options go here...
|
|
|
|
/// .get_matches_from(arg_vec);
|
|
|
|
/// ```
|
|
|
|
pub fn get_matches_from_lossy<I, T>(mut self, itr: I) -> ArgMatches<'ar, 'ar>
|
|
|
|
where I: IntoIterator<Item = T>,
|
|
|
|
T: AsRef<OsStr>
|
|
|
|
{
|
|
|
|
self.get_matches_from_safe_borrow_lossy(itr).unwrap_or_else(|e| {
|
|
|
|
// Otherwise, write to stderr and exit
|
|
|
|
self.maybe_wait_for_exit(e);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts the parsing process. Called on top level parent app **ONLY** then recursively calls
|
|
|
|
/// the real parsing function for all subcommands
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are
|
|
|
|
/// used. It will return an error, where the `error_type` is a `ClapErrorType::HelpDisplayed`
|
|
|
|
/// or `ClapErrorType::VersionDisplayed` respectively. You must call `error.exit()` or
|
|
|
|
/// perform a `std::process::exit` yourself.
|
|
|
|
///
|
|
|
|
/// **NOTE:** The first argument will be parsed as the binary name.
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method should only be used when absolutely necessary, such as needing to
|
|
|
|
/// parse arguments from something other than `std::env::args()`. If you are unsure, use
|
|
|
|
/// `App::get_matches_safe()`
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method should only be used when is absolutely necessary to handle errors
|
|
|
|
/// manually.
|
|
|
|
///
|
|
|
|
/// **NOTE:** Invalid unicode characters will result in an `Err` with type
|
|
|
|
/// `ClapErrorType::InvalidUnicode`
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"];
|
|
|
|
///
|
|
|
|
/// let matches = App::new("myprog")
|
|
|
|
/// // Args and options go here...
|
|
|
|
/// .get_matches_from_safe(arg_vec)
|
|
|
|
/// .unwrap_or_else( |e| { panic!("An error occurs: {}", e) });
|
|
|
|
/// ```
|
|
|
|
pub fn get_matches_from_safe<I, T>(mut self, itr: I) -> ClapResult<ArgMatches<'ar, 'ar>>
|
|
|
|
where I: IntoIterator<Item = T>,
|
|
|
|
T: AsRef<OsStr>
|
|
|
|
{
|
|
|
|
self.get_matches_from_safe_borrow(itr)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts the parsing process. Called on top level parent app **ONLY** then recursively calls
|
|
|
|
/// the real parsing function for all subcommands. Invalid unicode characters are replaced with
|
|
|
|
/// `U+FFFD REPLACEMENT CHARACTER`
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are
|
|
|
|
/// used. It will return an error, where the `error_type` is a `ClapErrorType::HelpDisplayed`
|
|
|
|
/// or `ClapErrorType::VersionDisplayed` respectively. You must call `error.exit()` or
|
|
|
|
/// perform a `std::process::exit` yourself.
|
|
|
|
///
|
|
|
|
/// **NOTE:** The first argument will be parsed as the binary name.
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method should only be used when absolutely necessary, such as needing to
|
|
|
|
/// parse arguments from something other than `std::env::args()`. If you are unsure, use
|
|
|
|
/// `App::get_matches_safe()`
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method should only be used when is absolutely necessary to handle errors
|
|
|
|
/// manually.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"];
|
|
|
|
///
|
|
|
|
/// let matches = App::new("myprog")
|
|
|
|
/// // Args and options go here...
|
|
|
|
/// .get_matches_from_safe(arg_vec)
|
|
|
|
/// .unwrap_or_else( |e| { panic!("An error occurs: {}", e) });
|
|
|
|
/// ```
|
|
|
|
pub fn get_matches_from_safe_lossy<I, T>(mut self, itr: I) -> ClapResult<ArgMatches<'ar, 'ar>>
|
|
|
|
where I: IntoIterator<Item = T>,
|
|
|
|
T: AsRef<OsStr>
|
|
|
|
{
|
|
|
|
self._get_matches_from_safe_borrow(itr, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts the parsing process without consuming the `App` struct `self`. This is normally not
|
|
|
|
/// the desired functionality, instead prefer `App::get_matches_from_safe` which *does*
|
|
|
|
/// consume `self`.
|
|
|
|
///
|
|
|
|
/// **NOTE:** The first argument will be parsed as the binary name.
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method should only be used when absolutely necessary, such as needing to
|
|
|
|
/// parse arguments from something other than `std::env::args()`. If you are unsure, use
|
|
|
|
/// `App::get_matches_safe()`
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method should only be used when is absolutely necessary to handle errors
|
|
|
|
/// manually.
|
|
|
|
///
|
|
|
|
/// **NOTE:** Invalid unicode characters will result in an `Err` with type
|
|
|
|
/// `ClapErrorType::InvalidUnicode`
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"];
|
|
|
|
///
|
|
|
|
/// let mut app = App::new("myprog");
|
|
|
|
/// // Args and options go here...
|
|
|
|
/// let matches = app.get_matches_from_safe_borrow(arg_vec)
|
|
|
|
/// .unwrap_or_else( |e| { panic!("An error occurs: {}", e) });
|
|
|
|
/// ```
|
|
|
|
pub fn get_matches_from_safe_borrow<I, T>(&mut self, itr: I) -> ClapResult<ArgMatches<'ar, 'ar>>
|
|
|
|
where I: IntoIterator<Item = T>,
|
|
|
|
T: AsRef<OsStr>
|
|
|
|
{
|
|
|
|
self._get_matches_from_safe_borrow(itr, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Starts the parsing process without consuming the `App` struct `self`. This is normally not
|
|
|
|
/// the desired functionality, instead prefer `App::get_matches_from_safe` which *does*
|
|
|
|
/// consume `self`. Invalid unicode characters are replaced with `U+FFFD REPLACEMENT CHARACTER`
|
|
|
|
///
|
|
|
|
/// **NOTE:** The first argument will be parsed as the binary name.
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method should only be used when absolutely necessary, such as needing to
|
|
|
|
/// parse arguments from something other than `std::env::args()`. If you are unsure, use
|
|
|
|
/// `App::get_matches_safe()`
|
|
|
|
///
|
|
|
|
/// **NOTE:** This method should only be used when is absolutely necessary to handle errors
|
|
|
|
/// manually.
|
|
|
|
///
|
|
|
|
/// **NOTE:** Invalid unicode characters will result in an `Err` with type
|
|
|
|
/// `ClapErrorType::InvalidUnicode`
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// # use clap::{App, Arg};
|
|
|
|
/// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"];
|
|
|
|
///
|
|
|
|
/// let mut app = App::new("myprog");
|
|
|
|
/// // Args and options go here...
|
|
|
|
/// let matches = app.get_matches_from_safe_borrow(arg_vec)
|
|
|
|
/// .unwrap_or_else( |e| { panic!("An error occurs: {}", e) });
|
|
|
|
/// ```
|
|
|
|
pub fn get_matches_from_safe_borrow_lossy<I, T>(&mut self,
|
|
|
|
itr: I)
|
|
|
|
-> ClapResult<ArgMatches<'ar, 'ar>>
|
|
|
|
where I: IntoIterator<Item = T>,
|
|
|
|
T: AsRef<OsStr>
|
|
|
|
{
|
|
|
|
self._get_matches_from_safe_borrow(itr, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn _get_matches_from_safe_borrow<I, T>(&mut self,
|
|
|
|
itr: I,
|
|
|
|
lossy: bool)
|
|
|
|
-> ClapResult<ArgMatches<'ar, 'ar>>
|
|
|
|
where I: IntoIterator<Item = T>,
|
|
|
|
T: AsRef<OsStr>
|
|
|
|
{
|
|
|
|
// Verify all positional assertions pass
|
|
|
|
self.verify_positionals();
|
|
|
|
// If there are global arguments, we need to propgate them down to subcommands
|
|
|
|
// before parsing incase we run into a subcommand
|
|
|
|
self.propogate_globals();
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
let mut matcher = ArgMatcher::new();
|
2015-11-09 08:48:49 +00:00
|
|
|
|
|
|
|
let mut it = itr.into_iter();
|
|
|
|
// Get the name of the program (argument 1 of env::args()) and determine the
|
|
|
|
// actual file
|
|
|
|
// that was used to execute the program. This is because a program called
|
|
|
|
// ./target/release/my_prog -a
|
|
|
|
// will have two arguments, './target/release/my_prog', '-a' but we don't want
|
|
|
|
// to display
|
|
|
|
// the full path when displaying help messages and such
|
|
|
|
if !self.settings.is_set(&AppSettings::NoBinaryName) {
|
|
|
|
if let Some(name) = it.next() {
|
|
|
|
let p = Path::new(name.as_ref());
|
|
|
|
if let Some(f) = p.file_name() {
|
|
|
|
if let Ok(s) = f.to_os_string().into_string() {
|
|
|
|
if let None = self.bin_name {
|
|
|
|
self.bin_name = Some(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// do the real parsing
|
2015-11-09 13:57:20 +00:00
|
|
|
if let Err(e) = self.get_matches_with(&mut matcher, &mut it, lossy) {
|
2015-11-09 08:48:49 +00:00
|
|
|
return Err(e);
|
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
Ok(matcher.into())
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// The actual parsing function
|
|
|
|
#[cfg_attr(feature="lints", allow(while_let_on_iterator))]
|
|
|
|
fn get_matches_with<I, T>(&mut self,
|
2015-11-09 13:57:20 +00:00
|
|
|
matcher: &mut ArgMatcher<'ar>,
|
2015-11-09 08:48:49 +00:00
|
|
|
it: &mut I,
|
|
|
|
lossy: bool)
|
|
|
|
-> ClapResult<()>
|
|
|
|
where I: Iterator<Item = T>,
|
|
|
|
T: AsRef<OsStr>
|
|
|
|
{
|
|
|
|
// First we create the `--help` and `--version` arguments and add them if
|
|
|
|
// necessary
|
|
|
|
self.create_help_and_version();
|
|
|
|
|
|
|
|
let mut pos_only = false;
|
|
|
|
let mut subcmd_name: Option<String> = None;
|
|
|
|
let mut needs_val_of: Option<&str> = None;
|
|
|
|
let mut pos_counter = 1;
|
|
|
|
while let Some(arg) = it.next() {
|
|
|
|
let arg_cow = match arg.as_ref().to_str() {
|
|
|
|
Some(s) => s.into(),
|
|
|
|
None => {
|
|
|
|
if !lossy {
|
|
|
|
return Err(
|
|
|
|
error_builder::InvalidUnicode(
|
2015-11-09 13:57:20 +00:00
|
|
|
&*try!(self.create_current_usage(matcher)))
|
2015-11-09 08:48:49 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
arg.as_ref().to_string_lossy()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let arg_slice: &str = arg_cow.borrow();
|
|
|
|
|
|
|
|
// we need to know if we're parsing a new argument, or the value of previous
|
|
|
|
// argument,
|
|
|
|
// perhaps one with multiple values such as --option val1 val2. We determine
|
|
|
|
// when to
|
|
|
|
// stop parsing multiple values by finding a '-'
|
2015-11-09 13:57:20 +00:00
|
|
|
// let new_arg = if arg_slice.starts_with("-") {
|
|
|
|
// // If we come to a single `-` it's a value, not a new argument...this happens
|
|
|
|
// // when
|
|
|
|
// // one wants to use the Unix standard of '-' to mean 'stdin'
|
|
|
|
// arg_slice.len() > 1
|
|
|
|
// } else {
|
|
|
|
// true
|
|
|
|
// };
|
2015-11-09 08:48:49 +00:00
|
|
|
|
|
|
|
// pos_only is determined later, and set true when a user uses the Unix
|
|
|
|
// standard of
|
|
|
|
// '--' to mean only positionals follow
|
2015-11-09 13:57:20 +00:00
|
|
|
// If the user passed `--` we don't check for subcommands, because the argument
|
|
|
|
// they
|
|
|
|
// may be trying to pass might match a subcommand name
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
let starts_new_arg = if arg_slice.starts_with("-") {
|
|
|
|
!(arg_slice.len() == 1)
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
};
|
|
|
|
if !pos_only {
|
|
|
|
if !starts_new_arg {
|
|
|
|
// Check to see if parsing a value from an option
|
|
|
|
if let Some(nvo) = needs_val_of {
|
|
|
|
// get the OptBuilder so we can check the settings
|
|
|
|
if let Some(opt) = self.opts.iter().filter(|o| &o.name == &nvo).next() {
|
|
|
|
needs_val_of = try!(self.add_val_to_arg(opt, arg_slice, matcher));
|
|
|
|
// get the next value from the iterator
|
|
|
|
continue;
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
let mut skip = false;
|
|
|
|
if arg_slice.starts_with("--") {
|
|
|
|
if arg_slice.len() == 2 {
|
|
|
|
// The user has passed '--' which means only positional args follow no matter
|
|
|
|
// what they start with
|
|
|
|
pos_only = true;
|
|
|
|
continue;
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
needs_val_of = try!(self.parse_long_arg(matcher, arg_slice));
|
|
|
|
} else if arg_slice.starts_with("-") && arg_slice.len() != 1 {
|
|
|
|
needs_val_of = try!(self.parse_short_arg(matcher, arg_slice));
|
|
|
|
} else {
|
|
|
|
skip = true;
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
if !skip { continue; }
|
|
|
|
if self.subcommands.iter().any(|s| s.name_slice == arg_slice) {
|
|
|
|
if arg_slice == "help" &&
|
|
|
|
self.settings.is_set(&AppSettings::NeedsSubcommandHelp) {
|
|
|
|
return self._help();
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
subcmd_name = Some(arg_slice.to_owned());
|
|
|
|
break;
|
|
|
|
} else if let Some(candidate) = suggestions::did_you_mean(
|
|
|
|
arg_slice,
|
|
|
|
self.subcommands.iter().map(|s| &s.name)) {
|
|
|
|
return Err(error_builder::InvalidSubcommand(
|
|
|
|
arg_slice,
|
|
|
|
candidate,
|
|
|
|
self.bin_name.as_ref().unwrap_or(&self.name),
|
|
|
|
&*try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
if let Some(p) = self.positionals.get(&pos_counter) {
|
|
|
|
try!(self.validate_arg(p, matcher));
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
try!(self.add_val_to_arg(p, arg_slice, matcher));
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
if !pos_only &&
|
|
|
|
(self.settings.is_set(&AppSettings::TrailingVarArg) &&
|
|
|
|
pos_counter == self.positionals.len()) {
|
|
|
|
pos_only = true;
|
|
|
|
}
|
|
|
|
arg_post_processing!(self, p, matcher);
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
// Only increment the positional counter if it doesn't allow multiples
|
|
|
|
if !p.settings.is_set(&ArgSettings::Multiple) {
|
|
|
|
pos_counter += 1;
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
} else {
|
|
|
|
return Err(error_builder::UnexpectedArgument(
|
|
|
|
arg_slice,
|
|
|
|
self.bin_name.as_ref().unwrap_or(&self.name),
|
|
|
|
&*try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
if let Some(a) = needs_val_of {
|
|
|
|
if let Some(o) = self.opts.iter().filter(|o| &o.name == &a).next() {
|
|
|
|
if (o.settings.is_set(&ArgSettings::Multiple) && self.required.is_empty()) ||
|
|
|
|
!o.settings.is_set(&ArgSettings::Multiple){
|
|
|
|
let should_err = match matcher.values_of(o.name) {
|
2015-11-09 08:48:49 +00:00
|
|
|
Some(ref v) => v.is_empty(),
|
|
|
|
None => true,
|
|
|
|
};
|
|
|
|
if should_err {
|
|
|
|
return Err(error_builder::EmptyValue(
|
|
|
|
&*o.to_string(),
|
2015-11-09 13:57:20 +00:00
|
|
|
&*try!(self.create_current_usage(matcher))
|
2015-11-09 08:48:49 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(error_builder::MissingRequiredArgument(
|
2015-11-09 13:57:20 +00:00
|
|
|
&*self.get_required_from(&self.required, Some(matcher))
|
2015-11-09 08:48:49 +00:00
|
|
|
.iter()
|
|
|
|
.fold(String::new(),
|
|
|
|
|acc, s| acc + &format!("\n\t{}", Format::Error(s))[..]),
|
2015-11-09 13:57:20 +00:00
|
|
|
&*try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(error_builder::EmptyValue(&*format!("{}",
|
|
|
|
self.positionals
|
|
|
|
.values()
|
2015-11-09 13:57:20 +00:00
|
|
|
.filter(|p| &p.name == &a)
|
2015-11-09 08:48:49 +00:00
|
|
|
.next()
|
2015-11-09 13:57:20 +00:00
|
|
|
.expect(INTERNAL_ERROR_MSG)),
|
|
|
|
&*try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
if let Err(e) = self.validate_blacklist(matcher) {
|
|
|
|
return Err(e);
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
if let Err(e) = self.validate_num_args(matcher) {
|
|
|
|
return Err(e);
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
matcher.usage(try!(self.create_usage(&[])));
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
if !(self.settings.is_set(&AppSettings::SubcommandsNegateReqs) && subcmd_name.is_some()) {
|
|
|
|
try!(self.validate_required(&matcher));
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
if let Some(sc_name) = subcmd_name {
|
|
|
|
use std::fmt::Write;
|
|
|
|
let mut mid_string = String::new();
|
|
|
|
if !self.settings.is_set(&AppSettings::SubcommandsNegateReqs) {
|
|
|
|
let mut hs = self.required.iter().map(|n| *n).collect::<Vec<_>>();
|
2015-11-09 13:57:20 +00:00
|
|
|
for k in matcher.arg_names() {
|
2015-11-09 08:48:49 +00:00
|
|
|
hs.push(*k);
|
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
let reqs = self.get_required_from(&hs, Some(matcher));
|
2015-11-09 08:48:49 +00:00
|
|
|
|
|
|
|
for s in reqs.iter() {
|
|
|
|
write!(&mut mid_string, " {}", s).ok().expect(INTERNAL_ERROR_MSG);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mid_string.push_str(" ");
|
|
|
|
if let Some(ref mut sc) = self.subcommands
|
|
|
|
.iter_mut()
|
|
|
|
.filter(|s| s.name_slice == &sc_name)
|
|
|
|
.next() {
|
2015-11-09 13:57:20 +00:00
|
|
|
let mut sc_matcher = ArgMatcher::new();
|
2015-11-09 08:48:49 +00:00
|
|
|
// bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
|
|
|
|
// a space
|
|
|
|
sc.usage = Some(format!("{}{}{}",
|
|
|
|
self.bin_name.as_ref().unwrap_or(&String::new()),
|
|
|
|
if self.bin_name.is_some() {
|
|
|
|
&*mid_string
|
|
|
|
} else {
|
|
|
|
""
|
|
|
|
},
|
|
|
|
&*sc.name));
|
|
|
|
sc.bin_name = Some(format!("{}{}{}",
|
|
|
|
self.bin_name.as_ref().unwrap_or(&String::new()),
|
|
|
|
if self.bin_name.is_some() {
|
|
|
|
" "
|
|
|
|
} else {
|
|
|
|
""
|
|
|
|
},
|
|
|
|
&*sc.name));
|
2015-11-09 13:57:20 +00:00
|
|
|
if let Err(e) = sc.get_matches_with(&mut sc_matcher, it, lossy) {
|
2015-11-09 08:48:49 +00:00
|
|
|
e.exit();
|
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
matcher.subcommand(SubCommand {
|
2015-11-09 08:48:49 +00:00
|
|
|
name: sc.name_slice,
|
2015-11-09 13:57:20 +00:00
|
|
|
matches: sc_matcher.into(),
|
|
|
|
});
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
} else if self.settings.is_set(&AppSettings::SubcommandRequired) {
|
|
|
|
let bn = self.bin_name.as_ref().unwrap_or(&self.name);
|
|
|
|
return Err(error_builder::MissingSubcommand(bn,
|
2015-11-09 13:57:20 +00:00
|
|
|
&try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
} else if self.settings.is_set(&AppSettings::SubcommandRequiredElseHelp) {
|
|
|
|
let mut out = vec![];
|
|
|
|
try!(self.write_help(&mut out));
|
|
|
|
return Err(ClapError {
|
|
|
|
error: String::from_utf8_lossy(&*out).into_owned(),
|
|
|
|
error_type: ClapErrorType::MissingArgumentOrSubcommand,
|
|
|
|
});
|
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
if matcher.is_empty() && matcher.subcommand_name().is_none() &&
|
2015-11-09 08:48:49 +00:00
|
|
|
self.settings.is_set(&AppSettings::ArgRequiredElseHelp) {
|
|
|
|
let mut out = vec![];
|
|
|
|
try!(self.write_help(&mut out));
|
|
|
|
return Err(ClapError {
|
|
|
|
error: String::from_utf8_lossy(&*out).into_owned(),
|
|
|
|
error_type: ClapErrorType::MissingArgumentOrSubcommand,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// basically re-implements ClapError::exit except it checks if we should wait
|
|
|
|
// for input before
|
|
|
|
// exiting since ClapError doesn't have that info and the error message must be
|
|
|
|
// printed before
|
|
|
|
// exiting
|
|
|
|
fn maybe_wait_for_exit(&self, e: ClapError) -> ! {
|
|
|
|
if e.use_stderr() {
|
|
|
|
wlnerr!("{}", e.error);
|
|
|
|
if self.settings.is_set(&AppSettings::WaitOnError) {
|
|
|
|
wlnerr!("\nPress [ENTER] / [RETURN] to continue...");
|
|
|
|
let mut s = String::new();
|
|
|
|
let i = io::stdin();
|
|
|
|
i.lock().read_line(&mut s).unwrap();
|
|
|
|
}
|
|
|
|
process::exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
e.exit()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prints the version to the user and exits if quit=true
|
|
|
|
fn print_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
|
|
|
|
// Print the binary name if existing, but replace all spaces with hyphens in
|
|
|
|
// case we're
|
|
|
|
// dealing with subcommands i.e. git mv is translated to git-mv
|
|
|
|
try!(writeln!(w,
|
|
|
|
"{} {}",
|
|
|
|
&self.bin_name.as_ref().unwrap_or(&self.name)[..].replace(" ", "-"),
|
|
|
|
self.version.unwrap_or("")));
|
|
|
|
|
|
|
|
w.flush().map_err(ClapError::from)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
2015-11-09 13:57:20 +00:00
|
|
|
pub fn create_current_usage(&self, matcher: &ArgMatcher) -> ClapResult<String> {
|
|
|
|
self.create_usage(&matcher.arg_names()
|
2015-11-09 08:48:49 +00:00
|
|
|
.filter(|k| {
|
|
|
|
if let Some(o) = self.opts
|
|
|
|
.iter()
|
|
|
|
.filter(|o| &&o.name == k)
|
|
|
|
.next() {
|
|
|
|
!o.settings.is_set(&ArgSettings::Required)
|
|
|
|
} else if let Some(p) = self.positionals
|
|
|
|
.values()
|
|
|
|
.filter(|p| &&p.name == k)
|
|
|
|
.next() {
|
|
|
|
!p.settings.is_set(&ArgSettings::Required)
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.map(|k| *k)
|
|
|
|
.collect::<Vec<_>>())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn groups_for_arg(&self, name: &str) -> Option<Vec<&'ar str>> {
|
|
|
|
if self.groups.is_empty() {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
let mut res = vec![];
|
|
|
|
for (g_name, grp) in &self.groups {
|
|
|
|
for a in &grp.args {
|
|
|
|
if a == &name {
|
|
|
|
res.push(*g_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if res.is_empty() {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(res)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn args_in_group(&self, group: &str) -> Vec<String> {
|
|
|
|
let mut g_vec = vec![];
|
|
|
|
let mut args = vec![];
|
|
|
|
|
|
|
|
for n in &self.groups.get(group).unwrap().args {
|
|
|
|
if let Some(f) = self.flags.iter().filter(|f| &f.name == n).next() {
|
|
|
|
args.push(f.to_string());
|
|
|
|
} else if let Some(f) = self.opts.iter().filter(|o| &o.name == n).next() {
|
|
|
|
args.push(f.to_string());
|
|
|
|
} else if self.groups.contains_key(n) {
|
|
|
|
g_vec.push(*n);
|
|
|
|
} else {
|
|
|
|
if let Some(p) = self.positionals
|
|
|
|
.values()
|
|
|
|
.filter(|p| &p.name == n)
|
|
|
|
.next() {
|
|
|
|
args.push(p.to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !g_vec.is_empty() {
|
|
|
|
for av in g_vec.iter().map(|g| self.args_in_group(g)) {
|
|
|
|
for a in av {
|
|
|
|
args.push(a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert!(!args.is_empty(),
|
|
|
|
"ArgGroup '{}' doesn't contain any args",
|
|
|
|
group);
|
|
|
|
args.dedup();
|
|
|
|
args.iter().map(ToOwned::to_owned).collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn arg_names_in_group(&self, group: &'ar str) -> Vec<&'ar str> {
|
|
|
|
let mut g_vec = vec![];
|
|
|
|
let mut args = vec![];
|
|
|
|
|
|
|
|
for n in &self.groups.get(group).unwrap().args {
|
|
|
|
if self.flags.iter().any(|f| &f.name == n) {
|
|
|
|
args.push(*n);
|
|
|
|
} else if self.opts.iter().any(|o| &o.name == n) {
|
|
|
|
args.push(*n);
|
|
|
|
} else if self.groups.contains_key(n) {
|
|
|
|
g_vec.push(*n);
|
|
|
|
} else if self.positionals.values().any(|p| &p.name == n) {
|
|
|
|
args.push(*n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !g_vec.is_empty() {
|
|
|
|
for av in g_vec.iter().map(|g| self.arg_names_in_group(g)) {
|
|
|
|
for a in av {
|
|
|
|
args.push(a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert!(!args.is_empty(),
|
|
|
|
"ArgGroup '{}' doesn't contain any args",
|
|
|
|
group);
|
|
|
|
args.dedup();
|
|
|
|
args.iter().map(|s| *s).collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_required_from(&self,
|
|
|
|
reqs: &[&'ar str],
|
2015-11-09 13:57:20 +00:00
|
|
|
matcher: Option<&ArgMatcher>)
|
2015-11-09 08:48:49 +00:00
|
|
|
-> VecDeque<String> {
|
|
|
|
let mut c_flags = vec![];
|
|
|
|
let mut c_pos = vec![];
|
|
|
|
let mut c_opt = vec![];
|
|
|
|
let mut grps = vec![];
|
|
|
|
for name in reqs {
|
|
|
|
if self.flags.iter().any(|f| &f.name == name) {
|
|
|
|
c_flags.push(name);
|
|
|
|
} else if self.opts.iter().any(|o| &o.name == name) {
|
|
|
|
c_opt.push(name);
|
|
|
|
} else if self.groups.contains_key(name) {
|
|
|
|
grps.push(*name);
|
|
|
|
} else {
|
|
|
|
c_pos.push(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let mut tmp_f = vec![];
|
|
|
|
for f in &c_flags {
|
|
|
|
if let Some(f) = self.flags.iter().filter(|flg| &&flg.name == f).next() {
|
|
|
|
if let Some(ref rl) = f.requires {
|
|
|
|
for r in rl.iter() {
|
|
|
|
if !reqs.contains(r) {
|
|
|
|
if self.flags.iter().any(|f| &f.name == r) {
|
|
|
|
tmp_f.push(r);
|
|
|
|
} else if self.opts.iter().any(|o| &o.name == r) {
|
|
|
|
c_opt.push(r);
|
|
|
|
} else if self.groups.contains_key(r) {
|
|
|
|
grps.push(*r);
|
|
|
|
} else {
|
|
|
|
c_pos.push(r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for f in tmp_f.into_iter() {
|
|
|
|
c_flags.push(f);
|
|
|
|
}
|
|
|
|
let mut tmp_o = vec![];
|
|
|
|
for f in &c_opt {
|
|
|
|
if let Some(f) = self.opts.iter().filter(|o| &&o.name == f).next() {
|
|
|
|
if let Some(ref rl) = f.requires {
|
|
|
|
for r in rl.iter() {
|
|
|
|
if !reqs.contains(r) {
|
|
|
|
if self.flags.iter().any(|f| &f.name == r) {
|
|
|
|
c_flags.push(r);
|
|
|
|
} else if self.opts.iter().any(|o| &o.name == r) {
|
|
|
|
tmp_o.push(r);
|
|
|
|
} else if self.groups.contains_key(r) {
|
|
|
|
grps.push(*r);
|
|
|
|
} else {
|
|
|
|
c_pos.push(r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for f in tmp_o.into_iter() {
|
|
|
|
c_opt.push(f);
|
|
|
|
}
|
|
|
|
let mut tmp_p = vec![];
|
|
|
|
for p in c_pos.iter() {
|
|
|
|
if let Some(p) = self.positionals.values().filter(|pos| &&pos.name == p).next() {
|
|
|
|
if let Some(ref rl) = p.requires {
|
|
|
|
for r in rl.iter() {
|
|
|
|
if !reqs.contains(r) {
|
|
|
|
if self.flags.iter().any(|f| &f.name == r) {
|
|
|
|
c_flags.push(r);
|
|
|
|
} else if self.opts.iter().any(|o| &o.name == r) {
|
|
|
|
c_opt.push(r);
|
|
|
|
} else if self.groups.contains_key(r) {
|
|
|
|
grps.push(*r);
|
|
|
|
} else {
|
|
|
|
tmp_p.push(r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for f in tmp_p.into_iter() {
|
|
|
|
c_pos.push(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut ret_val = VecDeque::new();
|
|
|
|
|
|
|
|
let mut pmap = BTreeMap::new();
|
|
|
|
for p in c_pos.into_iter() {
|
2015-11-09 13:57:20 +00:00
|
|
|
if matcher.is_some() && matcher.as_ref().unwrap().contains(p) {
|
2015-11-09 08:48:49 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if let Some(p) = self.positionals.values().filter(|x| &x.name == p).next() {
|
|
|
|
pmap.insert(p.index, format!("{}", p));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (_, s) in pmap {
|
|
|
|
ret_val.push_back(s);
|
|
|
|
}
|
|
|
|
for f in c_flags.into_iter() {
|
2015-11-09 13:57:20 +00:00
|
|
|
if matcher.is_some() && matcher.as_ref().unwrap().contains(f) {
|
2015-11-09 08:48:49 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ret_val.push_back(format!("{}",
|
|
|
|
self.flags
|
|
|
|
.iter()
|
|
|
|
.filter(|flg| &flg.name == f)
|
|
|
|
.next()
|
|
|
|
.unwrap()));
|
|
|
|
}
|
|
|
|
for o in c_opt.into_iter() {
|
2015-11-09 13:57:20 +00:00
|
|
|
if matcher.is_some() && matcher.as_ref().unwrap().contains(o) {
|
2015-11-09 08:48:49 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ret_val.push_back(format!("{}",
|
|
|
|
self.opts
|
|
|
|
.iter()
|
|
|
|
.filter(|opt| &opt.name == o)
|
|
|
|
.next()
|
|
|
|
.unwrap()));
|
|
|
|
}
|
|
|
|
for g in grps.into_iter() {
|
|
|
|
let g_string = self.args_in_group(g)
|
|
|
|
.iter()
|
|
|
|
.fold(String::new(), |acc, s| acc + &format!(" {} |", s)[..]);
|
|
|
|
ret_val.push_back(format!("[{}]", &g_string[..g_string.len() - 1]));
|
|
|
|
}
|
|
|
|
|
|
|
|
ret_val
|
|
|
|
}
|
|
|
|
|
|
|
|
fn verify_positionals(&mut self) {
|
|
|
|
// Because you must wait until all arguments have been supplied, this is the first chance
|
|
|
|
// to make assertions on positional argument indexes
|
|
|
|
//
|
|
|
|
// Firt we verify that the index highest supplied index, is equal to the number of
|
|
|
|
// positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
|
|
|
|
// but no 2)
|
|
|
|
if let Some((idx, ref p)) = self.positionals.iter().rev().next() {
|
|
|
|
if idx != self.positionals.len() {
|
|
|
|
panic!("Found positional argument \"{}\" who's index is {} but there are only {} \
|
|
|
|
positional arguments defined",
|
|
|
|
p.name,
|
|
|
|
idx,
|
|
|
|
self.positionals.len());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next we verify that only the highest index has a .multiple(true) (if any)
|
|
|
|
assert!(!self.positionals
|
|
|
|
.values()
|
|
|
|
.any(|a| {
|
|
|
|
a.settings.is_set(&ArgSettings::Multiple) &&
|
|
|
|
(a.index as usize != self.positionals.len())
|
|
|
|
}),
|
|
|
|
"Only the positional argument with the highest index may accept multiple values");
|
|
|
|
|
|
|
|
// If it's required we also need to ensure all previous positionals are
|
|
|
|
// required too
|
|
|
|
let mut found = false;
|
|
|
|
for p in self.positionals.values().rev() {
|
|
|
|
if !found {
|
|
|
|
if p.settings.is_set(&ArgSettings::Required) {
|
|
|
|
found = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert!(p.settings.is_set(&ArgSettings::Required),
|
|
|
|
"Found positional argument which is not required with a lower index than a \
|
|
|
|
required positional argument: {:?} index {}",
|
|
|
|
p.name,
|
|
|
|
p.index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn propogate_globals(&mut self) {
|
|
|
|
for sc in self.subcommands.iter_mut() {
|
|
|
|
// We have to create a new scope in order to tell rustc the borrow of `sc` is
|
|
|
|
// done and
|
|
|
|
// to recursively call this method
|
|
|
|
{
|
|
|
|
for a in self.global_args.iter() {
|
|
|
|
sc.add_arg(a.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sc.propogate_globals();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn blacklisted_from(&self, name: &str, matcher: &ArgMatcher) -> Option<String> {
|
|
|
|
for k in matcher.arg_names() {
|
2015-11-09 08:48:49 +00:00
|
|
|
if let Some(f) = self.flags.iter().filter(|f| &f.name == k).next() {
|
|
|
|
if let Some(ref bl) = f.blacklist {
|
|
|
|
if bl.contains(&name) {
|
|
|
|
return Some(format!("{}", f));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(o) = self.opts.iter().filter(|o| &o.name == k).next() {
|
|
|
|
if let Some(ref bl) = o.blacklist {
|
|
|
|
if bl.contains(&name) {
|
|
|
|
return Some(format!("{}", o));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(pos) = self.positionals.values().filter(|p| &p.name == k).next() {
|
|
|
|
if let Some(ref bl) = pos.blacklist {
|
|
|
|
if bl.contains(&name) {
|
|
|
|
return Some(format!("{}", pos));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn overriden_from(&self, name: &'ar str, matcher: &ArgMatcher) -> Option<&'ar str> {
|
|
|
|
for k in matcher.arg_names() {
|
2015-11-09 08:48:49 +00:00
|
|
|
if let Some(f) = self.flags.iter().filter(|f| &f.name == k).next() {
|
|
|
|
if let Some(ref bl) = f.overrides {
|
|
|
|
if bl.contains(&name) {
|
|
|
|
return Some(f.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(o) = self.opts.iter().filter(|o| &o.name == k).next() {
|
|
|
|
if let Some(ref bl) = o.overrides {
|
|
|
|
if bl.contains(&name) {
|
|
|
|
return Some(o.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(pos) = self.positionals.values().filter(|p| &p.name == k).next() {
|
|
|
|
if let Some(ref bl) = pos.overrides {
|
|
|
|
if bl.contains(&name) {
|
|
|
|
return Some(pos.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn create_help_and_version(&mut self) {
|
|
|
|
// name is "hclap_help" because flags are sorted by name
|
|
|
|
if !self.flags.iter().any(|a| a.long.is_some() && a.long.unwrap() == "help") {
|
|
|
|
if self.help_short.is_none() && !self.short_list.contains(&'h') {
|
|
|
|
self.help_short = Some('h');
|
|
|
|
}
|
|
|
|
let arg = FlagBuilder {
|
|
|
|
name: "hclap_help",
|
|
|
|
short: self.help_short,
|
|
|
|
long: Some("help"),
|
|
|
|
help: Some("Prints help information"),
|
|
|
|
blacklist: None,
|
|
|
|
requires: None,
|
|
|
|
overrides: None,
|
|
|
|
settings: ArgFlags::new(),
|
|
|
|
};
|
|
|
|
self.long_list.push("help");
|
|
|
|
self.flags.push(arg);
|
|
|
|
}
|
|
|
|
if !self.settings.is_set(&AppSettings::DisableVersion) &&
|
|
|
|
!self.flags.iter().any(|a| a.long.is_some() && a.long.unwrap() == "version") {
|
|
|
|
if self.version_short.is_none() && !self.short_list.contains(&'V') {
|
|
|
|
self.version_short = Some('V');
|
|
|
|
}
|
|
|
|
// name is "vclap_version" because flags are sorted by name
|
|
|
|
let arg = FlagBuilder {
|
|
|
|
name: "vclap_version",
|
|
|
|
short: self.version_short,
|
|
|
|
long: Some("version"),
|
|
|
|
help: Some("Prints version information"),
|
|
|
|
blacklist: None,
|
|
|
|
requires: None,
|
|
|
|
overrides: None,
|
|
|
|
settings: ArgFlags::new(),
|
|
|
|
};
|
|
|
|
self.long_list.push("version");
|
|
|
|
self.flags.push(arg);
|
|
|
|
}
|
|
|
|
if !self.subcommands.is_empty() &&
|
|
|
|
!self.subcommands
|
|
|
|
.iter()
|
|
|
|
.any(|a| a.name_slice == "help") {
|
|
|
|
self.subcommands.push(App::new("help").about("Prints this message"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn check_for_help_and_version_str(&self, arg: &str) -> ClapResult<()> {
|
|
|
|
if arg == "help" && self.settings.is_set(&AppSettings::NeedsLongHelp) {
|
|
|
|
try!(self._help());
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
if arg == "version" && self.settings.is_set(&AppSettings::NeedsLongVersion) {
|
|
|
|
try!(self._version());
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn check_for_help_and_version_char(&self, arg: char) -> ClapResult<()> {
|
|
|
|
if let Some(h) = self.help_short { if arg == h { try!(self._help()); } }
|
|
|
|
if let Some(v) = self.version_short { if arg == v { try!(self._version()); } }
|
|
|
|
Ok(())
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn _help(&self) -> ClapResult<()> {
|
|
|
|
try!(self.print_help());
|
|
|
|
Err(ClapError {
|
|
|
|
error: String::new(),
|
|
|
|
error_type: ClapErrorType::HelpDisplayed,
|
|
|
|
})
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn _version(&self) -> ClapResult<()> {
|
|
|
|
let out = io::stdout();
|
|
|
|
let mut buf_w = BufWriter::new(out.lock());
|
|
|
|
try!(self.print_version(&mut buf_w));
|
|
|
|
Err(ClapError {
|
|
|
|
error: String::new(),
|
|
|
|
error_type: ClapErrorType::VersionDisplayed,
|
|
|
|
})
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn parse_long_arg<'av>(&mut self,
|
|
|
|
matcher: &mut ArgMatcher<'ar>,
|
|
|
|
full_arg: &'av str)
|
|
|
|
-> ClapResult<Option<&'ar str>> {
|
|
|
|
let mut val = "";
|
|
|
|
let arg = if full_arg.contains("=") {
|
|
|
|
let parts: Vec<_> = full_arg.trim_left_matches(|c| c == '-').splitn(2, "=").collect();
|
|
|
|
val = parts[1];
|
|
|
|
parts[0]
|
|
|
|
} else {
|
|
|
|
full_arg.trim_left_matches(|c| c == '-')
|
|
|
|
};
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
if let Some(opt) = self.opts
|
|
|
|
.iter()
|
|
|
|
.filter(|v| v.long.is_some() && v.long.unwrap() == arg)
|
|
|
|
.next() {
|
|
|
|
let ret = try!(self.parse_opt(val, opt, matcher));
|
|
|
|
arg_post_processing!(self, opt, matcher);
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
return Ok(ret);
|
|
|
|
} else if let Some(flag) = self.flags
|
|
|
|
.iter()
|
|
|
|
.filter(|v| v.long.is_some() && v.long.unwrap() == arg)
|
|
|
|
.next() {
|
|
|
|
// Only flags could be help or version, and we need to check the raw long
|
|
|
|
// so this is the first point to check
|
|
|
|
try!(self.check_for_help_and_version_str(arg));
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
try!(self.parse_flag(flag, matcher));
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
// Handle conflicts, requirements, etc.
|
|
|
|
arg_post_processing!(self, flag, matcher);
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
return Ok(None);
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
self.did_you_mean_error(arg, matcher).map(|_| None)
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn parse_short_arg(&mut self,
|
|
|
|
matcher: &mut ArgMatcher<'ar>,
|
|
|
|
full_arg: &str)
|
|
|
|
-> ClapResult<Option<&'ar str>> {
|
|
|
|
let arg = &*full_arg.trim_left_matches(|c| c == '-');
|
|
|
|
for c in arg.chars() {
|
|
|
|
// Check for matching short options, and return the name if there is no trailing
|
|
|
|
// concatenated value: -oval
|
|
|
|
// Option: -o
|
|
|
|
// Value: val
|
|
|
|
if let Some(opt) = self.opts
|
|
|
|
.iter()
|
|
|
|
.filter(|&v| v.short.is_some() && v.short.unwrap() == c)
|
|
|
|
.next() {
|
|
|
|
// Check for trailing concatenated value
|
|
|
|
let val = arg.splitn(2, c).collect::<Vec<_>>()[1];
|
|
|
|
|
|
|
|
// Default to "we're expecting a value later"
|
|
|
|
let ret = try!(self.parse_opt(val, opt, matcher));
|
|
|
|
|
|
|
|
arg_post_processing!(self, opt, matcher);
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
return Ok(ret);
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
try!(self.check_for_help_and_version_char(c));
|
|
|
|
if let Some(flag) = self.flags.iter().filter(|&v| v.short.is_some() && v.short.unwrap() == c).next() {
|
|
|
|
// Only flags can be help or version
|
|
|
|
try!(self.parse_flag(flag, matcher));
|
|
|
|
// Handle conflicts, requirements, overrides, etc.
|
|
|
|
// Must be called here due to mutablilty
|
|
|
|
arg_post_processing!(self, flag, matcher);
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
}
|
|
|
|
Ok(None)
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn parse_opt(&self, val: &str, opt: &OptBuilder<'ar>, matcher: &mut ArgMatcher<'ar>) -> ClapResult<Option<&'ar str>> {
|
|
|
|
try!(self.validate_arg(opt, matcher));
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
if matcher.contains(opt.name) && !opt.settings.is_set(&ArgSettings::Multiple) {
|
|
|
|
// Not the first time, but we don't allow multiples
|
|
|
|
return Err(error_builder::UnexpectedMultipleUsage(
|
|
|
|
&*opt.to_string(),
|
|
|
|
&*try!(self.create_current_usage(matcher))));
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
if val.len() != 0 {
|
|
|
|
if opt.is_set(ArgSettings::EmptyValues) {
|
|
|
|
try!(self.add_val_to_arg(opt, val, matcher));
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
return Err(error_builder::EmptyValue(
|
|
|
|
&*opt.to_string(),
|
|
|
|
&*try!(self.create_current_usage(matcher))));
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
// If it doesn't allow mutliples, (or a specific number of values), or we don't have any
|
|
|
|
// values yet, we want to return the name of this arg so the next arg is parsed as a value
|
|
|
|
// otherwise we're done getting values
|
|
|
|
if opt.settings.is_set(&ArgSettings::Multiple) || opt.num_vals.is_some() || !matcher.contains(opt.name) {
|
|
|
|
return Ok(Some(opt.name));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
Ok(None)
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn add_val_to_arg<A>(&self,
|
|
|
|
arg: &A,
|
|
|
|
val: &str,
|
|
|
|
matcher: &mut ArgMatcher<'ar>)
|
|
|
|
-> ClapResult<Option<&'ar str>>
|
|
|
|
where A: AnyArg<'ar> + Display {
|
|
|
|
matcher.add_val_to(arg.name(), val.to_owned());
|
|
|
|
|
|
|
|
// Increment or create the group "args"
|
|
|
|
if let Some(grps) = self.groups_for_arg(arg.name()) {
|
|
|
|
for grp in grps {
|
|
|
|
matcher.add_val_to(grp, val.to_owned());
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
// The validation must come AFTER inserting into 'matcher' or the usage string
|
|
|
|
// can't be built
|
|
|
|
self.validate_value(arg, val, matcher)
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn validate_value<A>(&self, arg: &A, val: &str, matcher: &ArgMatcher<'ar>) -> ClapResult<Option<&'ar str>>
|
|
|
|
where A: AnyArg<'ar> + Display {
|
|
|
|
if let Some(ref p_vals) = arg.possible_vals() {
|
|
|
|
if !p_vals.contains(&val) {
|
2015-11-09 08:48:49 +00:00
|
|
|
return Err(
|
2015-11-09 13:57:20 +00:00
|
|
|
error_builder::InvalidValue(val,
|
2015-11-09 08:48:49 +00:00
|
|
|
p_vals,
|
2015-11-09 13:57:20 +00:00
|
|
|
&arg.to_string(),
|
|
|
|
&*try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
if !arg.is_set(ArgSettings::EmptyValues) &&
|
|
|
|
val.is_empty() &&
|
|
|
|
matcher.contains(arg.name()) {
|
|
|
|
return Err(error_builder::EmptyValue(&*arg.to_string(),
|
|
|
|
&*try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
if let Some(ref vtor) = arg.validator() {
|
|
|
|
if let Err(e) = vtor(val.to_owned()) {
|
2015-11-09 08:48:49 +00:00
|
|
|
return Err(error_builder::ValueValidationError(&*e));
|
|
|
|
}
|
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
let vals = matcher.get(arg.name())
|
|
|
|
.expect(INTERNAL_ERROR_MSG)
|
|
|
|
.values.as_ref()
|
|
|
|
.expect(INTERNAL_ERROR_MSG)
|
|
|
|
.len();
|
|
|
|
if let Some(max) = arg.max_vals() {
|
|
|
|
if (vals as u8) < max {
|
|
|
|
return Ok(Some(arg.name()));
|
|
|
|
} else {
|
|
|
|
return Ok(None);
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
}
|
|
|
|
if let Some(..) = arg.min_vals() {
|
|
|
|
return Ok(Some(arg.name()));
|
|
|
|
}
|
|
|
|
if let Some(num) = arg.num_vals() {
|
|
|
|
if arg.is_set(ArgSettings::Multiple) {
|
|
|
|
if (vals as u8) < num {
|
|
|
|
return Ok(Some(arg.name()));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (vals as u8 % num) != 0 {
|
|
|
|
return Ok(Some(arg.name()));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
if arg.is_set(ArgSettings::Multiple) {
|
|
|
|
return Ok(Some(arg.name()));
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn parse_flag(&self, flag: &FlagBuilder<'ar>, matcher: &mut ArgMatcher<'ar>) -> ClapResult<()> {
|
|
|
|
// Validate that we can actually accept this arg
|
|
|
|
try!(self.validate_arg(flag, matcher));
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
// First occurrence or not?
|
|
|
|
if !matcher.contains(flag.name) {
|
|
|
|
// If this is the first, then add this flag itself
|
|
|
|
matcher.insert(flag.name);
|
|
|
|
} else if !flag.settings.is_set(&ArgSettings::Multiple) {
|
|
|
|
// Not the first time, but we don't allow multiples
|
|
|
|
return Err(error_builder::UnexpectedMultipleUsage(
|
|
|
|
&*flag.to_string(),
|
|
|
|
&*try!(self.create_current_usage(matcher))));
|
|
|
|
} else {
|
|
|
|
matcher.inc_occurrence_of(flag.name);
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
// Increment or create the group "args"
|
|
|
|
self.groups_for_arg(flag.name).and_then(|vec| Some(matcher.inc_occurrences_of(&vec)));
|
2015-11-09 08:48:49 +00:00
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
Ok(())
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn validate_arg<A>(&self, arg: &A, matcher: &mut ArgMatcher<'ar>) -> ClapResult<()>
|
2015-11-09 12:21:28 +00:00
|
|
|
where A: AnyArg<'ar> + Display {
|
2015-11-09 13:57:20 +00:00
|
|
|
// May not be needed since we can't get here without being an Arg of some type
|
|
|
|
//
|
|
|
|
// if arg.has_switch() && (!self.flags.iter().any(|f| f.name == arg.name()) &&
|
|
|
|
// !self.opts.iter().any(|f| f.name == arg.name())) {
|
|
|
|
// return Err(error_builder::InvalidArgument(
|
|
|
|
// &*format!("{}", arg),
|
|
|
|
// None,
|
|
|
|
// &*try!(self.create_current_usage(matcher))));
|
|
|
|
// }
|
|
|
|
|
2015-11-09 12:21:28 +00:00
|
|
|
// Ensure this arg isn't on the mutually excludes list
|
|
|
|
if self.blacklist.contains(&arg.name()) {
|
2015-11-09 13:57:20 +00:00
|
|
|
matcher.remove(arg.name());
|
2015-11-09 12:21:28 +00:00
|
|
|
return Err(error_builder::ArgumentConflict(
|
|
|
|
arg.to_string(),
|
2015-11-09 13:57:20 +00:00
|
|
|
self.blacklisted_from(arg.name(), &matcher),
|
|
|
|
try!(self.create_current_usage(matcher))));
|
2015-11-09 12:21:28 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
// Make sure this isn't one being added multiple times if it doesn't support it
|
|
|
|
if matcher.contains(arg.name()) && !arg.is_set(ArgSettings::Multiple) {
|
2015-11-09 12:21:28 +00:00
|
|
|
return Err(error_builder::UnexpectedMultipleUsage(
|
2015-11-09 13:57:20 +00:00
|
|
|
&*format!("{}", arg),
|
|
|
|
&*try!(self.create_current_usage(matcher))));
|
2015-11-09 12:21:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn validate_blacklist(&self, matcher: &mut ArgMatcher<'ar>) -> ClapResult<()> {
|
2015-11-09 08:48:49 +00:00
|
|
|
for name in self.blacklist.iter() {
|
2015-11-09 13:57:20 +00:00
|
|
|
if matcher.contains(name) {
|
|
|
|
matcher.remove(name);
|
2015-11-09 08:48:49 +00:00
|
|
|
return Err(error_builder::ArgumentConflict(
|
|
|
|
format!("{}", Format::Warning(
|
|
|
|
if let Some(f) = self.flags.iter().filter(|f| &f.name == name).next() {
|
|
|
|
f.to_string()
|
|
|
|
} else if let Some(o) = self.opts.iter()
|
|
|
|
.filter(|o| &o.name == name)
|
|
|
|
.next() {
|
|
|
|
o.to_string()
|
|
|
|
} else {
|
|
|
|
match self.positionals.values()
|
|
|
|
.filter(|p| p.name == *name)
|
|
|
|
.next() {
|
|
|
|
Some(p) => p.to_string(),
|
|
|
|
None => format!("'{}'", name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)),
|
2015-11-09 13:57:20 +00:00
|
|
|
self.blacklisted_from(name, &matcher),
|
|
|
|
try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
} else if self.groups.contains_key(name) {
|
|
|
|
for n in self.arg_names_in_group(name) {
|
2015-11-09 13:57:20 +00:00
|
|
|
if matcher.contains(n) {
|
|
|
|
matcher.remove(n);
|
2015-11-09 08:48:49 +00:00
|
|
|
return Err(error_builder::ArgumentConflict(
|
|
|
|
format!("{}", Format::Warning(
|
|
|
|
if let Some(f) = self.flags.iter()
|
|
|
|
.filter(|f| &f.name == name)
|
|
|
|
.next() {
|
|
|
|
f.to_string()
|
|
|
|
} else if let Some(o) = self.opts
|
|
|
|
.iter()
|
|
|
|
.filter(|o| &o.name == name)
|
|
|
|
.next() {
|
|
|
|
o.to_string()
|
|
|
|
} else {
|
|
|
|
match self.positionals.values()
|
|
|
|
.filter(|p| p.name == n)
|
|
|
|
.next() {
|
|
|
|
Some(p) => p.to_string(),
|
|
|
|
None => format!("'{}'", name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)),
|
2015-11-09 13:57:20 +00:00
|
|
|
self.blacklisted_from(name, &matcher),
|
|
|
|
try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn validate_num_args(&self, matcher: &mut ArgMatcher<'ar>) -> ClapResult<()> {
|
|
|
|
for (name, ma) in matcher.iter() {
|
2015-11-09 08:48:49 +00:00
|
|
|
if self.groups.contains_key(name) {
|
|
|
|
continue;
|
|
|
|
} else if let Some(ref vals) = ma.values {
|
|
|
|
if let Some(f) = self.opts
|
|
|
|
.iter()
|
|
|
|
.filter(|o| &o.name == name)
|
|
|
|
.next() {
|
|
|
|
if let Some(num) = f.num_vals {
|
|
|
|
let should_err = if f.settings.is_set(&ArgSettings::Multiple) {
|
|
|
|
((vals.len() as u8) % num) != 0
|
|
|
|
} else {
|
|
|
|
num != (vals.len() as u8)
|
|
|
|
};
|
|
|
|
if should_err {
|
|
|
|
return Err(error_builder::WrongNumValues(
|
|
|
|
&*f.to_string(),
|
|
|
|
num,
|
|
|
|
if f.settings.is_set(&ArgSettings::Multiple) {
|
|
|
|
(vals.len() % num as usize)
|
|
|
|
} else {
|
|
|
|
vals.len()
|
|
|
|
},
|
|
|
|
if vals.len() == 1 ||
|
|
|
|
(f.settings.is_set(&ArgSettings::Multiple) &&
|
|
|
|
(vals.len() % num as usize) == 1) {
|
|
|
|
"as"
|
|
|
|
} else {
|
|
|
|
"ere"
|
|
|
|
},
|
2015-11-09 13:57:20 +00:00
|
|
|
&*try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(num) = f.max_vals {
|
|
|
|
if (vals.len() as u8) > num {
|
|
|
|
return Err(error_builder::TooManyValues(
|
2015-11-09 13:57:20 +00:00
|
|
|
vals.get(&vals.keys()
|
2015-11-09 08:48:49 +00:00
|
|
|
.last()
|
2015-11-09 12:21:28 +00:00
|
|
|
.expect(INTERNAL_ERROR_MSG))
|
|
|
|
.expect(INTERNAL_ERROR_MSG),
|
2015-11-09 08:48:49 +00:00
|
|
|
&f.to_string(),
|
2015-11-09 13:57:20 +00:00
|
|
|
&try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(num) = f.min_vals {
|
|
|
|
if (vals.len() as u8) < num {
|
|
|
|
return Err(error_builder::TooFewValues(
|
|
|
|
&*f.to_string(),
|
|
|
|
num,
|
|
|
|
vals.len(),
|
2015-11-09 13:57:20 +00:00
|
|
|
&*try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if let Some(f) = self.positionals
|
|
|
|
.values()
|
|
|
|
.filter(|p| &p.name == name)
|
|
|
|
.next() {
|
|
|
|
if let Some(num) = f.num_vals {
|
|
|
|
if num != vals.len() as u8 {
|
|
|
|
return Err(error_builder::WrongNumValues(
|
|
|
|
&*f.to_string(),
|
|
|
|
num,
|
|
|
|
vals.len(),
|
|
|
|
if vals.len() == 1 {
|
|
|
|
"as"
|
|
|
|
} else {
|
|
|
|
"ere"
|
|
|
|
},
|
2015-11-09 13:57:20 +00:00
|
|
|
&*try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(max) = f.max_vals {
|
|
|
|
if (vals.len() as u8) > max {
|
|
|
|
return Err(error_builder::TooManyValues(
|
2015-11-09 13:57:20 +00:00
|
|
|
vals.get(&vals.keys()
|
2015-11-09 08:48:49 +00:00
|
|
|
.last()
|
2015-11-09 13:57:20 +00:00
|
|
|
.expect(INTERNAL_ERROR_MSG))
|
|
|
|
.expect(INTERNAL_ERROR_MSG),
|
2015-11-09 08:48:49 +00:00
|
|
|
&f.to_string(),
|
2015-11-09 13:57:20 +00:00
|
|
|
&try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(min) = f.min_vals {
|
|
|
|
if (vals.len() as u8) < min {
|
|
|
|
return Err(error_builder::TooFewValues(
|
|
|
|
&*f.to_string(),
|
|
|
|
min,
|
|
|
|
vals.len(),
|
2015-11-09 13:57:20 +00:00
|
|
|
&*try!(self.create_current_usage(matcher))));
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2015-11-09 13:57:20 +00:00
|
|
|
fn validate_required(&self, matcher: &ArgMatcher<'ar>) -> ClapResult<()> {
|
2015-11-09 08:48:49 +00:00
|
|
|
'outer: for name in self.required.iter() {
|
2015-11-09 13:57:20 +00:00
|
|
|
if matcher.contains(name) {
|
2015-11-09 08:48:49 +00:00
|
|
|
continue 'outer;
|
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
if let Some(grp) = self.groups.get(name) {
|
|
|
|
for arg in &grp.args {
|
|
|
|
if matcher.contains(arg) { continue 'outer; }
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
if self.groups.values().any(|g| g.args.contains(name)) {
|
|
|
|
continue 'outer;
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
if let Some(a) = self.flags.iter().filter(|f| &f.name == name).next() {
|
2015-11-09 13:57:20 +00:00
|
|
|
if self._validate_blacklist_required(a, matcher) { continue 'outer; }
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
if let Some(a) = self.opts.iter().filter(|o| &o.name == name).next() {
|
2015-11-09 13:57:20 +00:00
|
|
|
if self._validate_blacklist_required(a, matcher) { continue 'outer; }
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
if let Some(a) = self.positionals.values().filter(|p| &p.name == name).next() {
|
|
|
|
if self._validate_blacklist_required(a, matcher) { continue 'outer; }
|
|
|
|
}
|
|
|
|
return Err(error_builder::MissingRequiredArgument(
|
|
|
|
&*self.get_required_from(&self.required, Some(matcher))
|
|
|
|
.iter()
|
|
|
|
.fold(String::new(),
|
|
|
|
|acc, s| acc + &format!("\n\t{}", Format::Error(s))[..]),
|
|
|
|
&*try!(self.create_current_usage(matcher))));
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn _validate_blacklist_required<A>(&self, a: &A, matcher: &ArgMatcher) -> bool where A: AnyArg<'ar> {
|
|
|
|
if let Some(bl) = a.blacklist() {
|
|
|
|
for n in bl.iter() {
|
|
|
|
if matcher.contains(n) {
|
|
|
|
return true;
|
|
|
|
} else if self.groups
|
|
|
|
.get(n)
|
|
|
|
.map(|g| g.args.iter().any(|an| matcher.contains(an)))
|
|
|
|
.unwrap_or(false) {
|
|
|
|
return true;
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
2015-11-09 13:57:20 +00:00
|
|
|
|
|
|
|
fn did_you_mean_error(&self, arg: &str, matcher: &mut ArgMatcher<'ar>) -> ClapResult<()> {
|
|
|
|
// Didn't match a flag or option...maybe it was a typo and close to one
|
|
|
|
let suffix = suggestions::did_you_mean_suffix(arg,
|
|
|
|
self.long_list.iter(),
|
|
|
|
suggestions::DidYouMeanMessageStyle::LongFlag);
|
|
|
|
|
|
|
|
// Add the arg to the matches to build a proper usage string
|
|
|
|
if let Some(name) = suffix.1 {
|
|
|
|
if let Some(opt) = self.opts
|
|
|
|
.iter()
|
|
|
|
.filter(|o| o.long.is_some() && o.long.unwrap() == name)
|
|
|
|
.next() {
|
|
|
|
self.groups_for_arg(opt.name).and_then(|grps| Some(matcher.inc_occurrences_of(&grps)));
|
|
|
|
matcher.insert(opt.name);
|
|
|
|
} else if let Some(flg) = self.flags
|
|
|
|
.iter()
|
|
|
|
.filter(|f| f.long.is_some() && f.long.unwrap() == name)
|
|
|
|
.next() {
|
|
|
|
self.groups_for_arg(flg.name).and_then(|grps| Some(matcher.inc_occurrences_of(&grps)));
|
|
|
|
matcher.insert(flg.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(error_builder::InvalidArgument(&*format!("--{}", arg),
|
|
|
|
Some(&*suffix.0),
|
|
|
|
&*try!(self.create_current_usage(matcher))))
|
|
|
|
}
|
2015-11-09 08:48:49 +00:00
|
|
|
}
|