clap/src/args/arg.rs

552 lines
20 KiB
Rust

use usageparser::{UsageParser, UsageToken};
/// The abstract representation of a command line argument used by the consumer of the library.
/// Used to set all the options and relationships that define a valid argument for the program.
///
/// This struct is used by the library consumer and describes the command line arguments for
/// their program. Then evaluates the settings the consumer provided and determines the concret
/// argument type to use when parsing.
///
/// There are two methods for constructing `Arg`s, using the builder pattern and setting options
/// manually, or using a usage string which is far less verbose. You can also use a combination
/// of the two methods to achieve the best of both worlds.
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// // Using the traditional builder pattern and setting each option manually
/// Arg::with_name("conifg")
/// .short("c")
/// .long("config")
/// .takes_value(true)
/// .help("Provides a config file to myprog")
/// # ).arg(
/// // Using a usage string (setting a similar argument to the one above)
/// Arg::from_usage("-i --input=[input] 'Provides an input file to the program'")
/// # ).get_matches();
pub struct Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// The unique name of the argument, required
#[doc(hidden)]
pub name: &'n str,
/// The short version (i.e. single character) of the argument, no preceding `-`
/// **NOTE:** `short` is mutually exclusive with `index`
#[doc(hidden)]
pub short: Option<char>,
/// The long version of the flag (i.e. word) without the preceding `--`
/// **NOTE:** `long` is mutually exclusive with `index`
#[doc(hidden)]
pub long: Option<&'l str>,
/// The string of text that will displayed to the user when the application's
/// `help` text is displayed
#[doc(hidden)]
pub help: Option<&'h str>,
/// If this is a required by default when using the command line program
/// i.e. a configuration file that's required for the program to function
/// **NOTE:** required by default means, it is required *until* mutually
/// exclusive arguments are evaluated.
#[doc(hidden)]
pub required: bool,
/// Determines if this argument is an option, vice a flag or positional and
/// is mutually exclusive with `index` and `multiple`
#[doc(hidden)]
pub takes_value: bool,
/// The index of the argument. `index` is mutually exclusive with `takes_value`
/// and `multiple`
#[doc(hidden)]
pub index: Option<u8>,
/// Determines if multiple instances of the same flag are allowed. `multiple`
/// is mutually exclusive with `index` and `takes_value`.
/// I.e. `-v -v -v` or `-vvv`
#[doc(hidden)]
pub multiple: bool,
/// A list of names for other arguments that *may not* be used with this flag
#[doc(hidden)]
pub blacklist: Option<Vec<&'b str>>,
/// A list of possible values for an option or positional argument
#[doc(hidden)]
pub possible_vals: Option<Vec<&'p str>>,
/// A list of names of other arguments that are *required* to be used when
/// this flag is used
#[doc(hidden)]
pub requires: Option<Vec<&'r str>>
}
impl<'n, 'l, 'h, 'b, 'p, 'r> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
/// Creates a new instace of `Arg` using a unique string name.
/// The name will be used by the library consumer to get information about
/// whether or not the argument was used at runtime.
///
/// **NOTE:** in the case of arguments that take values (i.e. `takes_value(true)`)
/// and positional arguments (i.e. those without a `-` or `--`) the name will also
/// be displayed when the user prints the usage/help information of the program.
///
/// **NOTE:** this function is deprecated in favor of Arg::with_name() to stay consistant with
/// Rust APIs
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// Arg::new("conifg")
/// # .short("c")
/// # ).get_matches();
pub fn new(n: &'n str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
Arg {
name: n,
short: None,
long: None,
help: None,
required: false,
takes_value: false,
multiple: false,
index: None,
possible_vals: None,
blacklist: None,
requires: None,
}
}
/// Creates a new instace of `Arg` using a unique string name.
/// The name will be used by the library consumer to get information about
/// whether or not the argument was used at runtime.
///
/// **NOTE:** in the case of arguments that take values (i.e. `takes_value(true)`)
/// and positional arguments (i.e. those without a `-` or `--`) the name will also
/// be displayed when the user prints the usage/help information of the program.
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// Arg::with_name("conifg")
/// # .short("c")
/// # ).get_matches();
pub fn with_name(n: &'n str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
Arg {
name: n,
short: None,
long: None,
help: None,
required: false,
takes_value: false,
multiple: false,
index: None,
possible_vals: None,
blacklist: None,
requires: None,
}
}
/// Creates a new instace of `Arg` from a usage string. Allows creation of basic settings
/// for Arg (i.e. everything except relational rules). The syntax is flexible, but there are
/// some rules to follow.
///
/// **NOTE**: only properties which you wish to set must be present
///
/// 1. Name (arguments with a `long` or that take a value can ommit this if desired),
/// use `[]` for non-required arguments, or `<>` for required arguments.
/// 2. Short preceded by a `-`
/// 3. Long preceded by a `--` (this may be used as the name, if the name is omitted. If the
/// name is *not* omittied, the name takes precedence over the `long`)
/// 4. Value (this can be used as the name if the name is not manually specified. If the name
/// is manually specified, it takes precedence. If this value is used as the name, it uses the
/// same `[]` and `<>` requirement specification rules. If it is *not* used as the name, it
/// still needs to be surrounded by either `[]` or `<>` but there is no requirement effect,
/// as the requirement rule is determined by the real name. This value may follow the `short`
/// or `long`, it doesn't matter. If it follows the `long`, it may follow either a `=` or ` `
/// there is no difference, just personal preference. If this follows a `short` it can only
/// be after a ` `) i.e. `-c [name]`, `--config [name]`, `--config=[name]`, etc.
/// 5. Multiple specifier `...` (the `...` may follow the name, `short`, `long`, or value *without*
/// a ` ` space) i.e. `<name>... -c`, `--config <name>...`, `[name] -c...`, etc.
/// 6. The help info surrounded by `'`s (single quotes)
/// 7. The index of a positional argument will be the next available index (you don't need to
/// specify one) i.e. all arguments without a `short` or `long` will be treated as positional
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// .args(vec![
///
/// // A option argument with a long, named "conf" (note: because the name was specified
/// // the portion after the long can be called anything, only the first name will be displayed
/// // to the user. Also, requirement is set with the *name*, so the portion after the long could
/// // be either <> or [] and it wouldn't matter, so long as it's one of them. Had the name been
/// // omitted, the name would have been derived from the portion after the long and those rules
/// // would have mattered)
/// Arg::from_usage("[conf] --config=[c] 'a required file for the configuration'"),
///
/// // A flag with a short, a long, named "debug", and accepts multiple values
/// Arg::from_usage("-d --debug... 'turns on debugging information"),
///
/// // A required positional argument named "input"
/// Arg::from_usage("<input> 'the input file to use'")
/// ])
/// # .get_matches();
pub fn from_usage(u: &'n str) -> Arg<'n, 'n, 'n, 'b, 'p, 'r> {
assert!(u.len() > 0, "Arg::from_usage() requires a non-zero-length usage string but none was provided");
let mut name = None;
let mut short = None;
let mut long = None;
let mut help = None;
let mut required = false;
let mut takes_value = false;
let mut multiple = false;
let parser = UsageParser::with_usage(u);
for_match!{ parser,
UsageToken::Name(n, req) => {
if name.is_none() {
name = Some(n);
if let Some(r) = req {
required = r;
}
} else if let Some(l) = long {
if l == name.unwrap() {
if let Some(r) = req {
required = r;
}
name = Some(n);
} else if n != l {
name = Some(n);
}
}
if short.is_some() || long.is_some() {
takes_value = true;
}
// if let Some(l) = long {
// if n != name.unwrap() && name.unwrap() == l {
// name = Some(n);
// if let Some(r) = req {
// required = r;
// }
// }
// }
},
UsageToken::Short(s) => {
short = Some(s);
},
UsageToken::Long(l) => {
long = Some(l);
if name.is_none() {
name = Some(l);
}
},
UsageToken::Help(h) => {
help = Some(h);
},
UsageToken::Multiple => {
multiple = true;
}
}
Arg {
name: name.unwrap(),
short: short,
long: long,
help: help,
required: required,
takes_value: takes_value,
multiple: multiple,
index: None,
possible_vals: None,
blacklist: None,
requires: None,
}
}
/// Sets the short version of the argument without the preceding `-`.
///
///
/// By default `clap` automatically assigns `v` and `h` to display version and help information
/// respectivly. You may use `v` or `h` for your own purposes, in which case `clap` simply
/// will not asign those to the displaying of version or help.
///
/// **NOTE:** Any leading `-` characters will be stripped, and only the first
/// non `-` chacter will be used as the `short` version
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// # Arg::new("conifg")
/// .short("c")
/// # ).get_matches();
pub fn short(mut self, s: &str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
self.short = s.trim_left_matches(|c| c == '-').chars().nth(0);
self
}
/// Sets the long version of the argument without the preceding `--`.
///
/// By default `clap` automatically assigns `version` and `help` to display version and help information
/// respectivly. You may use `version` or `help` for your own purposes, in which case `clap` simply
/// will not asign those to the displaying of version or help automatically, and you will have to do
/// so manually.
///
/// **NOTE:** Any leading `-` characters will be stripped
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// # Arg::new("conifg")
/// .long("config")
/// # ).get_matches();
pub fn long(mut self, l: &'l str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
self.long = Some(l.trim_left_matches(|c| c == '-'));
self
}
/// Sets the help text of the argument that will be displayed to the user
/// when they print the usage/help information.
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// # Arg::new("conifg")
/// .help("The config file used by the myprog")
/// # ).get_matches();
pub fn help(mut self, h: &'h str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
self.help = Some(h);
self
}
/// Sets whether or not the argument is required by default. Required by
/// default means it is required, when no other mutually exlusive rules have
/// been evaluated. Mutually exclusive rules take precedence over being required
/// by default.
///
/// **NOTE:** Flags (i.e. not positional, or arguments that take values)
/// cannot be required by default.
/// when they print the usage/help information.
///
///
/// #Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// # Arg::with_name("conifg")
/// .required(true)
/// # ).get_matches();
pub fn required(mut self, r: bool) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
self.required = r;
self
}
/// Sets a mutually exclusive argument by name. I.e. when using this argument,
/// the following argument can't be present.
///
/// **NOTE:** Mutually exclusive rules take precedence over being required
/// by default. Mutually exclusive rules only need to be set for one of the two
/// arguments, they do not need to be set for each.
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let myprog = App::new("myprog").arg(Arg::with_name("conifg")
/// .mutually_excludes("debug")
/// # ).get_matches();
pub fn mutually_excludes(mut self, name: &'b str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
if let Some(ref mut vec) = self.blacklist {
vec.push(name);
} else {
self.blacklist = Some(vec![name]);
}
self
}
/// Sets a mutually exclusive arguments by names. I.e. when using this argument,
/// the following argument can't be present.
///
/// **NOTE:** Mutually exclusive rules take precedence over being required
/// by default. Mutually exclusive rules only need to be set for one of the two
/// arguments, they do not need to be set for each.
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let myprog = App::new("myprog").arg(Arg::with_name("conifg")
/// .mutually_excludes_all(
/// vec!["debug", "input"])
/// # ).get_matches();
pub fn mutually_excludes_all(mut self, names: Vec<&'b str>) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
if let Some(ref mut vec) = self.blacklist {
for n in names {
vec.push(n);
}
} else {
self.blacklist = Some(names);
}
self
}
/// Sets an argument by name that is required when this one is presnet I.e. when
/// using this argument, the following argument *must* be present.
///
/// **NOTE:** Mutually exclusive rules take precedence over being required
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let myprog = App::new("myprog").arg(Arg::with_name("conifg")
/// .requires("debug")
/// # ).get_matches();
pub fn requires(mut self, name: &'r str) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
if let Some(ref mut vec) = self.requires {
vec.push(name);
} else {
self.requires = Some(vec![name]);
}
self
}
/// Sets arguments by names that are required when this one is presnet I.e. when
/// using this argument, the following arguments *must* be present.
///
/// **NOTE:** Mutually exclusive rules take precedence over being required
/// by default.
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let myprog = App::new("myprog").arg(Arg::with_name("conifg")
/// .requires_all(
/// vec!["debug", "input"])
/// # ).get_matches();
pub fn requires_all(mut self, names: Vec<&'r str>) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
if let Some(ref mut vec) = self.requires {
for n in names {
vec.push(n);
}
} else {
self.requires = Some(names);
}
self
}
/// Specifies that the argument takes an additional value at run time.
///
/// **NOTE:** When setting this to `true` the `name` of the argument
/// will be used when printing the help/usage information to the user.
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// # Arg::with_name("conifg")
/// .takes_value(true)
/// # ).get_matches();
pub fn takes_value(mut self, tv: bool) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
self.takes_value = tv;
self
}
/// Specifies the index of a positional argument starting at 1.
///
/// **NOTE:** When setting this, any `short` or `long` values you set
/// are ignored as positional arguments cannot have a `short` or `long`.
/// Also, the name will be used when printing the help/usage information
/// to the user.
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// # Arg::with_name("conifg")
/// .index(1)
/// # ).get_matches();
pub fn index(mut self, idx: u8) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
self.index = Some(idx);
self
}
/// Specifies if the flag may appear more than once such as for multiple debugging
/// levels (as an example). `-ddd` for three levels of debugging, or `-d -d -d`.
/// When this is set to `true` you recieve the number of occurances the user supplied
/// of a particular flag at runtime.
///
/// **NOTE:** When setting this, any `takes_value` or `index` values you set
/// are ignored as flags cannot have a values or an `index`.
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// # Arg::with_name("debug")
/// .multiple(true)
/// # ).get_matches();
pub fn multiple(mut self, multi: bool) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
self.multiple = multi;
self
}
/// Specifies a list of possible values for this argument. At runtime, clap verifies that only
/// one of the specified values was used, or fails with a usage string.
///
/// **NOTE:** This setting only applies to options and positional arguments
///
///
/// # Example
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// # Arg::with_name("debug").index(1)
/// .possible_values(vec!["fast", "slow"])
/// # ).get_matches();
pub fn possible_values(mut self, names: Vec<&'p str>) -> Arg<'n, 'l, 'h, 'b, 'p, 'r> {
if let Some(ref mut vec) = self.possible_vals {
for n in names {
vec.push(n);
}
} else {
self.possible_vals = Some(names);
}
self
}
}