Merge pull request #1446 from clap-rs/v3-dev

v3 Dev Rollup
This commit is contained in:
Kevin K 2019-04-05 20:41:55 -04:00 committed by GitHub
commit 388f162646
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 1031 additions and 770 deletions

View file

@ -3,8 +3,15 @@ language: rust
cache: cargo
rust:
- nightly
- nightly-2019-03-23
- beta
- stable
- 1.30.0
matrix:
allow_failures:
- rust: nightly
nightly-2019-03-23:
- script: cargo clippy
before_script:
- |
pip install git+git://github.com/kbknapp/travis-cargo.git --user &&
@ -49,5 +56,4 @@ after_success:
echo "Uploaded code coverage"
env:
global:
- TRAVIS_CARGO_NIGHTLY_FEATURE=lints
- secure: JLBlgHY6OEmhJ8woewNJHmuBokTNUv7/WvLkJGV8xk0t6bXBwSU0jNloXwlH7FiQTc4TccX0PumPDD4MrMgxIAVFPmmmlQOCmdpYP4tqZJ8xo189E5zk8lKF5OyaVYCs5SMmFC3cxCsKjfwGIexNu3ck5Uhwe9jI0tqgkgM3URA=

View file

@ -36,7 +36,7 @@ keywords = [
]
categories = ["command-line-interface"]
description = """
A simple to use, efficient, and full featured Command Line Argument Parser
A simple to use, efficient, and full-featured Command Line Argument Parser
"""
[badges]
@ -65,7 +65,7 @@ ansi_term = { version = "0.11.0", optional = true }
[dev-dependencies]
regex = "1.0"
lazy_static = "1"
version-sync = "0.5"
version-sync = "0.8"
[features]
default = ["suggestions", "color", "vec_map", "derive"]
@ -74,8 +74,8 @@ color = ["ansi_term", "atty"]
wrap_help = ["term_size", "textwrap/term_size"]
derive = ["clap_derive"]
yaml = ["yaml-rust"]
unstable = [] # for building with unstable clap features (doesn't require nightly Rust)
nightly = [] # for building with unstable Rust features
unstable = [] # for building with unstable clap features (doesn't require nightly Rust) (currently none)
nightly = [] # for building with unstable Rust features (currently none)
debug = [] # Enables debug messages
no_cargo = [] # Enable if you're not using Cargo, disables Cargo-env-var-dependent macros
doc = ["yaml"] # All the features which add to documentation

View file

@ -4,7 +4,7 @@ clap
[![Crates.io](https://img.shields.io/crates/v/clap.svg)](https://crates.io/crates/clap) [![Crates.io](https://img.shields.io/crates/d/clap.svg)](https://crates.io/crates/clap) [![license](http://img.shields.io/badge/license-Apache 2.0-blue.svg)](https://github.com/clap-rs/clap/blob/master/LICENSE-APACHE) [![license](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/clap-rs/clap/blob/master/LICENSE-MIT) [![Coverage Status](https://coveralls.io/repos/clap-rs/clap/badge.svg?branch=master&service=github)](https://coveralls.io/github/clap-rs/clap?branch=master) [![Join the chat at https://gitter.im/clap-rs/clap](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/clap-rs/clap?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Linux: [![Build Status](https://travis-ci.org/clap-rs/clap.svg?branch=master)](https://travis-ci.org/clap-rs/clap)
Windows: [![Build status](https://ci.appveyor.com/api/projects/status/ejg8c33dn31nhv36/branch/master?svg=true)](https://ci.appveyor.com/project/clap-rs/clap/branch/master)
Windows: [![Build status](https://ci.appveyor.com/api/projects/status/ejg8c33dn31nhv36/branch/master?svg=true)](https://ci.appveyor.com/project/kbknapp/clap-rs/branch/master)
Command Line Argument Parser for Rust

View file

@ -1,10 +1,16 @@
The following is a list of [sponsors](https://clap.rs/sponsorship/) for the clap-rs project:
Below is a list of sponsors for the clap-rs project
[<img alt="Noelia Seva-Gonzalez" src="https://clap.rs/wp-content/uploads/2017/10/noelia_sm-1.png" width="117">](https://noeliasg.com/about/)
Noelia Seva-Gonzalez
If you are interested in becoming a sponsor for this project please our [sponsorship page](https://clap.rs/sponsorship/).
[<img alt="Rob Tsuk" src="https://clap.rs/wp-content/uploads/2017/10/robtsuk_sm.png" width="117">](https://github.com/rtsuk)
Rob Tsuk
## Recurring Sponsors:
[<img alt="messense" src="https://clap.rs/wp-content/uploads/2018/01/messense-400x400.png" width="117">](https://github.com/messense)
Messense
| [<img alt="Noelia Seva-Gonzalez" src="https://clap.rs/wp-content/uploads/2017/10/noelia_sm-1.png" width="117">](https://noeliasg.com/about/) | [<img alt="messense" src="https://clap.rs/wp-content/uploads/2018/01/messense-400x400.png" width="117">](https://github.com/messense) | [<img alt="Josh" src="https://clap.rs/wp-content/uploads/2018/11/josh_t.jpg" width="117">](https://joshtriplett.org) |
|:-:|:-:|:-:|
|Noelia Seva-Gonzalez | Messense | Josh Triplett |
## Single-Donation and Former Sponsors:
| [<img alt="Rob Tsuk" src="https://clap.rs/wp-content/uploads/2017/10/robtsuk_sm.png" width="117">](https://github.com/rtsuk)| | |
|:-:|:-:|:-:|
|Rob Tsuk| | |

View file

@ -24,14 +24,14 @@ fn build_app(b: &mut Bencher) { b.iter(|| create_app!()); }
#[bench]
fn add_flag(b: &mut Bencher) {
fn build_app() -> App<'static, 'static> { App::new("claptests") }
fn build_app() -> App<'static> { App::new("claptests") }
b.iter(|| build_app().arg(Arg::from("-s, --some 'something'")));
}
#[bench]
fn add_flag_ref(b: &mut Bencher) {
fn build_app() -> App<'static, 'static> { App::new("claptests") }
fn build_app() -> App<'static> { App::new("claptests") }
b.iter(|| {
let arg = Arg::from("-s, --some 'something'");
@ -41,14 +41,14 @@ fn add_flag_ref(b: &mut Bencher) {
#[bench]
fn add_opt(b: &mut Bencher) {
fn build_app() -> App<'static, 'static> { App::new("claptests") }
fn build_app() -> App<'static> { App::new("claptests") }
b.iter(|| build_app().arg(Arg::from("-s, --some <FILE> 'something'")));
}
#[bench]
fn add_opt_ref(b: &mut Bencher) {
fn build_app() -> App<'static, 'static> { App::new("claptests") }
fn build_app() -> App<'static> { App::new("claptests") }
b.iter(|| {
let arg = Arg::from("-s, --some <FILE> 'something'");
@ -58,14 +58,14 @@ fn add_opt_ref(b: &mut Bencher) {
#[bench]
fn add_pos(b: &mut Bencher) {
fn build_app() -> App<'static, 'static> { App::new("claptests") }
fn build_app() -> App<'static> { App::new("claptests") }
b.iter(|| build_app().arg(Arg::with_name("some")));
}
#[bench]
fn add_pos_ref(b: &mut Bencher) {
fn build_app() -> App<'static, 'static> { App::new("claptests") }
fn build_app() -> App<'static> { App::new("claptests") }
b.iter(|| {
let arg = Arg::with_name("some");

View file

@ -17,7 +17,7 @@ fn build_help(app: &mut App) -> String {
String::from_utf8(content).unwrap()
}
fn app_example1<'b, 'c>() -> App<'b, 'c> {
fn app_example1<'c>() -> App<'c> {
App::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
@ -32,14 +32,14 @@ fn app_example1<'b, 'c>() -> App<'b, 'c> {
)
}
fn app_example2<'b, 'c>() -> App<'b, 'c> {
fn app_example2<'c>() -> App<'c> {
App::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
}
fn app_example3<'b, 'c>() -> App<'b, 'c> {
fn app_example3<'c>() -> App<'c> {
App::new("MyApp")
.arg(
Arg::with_name("debug")
@ -62,7 +62,7 @@ fn app_example3<'b, 'c>() -> App<'b, 'c> {
.arg("-i, --int=[IFACE] 'Set an interface to use'")
}
fn app_example4<'b, 'c>() -> App<'b, 'c> {
fn app_example4<'c>() -> App<'c> {
App::new("MyApp")
.about("Parses an input file to do awesome things")
.version("1.0")
@ -87,7 +87,7 @@ fn app_example4<'b, 'c>() -> App<'b, 'c> {
)
}
fn app_example5<'b, 'c>() -> App<'b, 'c> {
fn app_example5<'c>() -> App<'c> {
App::new("MyApp").arg(
Arg::with_name("awesome")
.help("turns up the awesome")
@ -99,7 +99,7 @@ fn app_example5<'b, 'c>() -> App<'b, 'c> {
)
}
fn app_example6<'b, 'c>() -> App<'b, 'c> {
fn app_example6<'c>() -> App<'c> {
App::new("MyApp")
.arg(
Arg::with_name("input")
@ -116,7 +116,7 @@ fn app_example6<'b, 'c>() -> App<'b, 'c> {
)
}
fn app_example7<'b, 'c>() -> App<'b, 'c> {
fn app_example7<'c>() -> App<'c> {
App::new("MyApp")
.arg(Arg::with_name("config"))
.arg(Arg::with_name("output"))
@ -135,7 +135,7 @@ fn app_example7<'b, 'c>() -> App<'b, 'c> {
)
}
fn app_example8<'b, 'c>() -> App<'b, 'c> {
fn app_example8<'c>() -> App<'c> {
App::new("MyApp")
.arg(Arg::with_name("config"))
.arg(Arg::with_name("output"))
@ -154,7 +154,7 @@ fn app_example8<'b, 'c>() -> App<'b, 'c> {
)
}
fn app_example10<'b, 'c>() -> App<'b, 'c> {
fn app_example10<'c>() -> App<'c> {
App::new("myapp").about("does awesome things").arg(
Arg::with_name("CONFIG")
.help("The config file to use (default is \"config.json\")")

View file

@ -255,10 +255,10 @@ OPTIONS:
{unified}";
/// Build a clap application with short help strings.
pub fn app_short() -> App<'static, 'static> { app(false, |k| USAGES[k].short) }
pub fn app_short() -> App<'static> { app(false, |k| USAGES[k].short) }
/// Build a clap application with long help strings.
pub fn app_long() -> App<'static, 'static> { app(true, |k| USAGES[k].long) }
pub fn app_long() -> App<'static> { app(true, |k| USAGES[k].long) }
/// Build the help text of an application.
fn build_help(app: &mut App) -> String {
@ -275,7 +275,7 @@ fn build_help(app: &mut App) -> String {
///
/// This is an intentionally stand-alone module so that it can be used easily
/// in a `build.rs` script to build shell completion files.
fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static>
fn app<F>(_next_line_help: bool, doc: F) -> App<'static>
where
F: Fn(&'static str) -> &'static str,
{

View file

@ -22,7 +22,7 @@ fn parse_subcommands(b: &mut Bencher) {
b.iter(|| build_cli().get_matches_from(vec!["rustup override add stable"]));
}
pub fn build_cli() -> App<'static, 'static> {
pub fn build_cli() -> App<'static> {
App::new("rustup")
.version("0.9.0") // Simulating
.about("The Rust toolchain installer")

View file

@ -54,7 +54,7 @@ mod test {
// Legacy tests from the pyhton script days
pub fn complex_app() -> App<'static, 'static> {
pub fn complex_app() -> App<'static> {
let opt3_vals = ["fast", "slow"];
let pos3_vals = ["vi", "emacs"];
App::new("clap-test")

View file

@ -18,7 +18,7 @@ use clap::{App, Arg};
// Using arg_enum! is more like traditional enum declarations
//
// **NOTE:** Only bare variants are supported
arg_enum!{
arg_enum! {
#[derive(Debug)]
pub enum Oof {
Rab,
@ -27,7 +27,7 @@ arg_enum!{
}
}
arg_enum!{
arg_enum! {
#[derive(Debug)]
enum Foo {
Bar,

View file

@ -15,19 +15,21 @@ use std::process;
use yaml_rust::Yaml;
// Internal
use build::{Arg, ArgGroup, ArgSettings};
use mkeymap::MKeyMap;
use output::fmt::ColorWhen;
use output::{Help, Usage};
use parse::errors::Result as ClapResult;
use parse::{ArgMatcher, ArgMatches, Parser};
use INTERNAL_ERROR_MSG;
use crate::build::{Arg, ArgGroup, ArgSettings};
use crate::mkeymap::MKeyMap;
use crate::output::fmt::ColorWhen;
use crate::output::{Help, Usage};
use crate::parse::errors::Result as ClapResult;
use crate::parse::{ArgMatcher, ArgMatches, Parser};
use crate::util::{Key, HELP_HASH, VERSION_HASH};
use crate::INTERNAL_ERROR_MSG;
type Id = u64;
#[doc(hidden)]
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Propagation<'a> {
To(&'a str),
pub enum Propagation {
To(Id),
Full,
NextLevel,
None,
@ -62,10 +64,9 @@ pub enum Propagation<'a> {
/// ```
/// [`App::get_matches`]: ./struct.App.html#method.get_matches
#[derive(Default, Debug, Clone)]
pub struct App<'a, 'b>
where
'a: 'b,
{
pub struct App<'b> {
#[doc(hidden)]
pub id: Id,
#[doc(hidden)]
pub name: String,
#[doc(hidden)]
@ -105,16 +106,16 @@ where
#[doc(hidden)]
pub g_settings: AppFlags,
#[doc(hidden)]
pub args: MKeyMap<'a, 'b>,
pub args: MKeyMap<'b>,
#[doc(hidden)]
pub subcommands: Vec<App<'a, 'b>>,
pub subcommands: Vec<App<'b>>,
#[doc(hidden)]
pub groups: Vec<ArgGroup<'a>>,
pub groups: Vec<ArgGroup<'b>>,
#[doc(hidden)]
pub help_headings: Vec<Option<&'a str>>,
pub help_headings: Vec<Option<&'b str>>,
}
impl<'a, 'b> App<'a, 'b> {
impl<'b> App<'b> {
/// Creates a new instance of an application requiring a name. The name may be, but doesn't
/// have to be same as the binary. The name will be displayed to the user when they request to
/// print version or help and usage information.
@ -127,8 +128,11 @@ impl<'a, 'b> App<'a, 'b> {
/// # ;
/// ```
pub fn new<S: Into<String>>(n: S) -> Self {
let name = n.into();
let id = name.key();
App {
name: n.into(),
id,
name,
..Default::default()
}
}
@ -137,7 +141,7 @@ impl<'a, 'b> App<'a, 'b> {
pub fn get_name(&self) -> &str { &self.name }
/// Get the name of the binary
pub fn get_bin_name(&self) -> Option<&str> { self.bin_name.as_ref().map(|s| s.as_str()) }
pub fn get_bin_name(&self) -> Option<&str> { self.bin_name.as_ref().map(String::as_str) }
/// Sets a string of author(s) that will be displayed to the user when they
/// request the help information with `--help` or `-h`.
@ -623,8 +627,8 @@ impl<'a, 'b> App<'a, 'b> {
/// # ;
/// ```
/// [argument]: ./struct.Arg.html
pub fn arg<A: Into<Arg<'a, 'b>>>(mut self, a: A) -> Self {
let help_heading: Option<&'a str> = if let Some(option_str) = self.help_headings.last() {
pub fn arg<A: Into<Arg<'b>>>(mut self, a: A) -> Self {
let help_heading: Option<&'b str> = if let Some(option_str) = self.help_headings.last() {
*option_str
} else {
None
@ -637,7 +641,7 @@ impl<'a, 'b> App<'a, 'b> {
/// Set a custom section heading for future args. Every call to arg will
/// have this header (instead of its default header) until a subsequent
/// call to help_heading
pub fn help_heading(mut self, heading: &'a str) -> Self {
pub fn help_heading(mut self, heading: &'b str) -> Self {
self.help_headings.push(Some(heading));
self
}
@ -665,7 +669,7 @@ impl<'a, 'b> App<'a, 'b> {
pub fn args<I, T>(mut self, args: I) -> Self
where
I: IntoIterator<Item = T>,
T: Into<Arg<'a, 'b>>,
T: Into<Arg<'b>>,
{
// @TODO @perf @p4 @v3-beta: maybe extend_from_slice would be possible and perform better?
// But that may also not let us do `&["-a 'some'", "-b 'other']` because of not Into<Arg>
@ -814,7 +818,7 @@ impl<'a, 'b> App<'a, 'b> {
/// # ;
/// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html
pub fn group(mut self, group: ArgGroup<'a>) -> Self {
pub fn group(mut self, group: ArgGroup<'b>) -> Self {
self.groups.push(group);
self
}
@ -843,7 +847,7 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html
/// [`App`]: ./struct.App.html
pub fn groups(mut self, groups: &[ArgGroup<'a>]) -> Self {
pub fn groups(mut self, groups: &[ArgGroup<'b>]) -> Self {
for g in groups {
self = self.group(g.into());
}
@ -867,7 +871,7 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [``]: ./struct..html
/// [`App`]: ./struct.App.html
pub fn subcommand(mut self, subcmd: App<'a, 'b>) -> Self {
pub fn subcommand(mut self, subcmd: App<'b>) -> Self {
self.subcommands.push(subcmd);
self
}
@ -890,7 +894,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
pub fn subcommands<I>(mut self, subcmds: I) -> Self
where
I: IntoIterator<Item = App<'a, 'b>>,
I: IntoIterator<Item = App<'b>>,
{
for subcmd in subcmds {
self.subcommands.push(subcmd);
@ -973,14 +977,17 @@ impl<'a, 'b> App<'a, 'b> {
/// assert!(res.is_ok());
/// ```
/// [`Arg`]: ./struct.Arg.html
pub fn mut_arg<F>(mut self, arg: &'a str, f: F) -> Self
pub fn mut_arg<T, F>(mut self, arg_id: T, f: F) -> Self
where
F: FnOnce(Arg<'a, 'b>) -> Arg<'a, 'b>,
F: FnOnce(Arg<'b>) -> Arg<'b>,
T: Key + Into<&'b str>,
{
let a = self
.args
.remove_by_name(arg)
.unwrap_or_else(|| Arg::with_name(arg));
let id = arg_id.key();
let a = self.args.remove_by_name(id).unwrap_or_else(|| Arg {
id,
name: arg_id.into(),
..Arg::default()
});
self.args.push(f(a));
self
@ -1006,7 +1013,7 @@ impl<'a, 'b> App<'a, 'b> {
pub fn print_help(&mut self) -> ClapResult<()> {
// If there are global arguments, or settings we need to propagate them down to subcommands
// before parsing incase we run into a subcommand
self._build(Propagation::NextLevel);
self._build();
let out = io::stdout();
let mut buf_w = BufWriter::new(out.lock());
@ -1033,7 +1040,7 @@ impl<'a, 'b> App<'a, 'b> {
pub fn print_long_help(&mut self) -> ClapResult<()> {
// If there are global arguments, or settings we need to propagate them down to subcommands
// before parsing incase we run into a subcommand
self._build(Propagation::NextLevel);
self._build();
let out = io::stdout();
let mut buf_w = BufWriter::new(out.lock());
@ -1059,7 +1066,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`-h` (short)]: ./struct.Arg.html#method.help
/// [`--help` (long)]: ./struct.Arg.html#method.long_help
pub fn write_help<W: Write>(&mut self, w: &mut W) -> ClapResult<()> {
self._build(Propagation::NextLevel);
self._build();
let p = Parser::new(self);
Help::new(w, &p, false, false).write_help()
@ -1084,7 +1091,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`-h` (short)]: ./struct.Arg.html#method.help
/// [`--help` (long)]: ./struct.Arg.html#method.long_help
pub fn write_long_help<W: Write>(&mut self, w: &mut W) -> ClapResult<()> {
self._build(Propagation::NextLevel);
self._build();
let p = Parser::new(self);
Help::new(w, &p, true, false).write_help()
@ -1136,8 +1143,8 @@ impl<'a, 'b> App<'a, 'b> {
pub fn generate_usage(&mut self) -> String {
// If there are global arguments, or settings we need to propgate them down to subcommands
// before parsing incase we run into a subcommand
if !self.settings.is_set(AppSettings::Propagated) {
self._build(Propagation::NextLevel);
if !self.settings.is_set(AppSettings::Built) {
self._build();
}
let mut parser = Parser::new(self);
@ -1159,7 +1166,7 @@ impl<'a, 'b> App<'a, 'b> {
/// .get_matches();
/// ```
/// [`env::args_os`]: https://doc.rust-lang.org/std/env/fn.args_os.html
pub fn get_matches(self) -> ArgMatches<'a> { self.get_matches_from(&mut env::args_os()) }
pub fn get_matches(self) -> ArgMatches { self.get_matches_from(&mut env::args_os()) }
/// Starts the parsing process, just like [`App::get_matches`] but doesn't consume the `App`
///
@ -1174,7 +1181,7 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`env::args_os`]: https://doc.rust-lang.org/std/env/fn.args_os.html
/// [`App::get_matches`]: ./struct.App.html#method.get_matches
pub fn get_matches_mut(&mut self) -> ArgMatches<'a> {
pub fn get_matches_mut(&mut self) -> ArgMatches {
self.try_get_matches_from_mut(&mut env::args_os())
.unwrap_or_else(|e| {
// Otherwise, write to stderr and exit
@ -1219,7 +1226,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`clap::Result`]: ./type.Result.html
/// [`clap::Error`]: ./struct.Error.html
/// [`kind`]: ./struct.Error.html
pub fn try_get_matches(self) -> ClapResult<ArgMatches<'a>> {
pub fn try_get_matches(self) -> ClapResult<ArgMatches> {
// Start the parsing
self.try_get_matches_from(&mut env::args_os())
}
@ -1245,7 +1252,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`clap::Result`]: ./type.Result.html
/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
/// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
pub fn get_matches_from<I, T>(mut self, itr: I) -> ArgMatches<'a>
pub fn get_matches_from<I, T>(mut self, itr: I) -> ArgMatches
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
@ -1302,7 +1309,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`Error::exit`]: ./struct.Error.html#method.exit
/// [`kind`]: ./struct.Error.html
/// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
pub fn try_get_matches_from<I, T>(mut self, itr: I) -> ClapResult<ArgMatches<'a>>
pub fn try_get_matches_from<I, T>(mut self, itr: I) -> ClapResult<ArgMatches>
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
@ -1331,7 +1338,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`App`]: ./struct.App.html
/// [`App::try_get_matches_from`]: ./struct.App.html#method.try_get_matches_from
/// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
pub fn try_get_matches_from_mut<I, T>(&mut self, itr: I) -> ClapResult<ArgMatches<'a>>
pub fn try_get_matches_from_mut<I, T>(&mut self, itr: I) -> ClapResult<ArgMatches>
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
@ -1364,9 +1371,9 @@ impl<'a, 'b> App<'a, 'b> {
// Internally used only
#[doc(hidden)]
impl<'a, 'b> App<'a, 'b> {
impl<'b> App<'b> {
#[doc(hidden)]
fn _do_parse<I, T>(&mut self, it: &mut Peekable<I>) -> ClapResult<ArgMatches<'a>>
fn _do_parse<I, T>(&mut self, it: &mut Peekable<I>) -> ClapResult<ArgMatches>
where
I: Iterator<Item = T>,
T: Into<OsString> + Clone,
@ -1376,8 +1383,8 @@ impl<'a, 'b> App<'a, 'b> {
// If there are global arguments, or settings we need to propgate them down to subcommands
// before parsing incase we run into a subcommand
if !self.settings.is_set(AppSettings::Propagated) {
self._build(Propagation::NextLevel);
if !self.settings.is_set(AppSettings::Built) {
self._build();
}
{
@ -1387,36 +1394,28 @@ impl<'a, 'b> App<'a, 'b> {
parser.get_matches_with(&mut matcher, it)?;
}
let global_arg_vec: Vec<&str> = self
let global_arg_vec: Vec<Id> = self
.args
.args
.iter()
.filter(|a| a.is_set(ArgSettings::Global))
.map(|ga| ga.name)
.map(|ga| ga.id)
.collect();
matcher.propagate_globals(&global_arg_vec);
Ok(matcher.into())
Ok(matcher.into_inner())
}
// used in clap_generate (https://github.com/clap-rs/clap_generate)
#[doc(hidden)]
pub fn _build(&mut self, prop: Propagation) {
pub fn _build(&mut self) {
debugln!("App::_build;");
// Make sure all the globally set flags apply to us as well
self.settings = self.settings | self.g_settings;
// Depending on if DeriveDisplayOrder is set or not, we need to determine when we build
// the help and version flags, otherwise help message orders get screwed up
if self.settings.is_set(AppSettings::DeriveDisplayOrder) {
self._derive_display_order();
self._create_help_and_version();
self._propagate(prop);
} else {
self._create_help_and_version();
self._propagate(prop);
self._derive_display_order();
}
self._derive_display_order();
self._create_help_and_version();
// Perform expensive debug assertions
debug_assert!({
for a in self.args.args.iter() {
@ -1429,15 +1428,15 @@ impl<'a, 'b> App<'a, 'b> {
for a in self.args.args.iter_mut() {
// Fill in the groups
if let Some(ref grps) = a.groups {
for g in grps {
for &g in grps {
let mut found = false;
if let Some(ref mut ag) = self.groups.iter_mut().find(|grp| &grp.name == g) {
ag.args.push(a.name);
if let Some(ag) = self.groups.iter_mut().find(|grp| grp.id == g) {
ag.args.push(a.id);
found = true;
}
if !found {
let mut ag = ArgGroup::with_name(g);
ag.args.push(a.name);
let mut ag = ArgGroup::_with_id(g);
ag.args.push(a.id);
self.groups.push(ag);
}
}
@ -1459,14 +1458,14 @@ impl<'a, 'b> App<'a, 'b> {
debug_assert!(self._app_debug_asserts());
self.args._build();
self.settings.set(AppSettings::Propagated);
self.settings.set(AppSettings::Built);
}
// Perform some expensive assertions on the Parser itself
fn _app_debug_asserts(&mut self) -> bool {
debugln!("App::_app_debug_asserts;");
for name in self.args.args.iter().map(|x| x.name) {
if self.args.args.iter().filter(|x| x.name == name).count() > 1 {
for name in self.args.args.iter().map(|x| x.id) {
if self.args.args.iter().filter(|x| x.id == name).count() > 1 {
panic!(format!(
"Arg names must be unique, found {} more than once",
name
@ -1490,42 +1489,57 @@ impl<'a, 'b> App<'a, 'b> {
true
}
// @TODO @v3-alpha @perf: should only propagate globals to subcmd we find, or for help
pub fn _propagate(&mut self, prop: Propagation) {
debugln!("App::_propagate:{}", self.name);
for sc in &mut self.subcommands {
// We have to create a new scope in order to tell rustc the borrow of `sc` is
// done and to recursively call this method
{
let vsc = self.settings.is_set(AppSettings::VersionlessSubcommands);
let gv = self.settings.is_set(AppSettings::GlobalVersion);
if vsc {
sc.set(AppSettings::DisableVersion);
}
if gv && sc.version.is_none() && self.version.is_some() {
sc.set(AppSettings::GlobalVersion);
sc.version = Some(self.version.unwrap());
}
sc.settings = sc.settings | self.g_settings;
sc.g_settings = sc.g_settings | self.g_settings;
sc.term_w = self.term_w;
sc.max_w = self.max_w;
}
{
for a in self
.args
.args
.iter()
.filter(|a| a.is_set(ArgSettings::Global))
macro_rules! propagate_subcmd {
($_self:ident, $sc:expr) => {{
// We have to create a new scope in order to tell rustc the borrow of `sc` is
// done and to recursively call this method
{
sc.args.push(a.clone());
let vsc = $_self.settings.is_set(AppSettings::VersionlessSubcommands);
let gv = $_self.settings.is_set(AppSettings::GlobalVersion);
if vsc {
$sc.set(AppSettings::DisableVersion);
}
if gv && $sc.version.is_none() && $_self.version.is_some() {
$sc.set(AppSettings::GlobalVersion);
$sc.version = Some($_self.version.unwrap());
}
$sc.settings = $sc.settings | $_self.g_settings;
$sc.g_settings = $sc.g_settings | $_self.g_settings;
$sc.term_w = $_self.term_w;
$sc.max_w = $_self.max_w;
}
}
// @TODO @deadcode @perf @v3-alpha: Currently we're not propagating
if prop == Propagation::Full {
sc._build(Propagation::Full);
}
{
for a in $_self
.args
.args
.iter()
.filter(|a| a.is_set(ArgSettings::Global))
{
$sc.args.push(a.clone());
}
}
}}
}
debugln!("App::_propagate:{}", self.name);
match prop {
Propagation::NextLevel | Propagation::Full => {
for sc in &mut self.subcommands {
propagate_subcmd!(self, sc);
if prop == Propagation::Full {
sc._propagate(prop);
}
}
},
Propagation::To(id) => {
let mut sc = self.subcommands.iter_mut().find(|sc| sc.id == id).expect(INTERNAL_ERROR_MSG);
propagate_subcmd!(self, sc);
},
Propagation::None => {
return;
},
}
}
@ -1535,7 +1549,7 @@ impl<'a, 'b> App<'a, 'b> {
.args
.args
.iter()
.any(|x| x.long == Some("help") || x.name == "help"))
.any(|x| x.long == Some("help") || x.id == HELP_HASH))
{
debugln!("App::_create_help_and_version: Building --help");
let mut help = Arg::with_name("help")
@ -1551,7 +1565,7 @@ impl<'a, 'b> App<'a, 'b> {
.args
.args
.iter()
.any(|x| x.long == Some("version") || x.name == "version")
.any(|x| x.long == Some("version") || x.id == VERSION_HASH)
|| self.is_set(AppSettings::DisableVersion))
{
debugln!("App::_create_help_and_version: Building --version");
@ -1566,7 +1580,7 @@ impl<'a, 'b> App<'a, 'b> {
}
if self.has_subcommands()
&& !self.is_set(AppSettings::DisableHelpSubcommand)
&& !subcommands!(self).any(|s| s.name == "help")
&& !subcommands!(self).any(|s| s.id == HELP_HASH)
{
debugln!("App::_create_help_and_version: Building help");
self.subcommands.push(
@ -1589,7 +1603,7 @@ impl<'a, 'b> App<'a, 'b> {
{
a.disp_ord = i;
}
for (i, sc) in &mut subcommands_mut!(self)
for (i, mut sc) in &mut subcommands_mut!(self)
.enumerate()
.filter(|&(_, ref sc)| sc.disp_ord == 999)
{
@ -1626,7 +1640,7 @@ impl<'a, 'b> App<'a, 'b> {
if let Some(idx) = a.index {
// No index conflicts
assert!(
positionals!(self).fold(0, |acc, p| if p.index == Some(idx as u64) {
positionals!(self).fold(0, |acc, p| if p.index == Some(idx) {
acc + 1
} else {
acc
@ -1665,7 +1679,7 @@ impl<'a, 'b> App<'a, 'b> {
#[doc(hidden)]
pub fn _build_bin_names(&mut self) {
debugln!("App::_build_bin_names;");
for sc in subcommands_mut!(self) {
for mut sc in subcommands_mut!(self) {
debug!("Parser::build_bin_names:iter: bin_name set...");
if sc.bin_name.is_none() {
sdebugln!("No");
@ -1713,11 +1727,11 @@ impl<'a, 'b> App<'a, 'b> {
}
}
pub(crate) fn format_group(&self, g: &str) -> String {
pub(crate) fn format_group(&self, g: Id) -> String {
let g_string = self
.unroll_args_in_group(g)
.iter()
.filter_map(|x| self.find(x))
.filter_map(|&x| self.find(x))
.map(|x| {
if x.index.is_some() {
x.name.to_owned()
@ -1733,9 +1747,9 @@ impl<'a, 'b> App<'a, 'b> {
// Internal Query Methods
#[doc(hidden)]
impl<'a, 'b> App<'a, 'b> {
pub(crate) fn find(&self, name: &str) -> Option<&Arg<'a, 'b>> {
self.args.args.iter().find(|a| a.name == name)
impl<'b> App<'b> {
pub(crate) fn find(&self, arg_id: Id) -> Option<&Arg<'b>> {
self.args.args.iter().find(|a| a.id == arg_id)
}
// Should we color the output? None=determined by output location, true=yes, false=no
@ -1756,14 +1770,14 @@ impl<'a, 'b> App<'a, 'b> {
}
pub(crate) fn contains_long(&self, l: &str) -> bool {
if !self.is_set(AppSettings::Propagated) {
if !self.is_set(AppSettings::Built) {
panic!("If App::_build hasn't been called, manually search through Arg longs");
}
self.args.contains_long(l)
}
pub(crate) fn contains_short(&self, s: char) -> bool {
if !self.is_set(AppSettings::Propagated) {
if !self.is_set(AppSettings::Built) {
panic!("If App::_build hasn't been called, manually search through Arg shorts");
}
self.args.contains_short(s)
@ -1805,20 +1819,20 @@ impl<'a, 'b> App<'a, 'b> {
.any(|sc| !sc.is_set(AppSettings::Hidden))
}
pub(crate) fn unroll_args_in_group(&self, group: &'a str) -> Vec<&'a str> {
pub(crate) fn unroll_args_in_group(&self, group: Id) -> Vec<Id> {
let mut g_vec = vec![group];
let mut args = vec![];
while let Some(ref g) = g_vec.pop() {
for n in self
for &n in self
.groups
.iter()
.find(|grp| &grp.name == g)
.find(|grp| &grp.id == g)
.expect(INTERNAL_ERROR_MSG)
.args
.iter()
{
if !args.contains(n) {
if !args.contains(&n) {
if self.find(n).is_some() {
args.push(n)
} else {
@ -1831,11 +1845,7 @@ impl<'a, 'b> App<'a, 'b> {
args
}
pub(crate) fn unroll_requirements_for_arg(
&self,
arg: &str,
matcher: &ArgMatcher<'a>,
) -> Vec<&'a str> {
pub(crate) fn unroll_requirements_for_arg(&self, arg: Id, matcher: &ArgMatcher) -> Vec<Id> {
let requires_if_or_not = |&(val, req_arg)| {
if let Some(v) = val {
if matcher
@ -1855,13 +1865,13 @@ impl<'a, 'b> App<'a, 'b> {
let mut r_vec = vec![arg];
let mut args = vec![];
while let Some(ref a) = r_vec.pop() {
while let Some(a) = r_vec.pop() {
if let Some(arg) = self.find(a) {
if let Some(ref reqs) = arg.requires {
for r in reqs.iter().filter_map(requires_if_or_not) {
if let Some(req) = self.find(r) {
if req.requires.is_some() {
r_vec.push(req.name)
r_vec.push(req.id)
}
}
args.push(r);
@ -1875,7 +1885,7 @@ impl<'a, 'b> App<'a, 'b> {
}
#[cfg(feature = "yaml")]
impl<'a> From<&'a Yaml> for App<'a, 'a> {
impl<'a> From<&'a Yaml> for App<'a> {
fn from(mut yaml: &'a Yaml) -> Self {
// We WANT this to panic on error...so expect() is good.
let mut is_sc = None;
@ -2017,6 +2027,6 @@ impl<'a> From<&'a Yaml> for App<'a, 'a> {
}
}
impl<'n, 'e> fmt::Display for App<'n, 'e> {
impl<'e> fmt::Display for App<'e> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.name) }
}

View file

@ -41,7 +41,7 @@ bitflags! {
const ALLOW_MISSING_POS = 1 << 32;
const TRAILING_VALUES = 1 << 33;
const VALID_NEG_NUM_FOUND = 1 << 34;
const PROPAGATED = 1 << 35;
const BUILT = 1 << 35;
const VALID_ARG_FOUND = 1 << 36;
const INFER_SUBCOMMANDS = 1 << 37;
const CONTAINS_LAST = 1 << 38;
@ -103,7 +103,7 @@ impl AppFlags {
WaitOnError => Flags::WAIT_ON_ERROR,
TrailingValues => Flags::TRAILING_VALUES,
ValidNegNumFound => Flags::VALID_NEG_NUM_FOUND,
Propagated => Flags::PROPAGATED,
Built => Flags::BUILT,
ValidArgFound => Flags::VALID_ARG_FOUND,
InferSubcommands => Flags::INFER_SUBCOMMANDS,
AllArgsOverrideSelf => Flags::ARGS_OVERRIDE_SELF,
@ -934,7 +934,7 @@ pub enum AppSettings {
ValidNegNumFound,
#[doc(hidden)]
Propagated,
Built,
#[doc(hidden)]
ValidArgFound,
@ -979,7 +979,7 @@ impl FromStr for AppSettings {
"waitonerror" => Ok(AppSettings::WaitOnError),
"validnegnumfound" => Ok(AppSettings::ValidNegNumFound),
"validargfound" => Ok(AppSettings::ValidArgFound),
"propagated" => Ok(AppSettings::Propagated),
"built" => Ok(AppSettings::Built),
"trailingvalues" => Ok(AppSettings::TrailingValues),
_ => Err("unknown AppSetting, cannot convert from str".to_owned()),
}
@ -1117,8 +1117,8 @@ mod test {
AppSettings::ValidArgFound
);
assert_eq!(
"propagated".parse::<AppSettings>().unwrap(),
AppSettings::Propagated
"built".parse::<AppSettings>().unwrap(),
AppSettings::Built
);
assert_eq!(
"trailingvalues".parse::<AppSettings>().unwrap(),

View file

@ -9,24 +9,26 @@ use std::cmp::{Ord, Ordering};
use std::env;
use std::ffi::{OsStr, OsString};
use std::fmt::{self, Display, Formatter};
use std::hash::{Hash, Hasher};
#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
use std::os::unix::ffi::OsStrExt;
use std::rc::Rc;
use std::str;
// Third Party
use util::VecMap;
use crate::util::VecMap;
#[cfg(feature = "yaml")]
use yaml_rust;
// Internal
use build::UsageParser;
use INTERNAL_ERROR_MSG;
use crate::build::UsageParser;
use crate::util::Key;
use crate::INTERNAL_ERROR_MSG;
type Validator = Rc<Fn(String) -> Result<(), String>>;
type ValidatorOs = Rc<Fn(&OsStr) -> Result<(), String>>;
type Id = u64;
/// The abstract representation of a command line argument. Used to set all the options and
/// relationships that define a valid argument for the program.
///
@ -51,42 +53,41 @@ type ValidatorOs = Rc<Fn(&OsStr) -> Result<(), String>>;
/// [`Arg`]: ./struct.Arg.html
#[allow(missing_debug_implementations)]
#[derive(Default, Clone)]
pub struct Arg<'a, 'b>
where
'a: 'b,
{
pub struct Arg<'help> {
#[doc(hidden)]
pub name: &'a str,
pub id: Id,
#[doc(hidden)]
pub help: Option<&'b str>,
pub name: &'help str,
#[doc(hidden)]
pub long_help: Option<&'b str>,
pub help: Option<&'help str>,
#[doc(hidden)]
pub blacklist: Option<Vec<&'a str>>,
pub long_help: Option<&'help str>,
#[doc(hidden)]
pub blacklist: Option<Vec<Id>>,
#[doc(hidden)]
pub settings: ArgFlags,
#[doc(hidden)]
pub r_unless: Option<Vec<&'a str>>,
pub r_unless: Option<Vec<Id>>,
#[doc(hidden)]
pub overrides: Option<Vec<&'a str>>,
pub overrides: Option<Vec<Id>>,
#[doc(hidden)]
pub groups: Option<Vec<&'a str>>,
pub groups: Option<Vec<Id>>,
#[doc(hidden)]
pub requires: Option<Vec<(Option<&'b str>, &'a str)>>,
pub requires: Option<Vec<(Option<&'help str>, Id)>>,
#[doc(hidden)]
pub short: Option<char>,
#[doc(hidden)]
pub long: Option<&'b str>,
pub long: Option<&'help str>,
#[doc(hidden)]
pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
pub aliases: Option<Vec<(&'help str, bool)>>, // (name, visible)
#[doc(hidden)]
pub disp_ord: usize,
#[doc(hidden)]
pub unified_ord: usize,
#[doc(hidden)]
pub possible_vals: Option<Vec<&'b str>>,
pub possible_vals: Option<Vec<&'help str>>,
#[doc(hidden)]
pub val_names: Option<VecMap<&'b str>>,
pub val_names: Option<VecMap<&'help str>>,
#[doc(hidden)]
pub num_vals: Option<u64>,
#[doc(hidden)]
@ -100,22 +101,31 @@ where
#[doc(hidden)]
pub val_delim: Option<char>,
#[doc(hidden)]
pub default_val: Option<&'b OsStr>,
pub default_val: Option<&'help OsStr>,
#[doc(hidden)]
pub default_vals_ifs: Option<VecMap<(&'a str, Option<&'b OsStr>, &'b OsStr)>>,
pub default_vals_ifs: Option<VecMap<(Id, Option<&'help OsStr>, &'help OsStr)>>,
#[doc(hidden)]
pub env: Option<(&'a OsStr, Option<OsString>)>,
pub env: Option<(&'help OsStr, Option<OsString>)>,
#[doc(hidden)]
pub terminator: Option<&'b str>,
pub terminator: Option<&'help str>,
#[doc(hidden)]
pub index: Option<u64>,
#[doc(hidden)]
pub r_ifs: Option<Vec<(&'a str, &'b str)>>,
pub r_ifs: Option<Vec<(Id, &'help str)>>,
#[doc(hidden)]
pub help_heading: Option<&'a str>,
pub help_heading: Option<&'help str>,
}
impl<'a, 'b> Arg<'a, 'b> {
impl<'help> Arg<'help> {
/// @TODO @p2 @docs @v3-beta1: Write Docs
pub fn new<T: Key>(t: T) -> Self {
Arg {
id: t.key(),
disp_ord: 999,
unified_ord: 999,
..Default::default()
}
}
/// Creates a new instance of [`Arg`] using a unique string name. The name will be used to get
/// information about whether or not the argument was used at runtime, get values, set
/// relationships with other args, etc..
@ -133,8 +143,9 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
/// [`Arg`]: ./struct.Arg.html
pub fn with_name(n: &'a str) -> Self {
pub fn with_name(n: &'help str) -> Self {
Arg {
id: n.key(),
name: n,
disp_ord: 999,
unified_ord: 999,
@ -293,7 +304,7 @@ impl<'a, 'b> Arg<'a, 'b> {
///
/// assert!(m.is_present("cfg"));
/// ```
pub fn long(mut self, l: &'b str) -> Self {
pub fn long(mut self, l: &'help str) -> Self {
self.long = Some(l.trim_left_matches(|c| c == '-'));
self
}
@ -319,7 +330,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert_eq!(m.value_of("test"), Some("cool"));
/// ```
/// [`Arg`]: ./struct.Arg.html
pub fn alias<S: Into<&'b str>>(mut self, name: S) -> Self {
pub fn alias<S: Into<&'help str>>(mut self, name: S) -> Self {
if let Some(ref mut als) = self.aliases {
als.push((name.into(), false));
} else {
@ -349,13 +360,13 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert!(m.is_present("test"));
/// ```
/// [`Arg`]: ./struct.Arg.html
pub fn aliases(mut self, names: &[&'b str]) -> Self {
pub fn aliases(mut self, names: &[&'help str]) -> Self {
if let Some(ref mut als) = self.aliases {
for n in names {
als.push((n, false));
}
} else {
self.aliases = Some(names.iter().map(|n| (*n, false)).collect::<Vec<_>>());
self.aliases = Some(names.iter().map(|&x| (x, false)).collect());
}
self
}
@ -380,7 +391,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg`]: ./struct.Arg.html
/// [`App::alias`]: ./struct.Arg.html#method.alias
pub fn visible_alias<S: Into<&'b str>>(mut self, name: S) -> Self {
pub fn visible_alias<S: Into<&'help str>>(mut self, name: S) -> Self {
if let Some(ref mut als) = self.aliases {
als.push((name.into(), true));
} else {
@ -407,7 +418,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg`]: ./struct.Arg.html
/// [`App::aliases`]: ./struct.Arg.html#method.aliases
pub fn visible_aliases(mut self, names: &[&'b str]) -> Self {
pub fn visible_aliases(mut self, names: &[&'help str]) -> Self {
if let Some(ref mut als) = self.aliases {
for n in names {
als.push((n, true));
@ -468,7 +479,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// -V, --version Prints version information
/// ```
/// [`Arg::long_help`]: ./struct.Arg.html#method.long_help
pub fn help(mut self, h: &'b str) -> Self {
pub fn help(mut self, h: &'help str) -> Self {
self.help = Some(h);
self
}
@ -539,7 +550,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// Prints version information
/// ```
/// [`Arg::help`]: ./struct.Arg.html#method.help
pub fn long_help(mut self, h: &'b str) -> Self {
pub fn long_help(mut self, h: &'help str) -> Self {
self.long_help = Some(h);
self
}
@ -600,7 +611,8 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::required_unless`]: ./struct.Arg.html#method.required_unless
/// [`Arg::required`]: ./struct.Arg.html#method.required
/// [`Arg::required_unless(name)`]: ./struct.Arg.html#method.required_unless
pub fn required_unless(mut self, name: &'a str) -> Self {
pub fn required_unless<T: Key>(mut self, arg_id: T) -> Self {
let name = arg_id.key();
if let Some(ref mut vec) = self.r_unless {
vec.push(name);
} else {
@ -672,13 +684,13 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg::required_unless_one`]: ./struct.Arg.html#method.required_unless_one
/// [`Arg::required_unless_all(names)`]: ./struct.Arg.html#method.required_unless_all
pub fn required_unless_all(mut self, names: &[&'a str]) -> Self {
pub fn required_unless_all(mut self, names: &[&str]) -> Self {
if let Some(ref mut vec) = self.r_unless {
for s in names {
vec.push(s);
vec.push(s.key());
}
} else {
self.r_unless = Some(names.to_vec());
self.r_unless = Some(names.iter().map(Key::key).collect());
}
self.setting(ArgSettings::RequiredUnlessAll)
}
@ -747,13 +759,13 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [required]: ./struct.Arg.html#method.required
/// [`Arg::required_unless_one(names)`]: ./struct.Arg.html#method.required_unless_one
/// [`Arg::required_unless_all`]: ./struct.Arg.html#method.required_unless_all
pub fn required_unless_one(mut self, names: &[&'a str]) -> Self {
pub fn required_unless_one(mut self, names: &[&str]) -> Self {
if let Some(ref mut vec) = self.r_unless {
for s in names {
vec.push(s);
vec.push(s.key());
}
} else {
self.r_unless = Some(names.to_vec());
self.r_unless = Some(names.iter().map(Key::key).collect());
}
self
}
@ -795,7 +807,8 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert!(res.is_err());
/// assert_eq!(res.unwrap_err().kind, ErrorKind::ArgumentConflict);
/// ```
pub fn conflicts_with(mut self, name: &'a str) -> Self {
pub fn conflicts_with<T: Key>(mut self, arg_id: T) -> Self {
let name = arg_id.key();
if let Some(ref mut vec) = self.blacklist {
vec.push(name);
} else {
@ -845,13 +858,13 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert_eq!(res.unwrap_err().kind, ErrorKind::ArgumentConflict);
/// ```
/// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with
pub fn conflicts_with_all(mut self, names: &[&'a str]) -> Self {
pub fn conflicts_with_all(mut self, names: &[&str]) -> Self {
if let Some(ref mut vec) = self.blacklist {
for s in names {
vec.push(s);
vec.push(s.key());
}
} else {
self.blacklist = Some(names.to_vec());
self.blacklist = Some(names.iter().map(Key::key).collect());
}
self
}
@ -957,7 +970,8 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Multiple*`]: ./enum.ArgSettings.html#variant.MultipleValues
/// [`UseValueDelimiter`]: ./enum.ArgSettings.html#variant.UseValueDelimiter
pub fn overrides_with(mut self, name: &'a str) -> Self {
pub fn overrides_with<T: Key>(mut self, arg_id: T) -> Self {
let name = arg_id.key();
if let Some(ref mut vec) = self.overrides {
vec.push(name);
} else {
@ -993,13 +1007,13 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert!(!m.is_present("debug"));
/// assert!(!m.is_present("flag"));
/// ```
pub fn overrides_with_all(mut self, names: &[&'a str]) -> Self {
pub fn overrides_with_all<T: Key>(mut self, names: &[T]) -> Self {
if let Some(ref mut vec) = self.overrides {
for s in names {
vec.push(s);
vec.push(s.key());
}
} else {
self.overrides = Some(names.to_vec());
self.overrides = Some(names.iter().map(Key::key).collect());
}
self
}
@ -1059,7 +1073,8 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires(mut self, name: &'a str) -> Self {
pub fn requires<T: Key>(mut self, arg_id: T) -> Self {
let name = arg_id.key();
if let Some(ref mut vec) = self.requires {
vec.push((None, name));
} else {
@ -1129,7 +1144,8 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires_if(mut self, val: &'b str, arg: &'a str) -> Self {
pub fn requires_if<T: Key>(mut self, val: &'help str, arg_id: T) -> Self {
let arg = arg_id.key();
if let Some(ref mut vec) = self.requires {
vec.push((Some(val), arg));
} else {
@ -1189,15 +1205,15 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires_ifs(mut self, ifs: &[(&'b str, &'a str)]) -> Self {
pub fn requires_ifs<T: Key>(mut self, ifs: &[(&'help str, T)]) -> Self {
if let Some(ref mut vec) = self.requires {
for &(val, arg) in ifs {
vec.push((Some(val), arg));
for (val, arg) in ifs {
vec.push((Some(val), arg.key()));
}
} else {
let mut vec = vec![];
for &(val, arg) in ifs {
vec.push((Some(val), arg));
for (val, arg) in ifs {
vec.push((Some(*val), arg.key()));
}
self.requires = Some(vec);
}
@ -1267,7 +1283,8 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [required]: ./struct.Arg.html#method.required
pub fn required_if(mut self, arg: &'a str, val: &'b str) -> Self {
pub fn required_if<T: Key>(mut self, arg_id: T, val: &'help str) -> Self {
let arg = arg_id.key();
if let Some(ref mut vec) = self.r_ifs {
vec.push((arg, val));
} else {
@ -1356,15 +1373,15 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [required]: ./struct.Arg.html#method.required
pub fn required_ifs(mut self, ifs: &[(&'a str, &'b str)]) -> Self {
pub fn required_ifs<T: Key>(mut self, ifs: &[(T, &'help str)]) -> Self {
if let Some(ref mut vec) = self.r_ifs {
for r_if in ifs {
vec.push((r_if.0, r_if.1));
vec.push((r_if.0.key(), r_if.1));
}
} else {
let mut vec = vec![];
for r_if in ifs {
vec.push((r_if.0, r_if.1));
vec.push((r_if.0.key(), r_if.1));
}
self.r_ifs = Some(vec);
}
@ -1433,15 +1450,15 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with
/// [`Arg::requires_all(&[arg, arg2])`]: ./struct.Arg.html#method.requires_all
pub fn requires_all(mut self, names: &[&'a str]) -> Self {
pub fn requires_all<T: Key>(mut self, names: &[T]) -> Self {
if let Some(ref mut vec) = self.requires {
for s in names {
vec.push((None, s));
vec.push((None, s.key()));
}
} else {
let mut vec = vec![];
for s in names {
vec.push((None, *s));
vec.push((None, s.key()));
}
self.requires = Some(vec);
}
@ -1545,7 +1562,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`min_values`]: ./struct.Arg.html#method.min_values
/// [`number_of_values`]: ./struct.Arg.html#method.number_of_values
/// [`max_values`]: ./struct.Arg.html#method.max_values
pub fn value_terminator(mut self, term: &'b str) -> Self {
pub fn value_terminator(mut self, term: &'help str) -> Self {
self.setb(ArgSettings::TakesValue);
self.terminator = Some(term);
self
@ -1598,7 +1615,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [options]: ./struct.Arg.html#method.takes_value
/// [positional arguments]: ./struct.Arg.html#method.index
pub fn possible_values(mut self, names: &[&'b str]) -> Self {
pub fn possible_values(mut self, names: &[&'help str]) -> Self {
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vec) = self.possible_vals {
for s in names {
@ -1663,7 +1680,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [options]: ./struct.Arg.html#method.takes_value
/// [positional arguments]: ./struct.Arg.html#method.index
pub fn possible_value(mut self, name: &'b str) -> Self {
pub fn possible_value(mut self, name: &'help str) -> Self {
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vec) = self.possible_vals {
vec.push(name);
@ -1703,7 +1720,8 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert!(m.is_present("mode"));
/// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html
pub fn group(mut self, name: &'a str) -> Self {
pub fn group<T: Key>(mut self, group_id: T) -> Self {
let name = group_id.key();
if let Some(ref mut vec) = self.groups {
vec.push(name);
} else {
@ -1743,13 +1761,13 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert!(m.is_present("verbosity"));
/// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html
pub fn groups(mut self, names: &[&'a str]) -> Self {
pub fn groups<T: Key>(mut self, group_ids: &[T]) -> Self {
if let Some(ref mut vec) = self.groups {
for s in names {
vec.push(s);
for s in group_ids {
vec.push(s.key());
}
} else {
self.groups = Some(names.to_vec());
self.groups = Some(group_ids.iter().map(Key::key).collect());
}
self
}
@ -2100,7 +2118,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::number_of_values`]: ./struct.Arg.html#method.number_of_values
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn value_names(mut self, names: &[&'b str]) -> Self {
pub fn value_names(mut self, names: &[&'help str]) -> Self {
self.setb(ArgSettings::TakesValue);
if self.is_set(ArgSettings::ValueDelimiterNotSet) {
self.unsetb(ArgSettings::ValueDelimiterNotSet);
@ -2168,7 +2186,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [option]: ./struct.Arg.html#method.takes_value
/// [positional]: ./struct.Arg.html#method.index
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
pub fn value_name(mut self, name: &'b str) -> Self {
pub fn value_name(mut self, name: &'help str) -> Self {
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vals) = self.val_names {
let l = vals.len();
@ -2244,7 +2262,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
/// [`ArgMatches::is_present`]: ./struct.ArgMatches.html#method.is_present
/// [`Arg::default_value_if`]: ./struct.Arg.html#method.default_value_if
pub fn default_value(self, val: &'a str) -> Self {
pub fn default_value(self, val: &'help str) -> Self {
self.default_value_os(OsStr::from_bytes(val.as_bytes()))
}
@ -2252,7 +2270,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// only using [`OsStr`]s instead.
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
pub fn default_value_os(mut self, val: &'a OsStr) -> Self {
pub fn default_value_os(mut self, val: &'help OsStr) -> Self {
self.setb(ArgSettings::TakesValue);
self.default_val = Some(val);
self
@ -2354,9 +2372,14 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
pub fn default_value_if(self, arg: &'a str, val: Option<&'b str>, default: &'b str) -> Self {
pub fn default_value_if<T: Key>(
self,
arg_id: T,
val: Option<&'help str>,
default: &'help str,
) -> Self {
self.default_value_if_os(
arg,
arg_id,
val.map(str::as_bytes).map(OsStr::from_bytes),
OsStr::from_bytes(default.as_bytes()),
)
@ -2366,12 +2389,13 @@ impl<'a, 'b> Arg<'a, 'b> {
/// only using [`OsStr`]s instead.
/// [`Arg::default_value_if`]: ./struct.Arg.html#method.default_value_if
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
pub fn default_value_if_os(
pub fn default_value_if_os<T: Key>(
mut self,
arg: &'a str,
val: Option<&'b OsStr>,
default: &'b OsStr,
arg_id: T,
val: Option<&'help OsStr>,
default: &'help OsStr,
) -> Self {
let arg = arg_id.key();
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vm) = self.default_vals_ifs {
let l = vm.len();
@ -2468,8 +2492,11 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
pub fn default_value_ifs(mut self, ifs: &[(&'a str, Option<&'b str>, &'b str)]) -> Self {
for &(arg, val, default) in ifs {
pub fn default_value_ifs<T: Key>(
mut self,
ifs: &[(T, Option<&'help str>, &'help str)],
) -> Self {
for (arg, val, default) in ifs {
self = self.default_value_if_os(
arg,
val.map(str::as_bytes).map(OsStr::from_bytes),
@ -2484,9 +2511,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::default_value_ifs`]: ./struct.Arg.html#method.default_value_ifs
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
#[cfg_attr(feature = "lints", allow(explicit_counter_loop))]
pub fn default_value_ifs_os(mut self, ifs: &[(&'a str, Option<&'b OsStr>, &'b OsStr)]) -> Self {
for &(arg, val, default) in ifs {
self = self.default_value_if_os(arg, val, default);
pub fn default_value_ifs_os<T: Key>(
mut self,
ifs: &[(T, Option<&'help OsStr>, &'help OsStr)],
) -> Self {
for (arg, val, default) in ifs {
self = self.default_value_if_os(arg.key(), *val, default);
}
self
}
@ -2590,12 +2620,12 @@ impl<'a, 'b> Arg<'a, 'b> {
///
/// assert_eq!(m.values_of("flag").unwrap().collect::<Vec<_>>(), vec!["env1", "env2"]);
/// ```
pub fn env(self, name: &'a str) -> Self { self.env_os(OsStr::new(name)) }
pub fn env(self, name: &'help str) -> Self { self.env_os(OsStr::new(name)) }
/// Specifies that if the value is not passed in as an argument, that it should be retrieved
/// from the environment if available in the exact same manner as [`Arg::env`] only using
/// [`OsStr`]s instead.
pub fn env_os(mut self, name: &'a OsStr) -> Self {
pub fn env_os(mut self, name: &'help OsStr) -> Self {
self.setb(ArgSettings::TakesValue);
self.env = Some((name, env::var_os(name)));
@ -3962,7 +3992,7 @@ impl<'a, 'b> Arg<'a, 'b> {
}
/// Set a custom heading for this arg to be printed under
pub fn help_heading(mut self, s: Option<&'a str>) -> Self {
pub fn help_heading(mut self, s: Option<&'help str>) -> Self {
self.help_heading = s;
self
}
@ -4055,19 +4085,19 @@ impl<'a, 'b> Arg<'a, 'b> {
}
}
impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for Arg<'a, 'b> {
fn from(a: &'z Arg<'a, 'b>) -> Self { a.clone() }
impl<'help, 'z> From<&'z Arg<'help>> for Arg<'help> {
fn from(a: &'z Arg<'help>) -> Self { a.clone() }
}
impl<'a, 'b> From<&'a str> for Arg<'a, 'b> {
fn from(s: &'a str) -> Self { UsageParser::from_usage(s).parse() }
impl<'help> From<&'help str> for Arg<'help> {
fn from(s: &'help str) -> Self { UsageParser::from_usage(s).parse() }
}
impl<'n, 'e> PartialEq for Arg<'n, 'e> {
fn eq(&self, other: &Arg<'n, 'e>) -> bool { self.name == other.name }
impl<'help> PartialEq for Arg<'help> {
fn eq(&self, other: &Arg<'help>) -> bool { self.name == other.name }
}
impl<'n, 'e> Display for Arg<'n, 'e> {
impl<'help> Display for Arg<'help> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.index.is_some() || (self.long.is_none() && self.short.is_none()) {
// Positional
@ -4165,25 +4195,21 @@ impl<'n, 'e> Display for Arg<'n, 'e> {
}
}
impl<'n, 'e> PartialOrd for Arg<'n, 'e> {
impl<'help> PartialOrd for Arg<'help> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl<'n, 'e> Ord for Arg<'n, 'e> {
impl<'help> Ord for Arg<'help> {
fn cmp(&self, other: &Arg) -> Ordering { self.name.cmp(&other.name) }
}
impl<'n, 'e> Eq for Arg<'n, 'e> {}
impl<'help> Eq for Arg<'help> {}
impl<'n, 'e> Hash for Arg<'n, 'e> {
fn hash<H: Hasher>(&self, state: &mut H) { self.name.hash(state); }
}
impl<'n, 'e> fmt::Debug for Arg<'n, 'e> {
impl<'help> fmt::Debug for Arg<'help> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(
f,
"Arg {{ name: {:?}, help: {:?}, long_help: {:?}, conflicts_with: {:?}, \
"Arg {{ id: {:X?}, name: {:?}, help: {:?}, long_help: {:?}, conflicts_with: {:?}, \
settings: {:?}, required_unless: {:?}, overrides_with: {:?}, groups: {:?}, \
requires: {:?}, requires_ifs: {:?}, short: {:?}, index: {:?}, long: {:?}, \
aliases: {:?}, possible_values: {:?}, value_names: {:?}, number_of_values: {:?}, \
@ -4191,6 +4217,7 @@ impl<'n, 'e> fmt::Debug for Arg<'n, 'e> {
value_terminator: {:?}, display_order: {:?}, env: {:?}, unified_ord: {:?}, \
default_value: {:?}, validator: {}, validator_os: {} \
}}",
self.id,
self.name,
self.help,
self.long_help,
@ -4227,8 +4254,8 @@ impl<'n, 'e> fmt::Debug for Arg<'n, 'e> {
#[cfg(test)]
mod test {
use super::Arg;
use build::ArgSettings;
use util::VecMap;
use crate::build::ArgSettings;
use crate::util::VecMap;
#[test]
fn flag_display() {

View file

@ -37,7 +37,7 @@ impl ArgFlags {
pub fn new() -> Self { ArgFlags::default() }
// @TODO @p6 @internal: Reorder alphabetically
impl_settings!{ArgSettings,
impl_settings! {ArgSettings,
Required => Flags::REQUIRED,
MultipleOccurrences => Flags::MULTIPLE_OCC,
MultipleValues => Flags::MULTIPLE_VALS,

View file

@ -5,6 +5,11 @@ use std::fmt::{Debug, Formatter, Result};
#[cfg(feature = "yaml")]
use yaml_rust;
// Internal
use crate::util::Key;
type Id = u64;
/// `ArgGroup`s are a family of related [arguments] and way for you to express, "Any of these
/// arguments". By placing arguments in a logical group, you can create easier requirement and
/// exclusion rules instead of having to list each argument individually, or when you want a rule
@ -77,21 +82,32 @@ use yaml_rust;
/// [requirement]: ./struct.Arg.html#method.requires
#[derive(Default)]
pub struct ArgGroup<'a> {
#[doc(hidden)]
pub id: Id,
#[doc(hidden)]
pub name: &'a str,
#[doc(hidden)]
pub args: Vec<&'a str>,
pub args: Vec<Id>,
#[doc(hidden)]
pub required: bool,
#[doc(hidden)]
pub requires: Option<Vec<&'a str>>,
pub requires: Option<Vec<Id>>,
#[doc(hidden)]
pub conflicts: Option<Vec<&'a str>>,
pub conflicts: Option<Vec<Id>>,
#[doc(hidden)]
pub multiple: bool,
}
impl<'a> ArgGroup<'a> {
#[doc(hidden)]
pub fn _with_id(id: Id) -> Self {
ArgGroup {
id,
..ArgGroup::default()
}
}
/// @TODO @p2 @docs @v3-beta1: Write Docs
pub fn new<T: Key>(id: T) -> Self { ArgGroup::_with_id(id.key()) }
/// Creates a new instance of `ArgGroup` using a unique string name. The name will be used to
/// get values from the group or refer to the group inside of conflict and requirement rules.
///
@ -104,12 +120,9 @@ impl<'a> ArgGroup<'a> {
/// ```
pub fn with_name(n: &'a str) -> Self {
ArgGroup {
id: n.key(),
name: n,
required: false,
args: vec![],
requires: None,
conflicts: None,
multiple: false,
..ArgGroup::default()
}
}
@ -153,13 +166,8 @@ impl<'a> ArgGroup<'a> {
/// ```
/// [argument]: ./struct.Arg.html
#[cfg_attr(feature = "lints", allow(should_assert_eq))]
pub fn arg(mut self, n: &'a str) -> Self {
assert!(
self.name != n,
"ArgGroup '{}' can not have same name as arg inside it",
&*self.name
);
self.args.push(n);
pub fn arg<T: Key>(mut self, arg_id: T) -> Self {
self.args.push(arg_id.key());
self
}
@ -183,7 +191,7 @@ impl<'a> ArgGroup<'a> {
/// assert!(m.is_present("flag"));
/// ```
/// [arguments]: ./struct.Arg.html
pub fn args(mut self, ns: &[&'a str]) -> Self {
pub fn args<T: Key>(mut self, ns: &[T]) -> Self {
for n in ns {
self = self.arg(n);
}
@ -304,11 +312,12 @@ impl<'a> ArgGroup<'a> {
/// ```
/// [required group]: ./struct.ArgGroup.html#method.required
/// [argument requirement rules]: ./struct.Arg.html#method.requires
pub fn requires(mut self, n: &'a str) -> Self {
pub fn requires<T: Key>(mut self, id: T) -> Self {
let arg_id = id.key();
if let Some(ref mut reqs) = self.requires {
reqs.push(n);
reqs.push(arg_id);
} else {
self.requires = Some(vec![n]);
self.requires = Some(vec![arg_id]);
}
self
}
@ -379,11 +388,12 @@ impl<'a> ArgGroup<'a> {
/// assert_eq!(err.kind, ErrorKind::ArgumentConflict);
/// ```
/// [argument exclusion rules]: ./struct.Arg.html#method.conflicts_with
pub fn conflicts_with(mut self, n: &'a str) -> Self {
pub fn conflicts_with<T: Key>(mut self, id: T) -> Self {
let arg_id = id.key();
if let Some(ref mut confs) = self.conflicts {
confs.push(n);
confs.push(arg_id);
} else {
self.conflicts = Some(vec![n]);
self.conflicts = Some(vec![arg_id]);
}
self
}
@ -445,6 +455,7 @@ impl<'a> Debug for ArgGroup<'a> {
impl<'a, 'z> From<&'z ArgGroup<'a>> for ArgGroup<'a> {
fn from(g: &'z ArgGroup<'a>) -> Self {
ArgGroup {
id: g.id,
name: g.name,
required: g.required,
args: g.args.clone(),
@ -508,6 +519,7 @@ impl<'a> From<&'a yaml_rust::yaml::Hash> for ArgGroup<'a> {
#[cfg(test)]
mod test {
use super::ArgGroup;
use super::Key;
#[cfg(feature = "yaml")]
use yaml_rust::YamlLoader;
@ -525,9 +537,9 @@ mod test {
.requires_all(&["r2", "r3"])
.requires("r4");
let args = vec!["a1", "a4", "a2", "a3"];
let reqs = vec!["r1", "r2", "r3", "r4"];
let confs = vec!["c1", "c2", "c3", "c4"];
let args = vec!["a1".key(), "a4".key(), "a2".key(), "a3".key()];
let reqs = vec!["r1".key(), "r2".key(), "r3".key(), "r4".key()];
let confs = vec!["c1".key(), "c2".key(), "c3".key(), "c4".key()];
assert_eq!(g.args, args);
assert_eq!(g.requires, Some(reqs));
@ -548,9 +560,9 @@ mod test {
.requires_all(&["r2", "r3"])
.requires("r4");
let args = vec!["a1", "a4", "a2", "a3"];
let reqs = vec!["r1", "r2", "r3", "r4"];
let confs = vec!["c1", "c2", "c3", "c4"];
let args = vec!["a1".key(), "a4".key(), "a2".key(), "a3".key()];
let reqs = vec!["r1".key(), "r2".key(), "r3".key(), "r4".key()];
let confs = vec!["c1".key(), "c2".key(), "c3".key(), "c4".key()];
let debug_str = format!(
"{{\n\
@ -582,9 +594,9 @@ mod test {
.requires_all(&["r2", "r3"])
.requires("r4");
let args = vec!["a1", "a4", "a2", "a3"];
let reqs = vec!["r1", "r2", "r3", "r4"];
let confs = vec!["c1", "c2", "c3", "c4"];
let args = vec!["a1".key(), "a4".key(), "a2".key(), "a3".key()];
let reqs = vec!["r1".key(), "r2".key(), "r3".key(), "r4".key()];
let confs = vec!["c1".key(), "c2".key(), "c3".key(), "c4".key()];
let g2 = ArgGroup::from(&g);
assert_eq!(g2.args, args);
@ -625,6 +637,7 @@ requires:
impl<'a> Clone for ArgGroup<'a> {
fn clone(&self) -> Self {
ArgGroup {
id: self.id,
name: self.name,
required: self.required,
args: self.args.clone(),

View file

@ -1,7 +1,7 @@
// Internal
use build::{Arg, ArgSettings};
use util::VecMap;
use INTERNAL_ERROR_MSG;
use crate::build::{Arg, ArgSettings};
use crate::util::{Key, VecMap};
use crate::INTERNAL_ERROR_MSG;
#[derive(PartialEq, Debug)]
enum UsageToken {
@ -41,7 +41,7 @@ impl<'a> UsageParser<'a> {
UsageParser::new(usage)
}
pub fn parse(mut self) -> Arg<'a, 'a> {
pub fn parse(mut self) -> Arg<'a> {
debugln!("UsageParser::parse;");
let mut arg = Arg::default();
arg.disp_ord = 999;
@ -72,7 +72,7 @@ impl<'a> UsageParser<'a> {
arg
}
fn name(&mut self, arg: &mut Arg<'a, 'a>) {
fn name(&mut self, arg: &mut Arg<'a>) {
debugln!("UsageParser::name;");
if *self
.usage
@ -89,6 +89,7 @@ impl<'a> UsageParser<'a> {
let name = &self.usage[self.start..self.pos];
if self.prev == UsageToken::Unknown {
debugln!("UsageParser::name: setting name...{}", name);
arg.id = name.key();
arg.name = name;
if arg.long.is_none() && arg.short.is_none() {
debugln!("UsageParser::name: explicit name set...");
@ -122,7 +123,7 @@ impl<'a> UsageParser<'a> {
.count();
}
fn short_or_long(&mut self, arg: &mut Arg<'a, 'a>) {
fn short_or_long(&mut self, arg: &mut Arg<'a>) {
debugln!("UsageParser::short_or_long;");
self.pos += 1;
if *self
@ -139,12 +140,13 @@ impl<'a> UsageParser<'a> {
self.short(arg)
}
fn long(&mut self, arg: &mut Arg<'a, 'a>) {
fn long(&mut self, arg: &mut Arg<'a>) {
debugln!("UsageParser::long;");
self.stop_at(long_end);
let name = &self.usage[self.start..self.pos];
if !self.explicit_name_set {
debugln!("UsageParser::long: setting name...{}", name);
arg.id = name.key();
arg.name = name;
}
debugln!("UsageParser::long: setting long...{}", name);
@ -152,7 +154,7 @@ impl<'a> UsageParser<'a> {
self.prev = UsageToken::Long;
}
fn short(&mut self, arg: &mut Arg<'a, 'a>) {
fn short(&mut self, arg: &mut Arg<'a>) {
debugln!("UsageParser::short;");
let start = &self.usage[self.pos..];
let short = start.chars().nth(0).expect(INTERNAL_ERROR_MSG);
@ -162,6 +164,7 @@ impl<'a> UsageParser<'a> {
// --long takes precedence but doesn't set self.explicit_name_set
let name = &start[..short.len_utf8()];
debugln!("UsageParser::short: setting name...{}", name);
arg.id = name.key();
arg.name = name;
}
self.prev = UsageToken::Short;
@ -189,7 +192,7 @@ impl<'a> UsageParser<'a> {
}
}
fn help(&mut self, arg: &mut Arg<'a, 'a>) {
fn help(&mut self, arg: &mut Arg<'a>) {
debugln!("UsageParser::help;");
self.stop_at(help_start);
self.start = self.pos + 1;
@ -220,7 +223,7 @@ fn help_start(b: u8) -> bool { b != b'\'' }
#[cfg(test)]
mod test {
use build::{Arg, ArgSettings};
use crate::build::{Arg, ArgSettings};
#[test]
fn create_flag_usage() {

View file

@ -523,13 +523,8 @@
missing_copy_implementations,
trivial_casts,
unused_import_braces,
unused_allocation
)]
// @TODO @v3-beta: remove me!
#![allow(deprecated)]
#![cfg_attr(
not(any(feature = "lints", feature = "nightly")),
forbid(unstable_features)
unused_allocation,
trivial_numeric_casts
)]
// Need to disable deny(warnings) while deprecations are active
// #![cfg_attr(feature = "lints", deny(warnings))]
@ -561,10 +556,10 @@ extern crate vec_map;
#[cfg(feature = "yaml")]
extern crate yaml_rust;
pub use build::{App, AppSettings, Arg, ArgGroup, ArgSettings, Propagation};
pub use output::fmt::Format;
pub use parse::errors::{Error, ErrorKind, Result};
pub use parse::{ArgMatches, OsValues, Values};
pub use crate::build::{App, AppSettings, Arg, ArgGroup, ArgSettings, Propagation};
pub use crate::output::fmt::Format;
pub use crate::parse::errors::{Error, ErrorKind, Result};
pub use crate::parse::{ArgMatches, OsValues, Values};
#[cfg(feature = "yaml")]
pub use yaml_rust::YamlLoader;
@ -593,12 +588,12 @@ pub trait Clap: FromArgMatches + IntoApp + Sized {}
/// @TODO @release @docs
pub trait FromArgMatches: Sized {
/// @TODO @release @docs
fn from_argmatches<'a>(matches: &::parse::ArgMatches<'a>) -> Self;
fn from_argmatches(matches: &crate::parse::ArgMatches) -> Self;
/// @TODO @release @docs
fn try_from_argmatches<'a>(
matches: &::parse::ArgMatches<'a>,
) -> StdResult<Self, ::parse::errors::Error> {
fn try_from_argmatches(
matches: &crate::parse::ArgMatches,
) -> StdResult<Self, crate::parse::errors::Error> {
Ok(<Self as FromArgMatches>::from_argmatches(matches))
}
}
@ -606,7 +601,7 @@ pub trait FromArgMatches: Sized {
/// @TODO @release @docs
pub trait IntoApp: Sized {
/// @TODO @release @docs
fn into_app<'a, 'b>() -> ::build::App<'a, 'b>;
fn into_app<'b>() -> crate::build::App<'b>;
}
/// @TODO @release @docs

View file

@ -264,7 +264,7 @@ macro_rules! values_t_or_exit {
macro_rules! _clap_count_exprs {
() => { 0 };
($e:expr) => { 1 };
($e:expr, $($es:expr),+) => { 1 + _clap_count_exprs!($($es),*) };
($e:expr, $($es:expr),+) => { 1 + $crate::_clap_count_exprs!($($es),*) };
}
/// Convenience macro to generate more complete enums with variants to be used as a type when
@ -348,7 +348,7 @@ macro_rules! arg_enum {
}
impl $e {
#[allow(dead_code)]
pub fn variants() -> [&'static str; _clap_count_exprs!($(stringify!($v)),+)] {
pub fn variants() -> [&'static str; $crate::_clap_count_exprs!($(stringify!($v)),+)] {
[
$(stringify!($v),)+
]
@ -890,7 +890,9 @@ macro_rules! flags {
$app.args
.args
.$how()
.filter(|a| !a.settings.is_set(::build::ArgSettings::TakesValue) && a.index.is_none())
.filter(|a| {
!a.settings.is_set(crate::build::ArgSettings::TakesValue) && a.index.is_none()
})
.filter(|a| !a.help_heading.is_some())
}};
($app:expr) => {
@ -910,7 +912,9 @@ macro_rules! opts {
$app.args
.args
.$how()
.filter(|a| a.settings.is_set(::build::ArgSettings::TakesValue) && a.index.is_none())
.filter(|a| {
a.settings.is_set(crate::build::ArgSettings::TakesValue) && a.index.is_none()
})
.filter(|a| !a.help_heading.is_some())
}};
($app:expr) => {
@ -979,8 +983,8 @@ macro_rules! groups_for_arg {
debugln!("Parser::groups_for_arg: name={}", $grp);
$app.groups
.iter()
.filter(|grp| grp.args.iter().any(|a| a == $grp))
.map(|grp| grp.name)
.filter(|grp| grp.args.iter().any(|&a| a == $grp))
.map(|grp| grp.id)
}};
}
@ -998,7 +1002,7 @@ macro_rules! find_subcmd {
macro_rules! longs {
($app:expr) => {{
use mkeymap::KeyType;
use crate::mkeymap::KeyType;
$app.args.keys.iter().map(|x| &x.key).filter_map(|a| {
if let KeyType::Long(v) = a {
Some(v)

View file

@ -1,6 +1,8 @@
use build::Arg;
use crate::build::Arg;
use std::ffi::{OsStr, OsString};
type Id = u64;
#[derive(PartialEq, Debug, Clone)]
pub struct Key {
pub key: KeyType,
@ -8,9 +10,9 @@ pub struct Key {
}
#[derive(Default, PartialEq, Debug, Clone)]
pub struct MKeyMap<'a, 'b> {
pub struct MKeyMap<'b> {
pub keys: Vec<Key>,
pub args: Vec<Arg<'a, 'b>>,
pub args: Vec<Arg<'b>>,
built: bool, // mutation isn't possible after being built
}
@ -60,7 +62,7 @@ impl PartialEq<char> for KeyType {
}
}
impl<'a, 'b> MKeyMap<'a, 'b> {
impl<'b> MKeyMap<'b> {
pub fn new() -> Self { MKeyMap::default() }
//TODO ::from(x), ::with_capacity(n) etc
//? set theory ops?
@ -69,13 +71,13 @@ impl<'a, 'b> MKeyMap<'a, 'b> {
pub fn contains_short(&self, c: char) -> bool { self.keys.iter().any(|x| x.key == c) }
pub fn insert(&mut self, key: KeyType, value: Arg<'a, 'b>) -> usize {
pub fn insert(&mut self, key: KeyType, value: Arg<'b>) -> usize {
let index = self.push(value);
self.keys.push(Key { key, index });
index
}
pub fn push(&mut self, value: Arg<'a, 'b>) -> usize {
pub fn push(&mut self, value: Arg<'b>) -> usize {
if self.built {
panic!("Cannot add Args to the map after the map is built");
}
@ -98,7 +100,7 @@ impl<'a, 'b> MKeyMap<'a, 'b> {
// ! Arg mutation functionality
pub fn get(&self, key: &KeyType) -> Option<&Arg<'a, 'b>> {
pub fn get(&self, key: &KeyType) -> Option<&Arg<'b>> {
for k in &self.keys {
if &k.key == key {
return Some(&self.args[k.index]);
@ -108,7 +110,7 @@ impl<'a, 'b> MKeyMap<'a, 'b> {
}
//TODO ::get_first([KeyA, KeyB])
pub fn get_mut(&mut self, key: &KeyType) -> Option<&mut Arg<'a, 'b>> {
pub fn get_mut(&mut self, key: &KeyType) -> Option<&mut Arg<'b>> {
for k in &self.keys {
if &k.key == key {
return self.args.get_mut(k.index);
@ -186,7 +188,7 @@ impl<'a, 'b> MKeyMap<'a, 'b> {
.expect("No such name found")
}
pub fn remove(&mut self, key: &KeyType) -> Option<Arg<'a, 'b>> {
pub fn remove(&mut self, key: &KeyType) -> Option<Arg<'b>> {
if self.built {
panic!("Cannot remove args after being built");
}
@ -200,7 +202,7 @@ impl<'a, 'b> MKeyMap<'a, 'b> {
if let Some(idx) = idx {
let arg = self.args.swap_remove(idx);
for key in _get_keys(&arg) {
let _ = self.remove_key(&key);
self.remove_key(&key);
}
return Some(arg);
}
@ -211,13 +213,13 @@ impl<'a, 'b> MKeyMap<'a, 'b> {
//? probably shouldn't add a possibility for removal?
//? or remove by replacement by some dummy object, so the order is preserved
pub fn remove_by_name(&mut self, _name: &str) -> Option<Arg<'a, 'b>> {
pub fn remove_by_name(&mut self, _name: Id) -> Option<Arg<'b>> {
if self.built {
panic!("Cannot remove args after being built");
}
let mut index = None;
for (i, arg) in self.args.iter().enumerate() {
if arg.name == _name {
if arg.id == _name {
index = Some(i);
break;
}

View file

@ -6,13 +6,13 @@ use std::io::{self, Cursor, Read, Write};
use std::usize;
// Internal
use build::{App, AppSettings, Arg, ArgSettings};
use output::fmt::{Colorizer, ColorizerOption, Format};
use output::Usage;
use parse::errors::{Error, Result as ClapResult};
use parse::Parser;
use util::VecMap;
use INTERNAL_ERROR_MSG;
use crate::build::{App, AppSettings, Arg, ArgSettings};
use crate::output::fmt::{Colorizer, ColorizerOption, Format};
use crate::output::Usage;
use crate::parse::errors::{Error, Result as ClapResult};
use crate::parse::Parser;
use crate::util::VecMap;
use crate::INTERNAL_ERROR_MSG;
// Third Party
#[cfg(feature = "wrap_help")]
@ -32,9 +32,9 @@ const TAB: &str = " ";
/// `clap` Help Writer.
///
/// Wraps a writer stream providing different methods to generate help for `clap` objects.
pub struct Help<'a, 'b, 'c, 'd, 'w> {
pub struct Help<'b, 'c, 'd, 'w> {
writer: &'w mut Write,
parser: &'d Parser<'a, 'b, 'c>,
parser: &'d Parser<'b, 'c>,
next_line_help: bool,
hide_pv: bool,
term_w: usize,
@ -46,14 +46,9 @@ pub struct Help<'a, 'b, 'c, 'd, 'w> {
}
// Public Functions
impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
impl<'b, 'c, 'd, 'w> Help<'b, 'c, 'd, 'w> {
/// Create a new `Help` instance.
pub fn new(
w: &'w mut Write,
parser: &'d Parser<'a, 'b, 'c>,
use_long: bool,
stderr: bool,
) -> Self {
pub fn new(w: &'w mut Write, parser: &'d Parser<'b, 'c>, use_long: bool, stderr: bool) -> Self {
debugln!("Help::new;");
let term_w = match parser.app.term_w {
Some(0) => usize::MAX,
@ -102,19 +97,36 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
}
// Methods to write Arg help.
impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
impl<'b, 'c, 'd, 'w> Help<'b, 'c, 'd, 'w> {
fn color(&mut self, f: Format<&str>) -> io::Result<()> {
match f {
Format::Good(g) => if self.color { write!(self.writer, "{}", self.cizer.good(g)) } else { write!(self.writer, "{}", g) },
Format::Warning(w) => if self.color { write!(self.writer, "{}", self.cizer.warning(w))} else { write!(self.writer, "{}", w) },
Format::Error(e) => if self.color { write!(self.writer, "{}", self.cizer.error(e)) } else { write!(self.writer, "{}", e) },
_ => unreachable!()
Format::Good(g) => {
if self.color {
write!(self.writer, "{}", self.cizer.good(g))
} else {
write!(self.writer, "{}", g)
}
}
Format::Warning(w) => {
if self.color {
write!(self.writer, "{}", self.cizer.warning(w))
} else {
write!(self.writer, "{}", w)
}
}
Format::Error(e) => {
if self.color {
write!(self.writer, "{}", self.cizer.error(e))
} else {
write!(self.writer, "{}", e)
}
}
_ => unreachable!(),
}
}
/// Writes help for each argument in the order they were declared to the wrapped stream.
fn write_args_unsorted(&mut self, args: &[&Arg<'a, 'b>]) -> io::Result<()>
{
fn write_args_unsorted(&mut self, args: &[&Arg<'b>]) -> io::Result<()> {
debugln!("Help::write_args_unsorted;");
// The shortest an arg can legally be is 2 (i.e. '-x')
self.longest = 2;
@ -140,7 +152,7 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
}
/// Sorts arguments by length and display order and write their help to the wrapped stream.
fn write_args(&mut self, args: &[&Arg<'a, 'b>]) -> io::Result<()> {
fn write_args(&mut self, args: &[&Arg<'b>]) -> io::Result<()> {
debugln!("Help::write_args;");
// The shortest an arg can legally be is 2 (i.e. '-x')
self.longest = 2;
@ -159,6 +171,8 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
debugln!("Help::write_args: New Longest...{}", self.longest);
}
let btm = ord_m.entry(arg.disp_ord).or_insert(BTreeMap::new());
// We use name here for alphabetic sorting
// @TODO @maybe perhaps we could do some sort of ordering off of keys?
btm.insert(arg.name, arg);
}
let mut first = true;
@ -176,7 +190,7 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
}
/// Writes help for an argument to the wrapped stream.
fn write_arg(&mut self, arg: &Arg<'b, 'c>, prevent_nlh: bool) -> io::Result<()> {
fn write_arg(&mut self, arg: &Arg<'c>, prevent_nlh: bool) -> io::Result<()> {
debugln!("Help::write_arg;");
self.short(arg)?;
self.long(arg)?;
@ -186,7 +200,7 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
}
/// Writes argument's short command to the wrapped stream.
fn short(&mut self, arg: &Arg<'b, 'c>) -> io::Result<()> {
fn short(&mut self, arg: &Arg<'c>) -> io::Result<()> {
debugln!("Help::short;");
write!(self.writer, "{}", TAB)?;
if let Some(s) = arg.short {
@ -199,7 +213,7 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
}
/// Writes argument's long command to the wrapped stream.
fn long(&mut self, arg: &Arg<'b, 'c>) -> io::Result<()> {
fn long(&mut self, arg: &Arg<'c>) -> io::Result<()> {
debugln!("Help::long;");
if !arg.has_switch() {
return Ok(());
@ -228,7 +242,7 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
}
/// Writes argument's possible values to the wrapped stream.
fn val(&mut self, arg: &Arg<'b, 'c>) -> Result<String, io::Error> {
fn val(&mut self, arg: &Arg<'c>) -> Result<String, io::Error> {
debugln!("Help::val: arg={}", arg.name);
let mult =
arg.is_set(ArgSettings::MultipleValues) || arg.is_set(ArgSettings::MultipleOccurrences);
@ -358,12 +372,7 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
}
/// Writes argument's help to the wrapped stream.
fn help(
&mut self,
arg: &Arg<'b, 'c>,
spec_vals: &str,
prevent_nlh: bool,
) -> io::Result<()> {
fn help(&mut self, arg: &Arg<'c>, spec_vals: &str, prevent_nlh: bool) -> io::Result<()> {
debugln!("Help::help;");
let h = if self.use_long {
arg.long_help.unwrap_or_else(|| arg.help.unwrap_or(""))
@ -496,8 +505,8 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
}
/// Methods to write a single subcommand
impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
fn write_subcommand(&mut self, app: &App<'a, 'b>) -> io::Result<()> {
impl<'b, 'c, 'd, 'w> Help<'b, 'c, 'd, 'w> {
fn write_subcommand(&mut self, app: &App<'b>) -> io::Result<()> {
debugln!("Help::write_subcommand;");
write!(self.writer, "{}", TAB)?;
self.color(Format::Good(&*app.name))?;
@ -506,7 +515,7 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
Ok(())
}
fn sc_val(&mut self, app: &App<'a, 'b>) -> Result<String, io::Error> {
fn sc_val(&mut self, app: &App<'b>) -> Result<String, io::Error> {
debugln!("Help::sc_val: app={}", app.name);
let spec_vals = self.sc_spec_vals(app);
let h = app.about.unwrap_or("");
@ -554,7 +563,7 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
spec_vals.join(" ")
}
fn sc_help(&mut self, app: &App<'a, 'b>, spec_vals: &str) -> io::Result<()> {
fn sc_help(&mut self, app: &App<'b>, spec_vals: &str) -> io::Result<()> {
debugln!("Help::sc_help;");
let h = if self.use_long {
app.long_about.unwrap_or_else(|| app.about.unwrap_or(""))
@ -610,7 +619,7 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
}
// Methods to write Parser help.
impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
impl<'b, 'c, 'd, 'w> Help<'b, 'c, 'd, 'w> {
/// Writes help for all arguments (options, flags, args, subcommands)
/// including titles of a Parser Object to the wrapped stream.
pub fn write_all_args(&mut self) -> ClapResult<()> {
@ -649,7 +658,14 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
let unified_help = self.parser.is_set(AppSettings::UnifiedHelpMessage);
if unified_help && (flags || opts) {
let opts_flags = self.parser.app.args.args.iter().filter(|a| a.has_switch()).collect::<Vec<_>>();
let opts_flags = self
.parser
.app
.args
.args
.iter()
.filter(|a| a.has_switch())
.collect::<Vec<_>>();
if !first {
self.writer.write_all(b"\n\n")?;
}
@ -662,7 +678,8 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
self.writer.write_all(b"\n\n")?;
}
self.color(Format::Warning("FLAGS:\n"))?;
self.write_args(&*flags!(self.parser.app).collect::<Vec<_>>())?;
let flags_v: Vec<_> = flags!(self.parser.app).collect();
self.write_args(&*flags_v)?;
first = false;
}
if opts {
@ -674,7 +691,8 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
first = false;
}
if custom_headings {
for heading in self.parser
for heading in self
.parser
.app
.help_headings
.iter()
@ -685,9 +703,14 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
self.writer.write_all(b"\n\n")?;
}
self.color(Format::Warning(&*format!("{}:\n", heading)))?;
let args = self.parser.app.args.args.iter().filter(|a| {
a.help_heading.is_some() && a.help_heading.unwrap() == heading
}).collect::<Vec<_>>();
let args = self
.parser
.app
.args
.args
.iter()
.filter(|a| a.help_heading.is_some() && a.help_heading.unwrap() == heading)
.collect::<Vec<_>>();
self.write_args(&*args)?;
first = false
}
@ -706,7 +729,7 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
}
/// Writes help for subcommands of a Parser Object to the wrapped stream.
fn write_subcommands(&mut self, app: &App<'a, 'b>) -> io::Result<()> {
fn write_subcommands(&mut self, app: &App<'b>) -> io::Result<()> {
debugln!("Help::write_subcommands;");
// The shortest an arg can legally be is 2 (i.e. '-x')
self.longest = 2;
@ -741,10 +764,13 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
/// Writes binary name of a Parser Object to the wrapped stream.
fn write_bin_name(&mut self) -> io::Result<()> {
debugln!("Help::write_bin_name;");
let term_w = self.term_w.clone();
let term_w = self.term_w;
macro_rules! write_name {
() => {{
self.color(Format::Good(&*wrap_help(&self.parser.app.name.replace("{n}", "\n"), term_w)))?;
self.color(Format::Good(&*wrap_help(
&self.parser.app.name.replace("{n}", "\n"),
term_w,
)))?;
}};
}
if let Some(bn) = self.parser.app.bin_name.as_ref() {
@ -770,7 +796,11 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
macro_rules! write_thing {
($thing:expr) => {{
write!(self.writer, "{}\n", wrap_help(&$thing.replace("{n}", "\n"), self.term_w))?
write!(
self.writer,
"{}\n",
wrap_help(&$thing.replace("{n}", "\n"), self.term_w)
)?
}};
}
// Print the version
@ -915,7 +945,7 @@ fn copy_and_capture<R: Read, W: Write>(
}
// Methods to write Parser help using templates.
impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
impl<'b, 'c, 'd, 'w> Help<'b, 'c, 'd, 'w> {
/// Write help to stream for the parser in the format defined by the template.
///
/// Tags arg given inside curly brackets:
@ -1009,7 +1039,14 @@ impl<'a, 'b, 'c, 'd, 'w> Help<'a, 'b, 'c, 'd, 'w> {
self.write_all_args()?;
}
b"unified" => {
let opts_flags = self.parser.app.args.args.iter().filter(|a| a.has_switch()).collect::<Vec<_>>();
let opts_flags = self
.parser
.app
.args
.args
.iter()
.filter(|a| a.has_switch())
.collect::<Vec<_>>();
self.write_args(&*opts_flags)?;
}
b"flags" => {

View file

@ -2,26 +2,27 @@
use std::collections::{BTreeMap, VecDeque};
// Internal
use build::AppSettings as AS;
use build::{Arg, ArgSettings};
use parse::{ArgMatcher, Parser};
use INTERNAL_ERROR_MSG;
use crate::build::AppSettings as AS;
use crate::build::{Arg, ArgSettings};
use crate::parse::{ArgMatcher, Parser};
use crate::INTERNAL_ERROR_MSG;
pub struct Usage<'a, 'b, 'c, 'z>
type Id = u64;
pub struct Usage<'b, 'c, 'z>
where
'a: 'b,
'b: 'c,
'c: 'z,
{
p: &'z Parser<'a, 'b, 'c>,
p: &'z Parser<'b, 'c>,
}
impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
pub fn new(p: &'z Parser<'a, 'b, 'c>) -> Self { Usage { p } }
impl<'b, 'c, 'z> Usage<'b, 'c, 'z> {
pub fn new(p: &'z Parser<'b, 'c>) -> Self { Usage { p } }
// Creates a usage string for display. This happens just after all arguments were parsed, but before
// any subcommands have been parsed (so as to give subcommands their own usage recursively)
pub fn create_usage_with_title(&self, used: &[&str]) -> String {
pub fn create_usage_with_title(&self, used: &[Id]) -> String {
debugln!("usage::create_usage_with_title;");
let mut usage = String::with_capacity(75);
usage.push_str("USAGE:\n ");
@ -30,7 +31,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
}
// Creates a usage string (*without title*) if one was not provided by the user manually.
pub fn create_usage_no_title(&self, used: &[&str]) -> String {
pub fn create_usage_no_title(&self, used: &[Id]) -> String {
debugln!("usage::create_usage_no_title;");
if let Some(u) = self.p.app.usage_str {
String::from(&*u)
@ -148,7 +149,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
// Creates a context aware usage string, or "smart usage" from currently used
// args, and requirements
fn create_smart_usage(&self, used: &[&str]) -> String {
fn create_smart_usage(&self, used: &[Id]) -> String {
debugln!("usage::smart_usage;");
let mut usage = String::with_capacity(75);
@ -183,7 +184,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
.filter(|pos| !pos.is_set(ArgSettings::Last))
{
debugln!("usage::get_args_tag:iter:{}:", pos.name);
for grp_s in groups_for_arg!(self.p.app, &pos.name) {
for grp_s in groups_for_arg!(self.p.app, pos.id) {
debugln!("usage::get_args_tag:iter:{}:iter:{};", pos.name, grp_s);
// if it's part of a required group we don't want to count it
if self
@ -191,7 +192,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
.app
.groups
.iter()
.any(|g| g.required && (g.name == grp_s))
.any(|g| g.required && (g.id == grp_s))
{
continue 'outer;
}
@ -279,14 +280,14 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
continue;
}
}
for grp_s in groups_for_arg!(self.p.app, &f.name) {
for grp_s in groups_for_arg!(self.p.app, f.id) {
debugln!("usage::needs_flags_tag:iter:iter: grp_s={};", grp_s);
if self
.p
.app
.groups
.iter()
.any(|g| g.name == grp_s && g.required)
.any(|g| g.id == grp_s && g.required)
{
debugln!("usage::needs_flags_tag:iter:iter: Group is required");
continue 'outer;
@ -309,7 +310,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
// `prog [foo] -- [last] <subcommand>` which is totally wrong.
pub fn get_required_usage_from(
&self,
incls: &[&str],
incls: &[Id],
matcher: Option<&ArgMatcher>,
incl_last: bool,
) -> VecDeque<String> {
@ -323,7 +324,7 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
let mut unrolled_reqs = vec![];
for a in self.p.required.iter() {
for &a in self.p.required.iter() {
if let Some(ref m) = matcher {
for aa in self.p.app.unroll_requirements_for_arg(a, m) {
unrolled_reqs.push(aa);
@ -338,60 +339,60 @@ impl<'a, 'b, 'c, 'z> Usage<'a, 'b, 'c, 'z> {
.app
.groups
.iter()
.filter(|gn| self.p.required.contains(&gn.name))
.flat_map(|g| self.p.app.unroll_args_in_group(g.name))
.filter(|gn| self.p.required.contains(gn.id))
.flat_map(|g| self.p.app.unroll_args_in_group(g.id))
.collect::<Vec<_>>();
let pmap = if let Some(m) = matcher {
unrolled_reqs
.iter()
.chain(incls.iter())
.filter(|a| positionals!(self.p.app).any(|p| &&p.name == a))
.filter(|&pos| !m.contains(pos))
.filter_map(|pos| self.p.app.find(pos))
.filter(|a| positionals!(self.p.app).any(|p| &&p.id == a))
.filter(|&&pos| !m.contains(pos))
.filter_map(|&pos| self.p.app.find(pos))
.filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
.filter(|pos| !args_in_groups.contains(&pos.name))
.filter(|pos| !args_in_groups.contains(&pos.id))
.map(|pos| (pos.index.unwrap(), pos))
.collect::<BTreeMap<u64, &Arg>>() // sort by index
} else {
unrolled_reqs
.iter()
.chain(incls.iter())
.filter(|a| positionals!(self.p.app).any(|p| &&p.name == a))
.filter_map(|pos| self.p.app.find(pos))
.filter(|a| positionals!(self.p.app).any(|p| &&p.id == a))
.filter_map(|&pos| self.p.app.find(pos))
.filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
.filter(|pos| !args_in_groups.contains(&pos.name))
.filter(|pos| !args_in_groups.contains(&pos.id))
.map(|pos| (pos.index.unwrap(), pos))
.collect::<BTreeMap<u64, &Arg>>() // sort by index
};
for &p in pmap.values() {
debugln!("Usage::get_required_usage_from:iter:{}", p.to_string());
let s = p.to_string();
if args_in_groups.is_empty() || !args_in_groups.contains(&&*s) {
ret_val.push_back(s);
debugln!("Usage::get_required_usage_from:iter:{}", p.id);
let s = p.id;
if args_in_groups.is_empty() || !args_in_groups.contains(&s) {
ret_val.push_back(p.to_string());
}
}
for a in unrolled_reqs
for &a in unrolled_reqs
.iter()
.chain(incls.iter())
.filter(|name| !positionals!(self.p.app).any(|p| &&p.name == name))
.filter(|name| !self.p.app.groups.iter().any(|g| &&g.name == name))
.filter(|name| !positionals!(self.p.app).any(|p| &&p.id == name))
.filter(|name| !self.p.app.groups.iter().any(|g| &&g.id == name))
.filter(|name| !args_in_groups.contains(name))
.filter(|name| !(matcher.is_some() && matcher.as_ref().unwrap().contains(name)))
.filter(|name| !(matcher.is_some() && matcher.as_ref().unwrap().contains(**name)))
{
debugln!("Usage::get_required_usage_from:iter:{}:", a);
let arg = self
.p
.app
.find(a)
.map(|f| f.to_string())
.map(ToString::to_string)
.expect(INTERNAL_ERROR_MSG);
ret_val.push_back(arg);
}
let mut g_vec: Vec<String> = vec![];
for g in unrolled_reqs
for &g in unrolled_reqs
.iter()
.filter(|n| self.p.app.groups.iter().any(|g| &&g.name == n))
.filter(|n| self.p.app.groups.iter().any(|g| g.id == **n))
{
let elem = self.p.app.format_group(g);
if !g_vec.contains(&elem) {

View file

@ -7,24 +7,28 @@ use std::mem;
use indexmap;
// Internal
use build::{Arg, ArgSettings};
use parse::{ArgMatches, MatchedArg, SubCommand};
use crate::build::{Arg, ArgSettings};
use crate::parse::{ArgMatches, MatchedArg, SubCommand};
type Id = u64;
#[doc(hidden)]
#[allow(missing_debug_implementations)]
pub struct ArgMatcher<'a>(pub ArgMatches<'a>);
#[derive(Debug)]
pub struct ArgMatcher(pub ArgMatches);
impl<'a> Default for ArgMatcher<'a> {
impl Default for ArgMatcher {
fn default() -> Self { ArgMatcher(ArgMatches::default()) }
}
impl<'a> ArgMatcher<'a> {
impl ArgMatcher {
pub fn new() -> Self { ArgMatcher::default() }
#[allow(dead_code)]
pub fn is_present(&self, name: &str) -> bool { self.0.is_present(name) }
pub fn into_inner(self) -> ArgMatches { self.0 }
pub fn propagate_globals(&mut self, global_arg_vec: &[&'a str]) {
#[allow(dead_code)]
pub fn is_present(&self, name: Id) -> bool { self.0._id_is_present(name) }
pub fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
debugln!(
"ArgMatcher::get_global_values: global_arg_vec={:?}",
global_arg_vec
@ -35,10 +39,10 @@ impl<'a> ArgMatcher<'a> {
fn fill_in_global_values(
&mut self,
global_arg_vec: &[&'a str],
vals_map: &mut HashMap<&'a str, MatchedArg>,
global_arg_vec: &[Id],
vals_map: &mut HashMap<Id, MatchedArg>,
) {
for global_arg in global_arg_vec {
for &global_arg in global_arg_vec {
if let Some(ma) = self.get(global_arg) {
// We have to check if the parent's global arg wasn't used but still exists
// such as from a default value.
@ -46,7 +50,7 @@ impl<'a> ArgMatcher<'a> {
// For example, `myprog subcommand --global-arg=value` where --global-arg defines
// a default value of `other` myprog would have an existing MatchedArg for
// --global-arg where the value is `other`, however the occurs will be 0.
let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
let to_update = if let Some(parent_ma) = vals_map.get(&global_arg) {
if parent_ma.occurs > 0 && ma.occurs == 0 {
parent_ma.clone()
} else {
@ -64,43 +68,43 @@ impl<'a> ArgMatcher<'a> {
mem::swap(&mut am.0, &mut sc.matches);
}
for (name, matched_arg) in vals_map.iter_mut() {
for (&name, matched_arg) in vals_map.iter_mut() {
self.0.args.insert(name, matched_arg.clone());
}
}
pub fn get_mut(&mut self, arg: &str) -> Option<&mut MatchedArg> { self.0.args.get_mut(arg) }
pub fn get_mut(&mut self, arg: Id) -> Option<&mut MatchedArg> { self.0.args.get_mut(&arg) }
pub fn get(&self, arg: &str) -> Option<&MatchedArg> { self.0.args.get(arg) }
pub fn get(&self, arg: Id) -> Option<&MatchedArg> { self.0.args.get(&arg) }
pub fn remove(&mut self, arg: &str) { self.0.args.remove(arg); }
pub fn remove(&mut self, arg: Id) { self.0.args.remove(&arg); }
#[allow(dead_code)]
pub fn remove_all(&mut self, args: &[&str]) {
for &arg in args {
pub fn remove_all(&mut self, args: &[Id]) {
for arg in args {
self.0.args.remove(arg);
}
}
pub fn insert(&mut self, name: &'a str) { self.0.args.insert(name, MatchedArg::new()); }
pub fn insert(&mut self, name: Id) { self.0.args.insert(name, MatchedArg::new()); }
pub fn contains(&self, arg: &str) -> bool { self.0.args.contains_key(arg) }
pub fn contains(&self, arg: Id) -> bool { self.0.args.contains_key(&arg) }
pub fn is_empty(&self) -> bool { self.0.args.is_empty() }
pub fn arg_names(&'a self) -> indexmap::map::Keys<&'a str, MatchedArg> { self.0.args.keys() }
pub fn arg_names(&self) -> indexmap::map::Keys<Id, MatchedArg> { self.0.args.keys() }
pub fn entry(&mut self, arg: &'a str) -> indexmap::map::Entry<&'a str, MatchedArg> {
pub fn entry(&mut self, arg: Id) -> indexmap::map::Entry<Id, MatchedArg> {
self.0.args.entry(arg)
}
pub fn subcommand(&mut self, sc: SubCommand<'a>) { self.0.subcommand = Some(Box::new(sc)); }
pub fn subcommand(&mut self, sc: SubCommand) { self.0.subcommand = Some(Box::new(sc)); }
pub fn subcommand_name(&self) -> Option<&str> { self.0.subcommand_name() }
pub fn iter(&self) -> indexmap::map::Iter<&str, MatchedArg> { self.0.args.iter() }
pub fn iter(&self) -> indexmap::map::Iter<Id, MatchedArg> { self.0.args.iter() }
pub fn inc_occurrence_of(&mut self, arg: &'a str) {
pub fn inc_occurrence_of(&mut self, arg: Id) {
debugln!("ArgMatcher::inc_occurrence_of: arg={}", arg);
if let Some(a) = self.get_mut(arg) {
a.occurs += 1;
@ -110,16 +114,16 @@ impl<'a> ArgMatcher<'a> {
self.insert(arg);
}
pub fn add_val_to(&mut self, arg: &'a str, val: &OsStr) {
pub fn add_val_to(&mut self, arg: Id, val: &OsStr) {
let ma = self.entry(arg).or_insert(MatchedArg {
occurs: 0,
occurs: 0, // @TODO @question Shouldn't this be 1 if we're already adding a value to this arg?
indices: Vec::with_capacity(1),
vals: Vec::with_capacity(1),
});
ma.vals.push(val.to_owned());
}
pub fn add_index_to(&mut self, arg: &'a str, idx: usize) {
pub fn add_index_to(&mut self, arg: Id, idx: usize) {
let ma = self.entry(arg).or_insert(MatchedArg {
occurs: 0,
indices: Vec::with_capacity(1),
@ -130,7 +134,7 @@ impl<'a> ArgMatcher<'a> {
pub fn needs_more_vals(&self, o: &Arg) -> bool {
debugln!("ArgMatcher::needs_more_vals: o={}", o.name);
if let Some(ma) = self.get(o.name) {
if let Some(ma) = self.get(o.id) {
if let Some(num) = o.num_vals {
debugln!("ArgMatcher::needs_more_vals: num_vals...{}", num);
return if o.is_set(ArgSettings::MultipleValues) {
@ -150,7 +154,3 @@ impl<'a> ArgMatcher<'a> {
true
}
}
impl<'a> Into<ArgMatches<'a>> for ArgMatcher<'a> {
fn into(self) -> ArgMatches<'a> { self.0 }
}

View file

@ -8,9 +8,9 @@ use std::process;
use std::result::Result as StdResult;
// Internal
use build::{Arg, ArgGroup};
use output::fmt::{ColorWhen, Colorizer, ColorizerOption};
use parse::features::suggestions;
use crate::build::{Arg, ArgGroup};
use crate::output::fmt::{ColorWhen, Colorizer, ColorizerOption};
use crate::parse::features::suggestions;
/// Short hand for [`Result`] type
///

View file

@ -3,8 +3,8 @@
use strsim;
// Internal
use build::{App, Propagation};
use output::fmt::Format;
use crate::build::{App, Propagation};
use crate::output::fmt::Format;
/// Produces a string from a given list of possible values which is similar to
/// the passed in value `v` with a certain confidence.
@ -62,7 +62,7 @@ where
}
None => {
for subcommand in subcommands {
subcommand._build(Propagation::NextLevel);
subcommand._build();
if let Some(ref candidate) = did_you_mean(
arg,
longs!(subcommand).map(|x| x.to_string_lossy().into_owned()),

View file

@ -8,8 +8,11 @@ use std::slice::Iter;
use indexmap::IndexMap;
// Internal
use parse::{MatchedArg, SubCommand};
use INVALID_UTF8;
use crate::parse::{MatchedArg, SubCommand};
use crate::util::Key;
use crate::INVALID_UTF8;
type Id = u64;
/// Used to get information about the arguments that where supplied to the program at runtime by
/// the user. New instances of this struct are obtained by using the [`App::get_matches`] family of
@ -59,14 +62,14 @@ use INVALID_UTF8;
/// ```
/// [`App::get_matches`]: ./struct.App.html#method.get_matches
#[derive(Debug, Clone)]
pub struct ArgMatches<'a> {
pub struct ArgMatches {
#[doc(hidden)]
pub args: IndexMap<&'a str, MatchedArg>,
pub args: IndexMap<Id, MatchedArg>,
#[doc(hidden)]
pub subcommand: Option<Box<SubCommand<'a>>>,
pub subcommand: Option<Box<SubCommand>>,
}
impl<'a> Default for ArgMatches<'a> {
impl<'a> Default for ArgMatches {
fn default() -> Self {
ArgMatches {
args: IndexMap::new(),
@ -75,7 +78,7 @@ impl<'a> Default for ArgMatches<'a> {
}
}
impl<'a> ArgMatches<'a> {
impl ArgMatches {
#[doc(hidden)]
pub fn new() -> Self {
ArgMatches {
@ -110,8 +113,8 @@ impl<'a> ArgMatches<'a> {
/// [positional]: ./struct.Arg.html#method.index
/// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of
/// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html
pub fn value_of<S: AsRef<str>>(&self, name: S) -> Option<&str> {
if let Some(arg) = self.args.get(name.as_ref()) {
pub fn value_of<T: Key>(&self, id: T) -> Option<&str> {
if let Some(arg) = self.args.get(&id.key()) {
if let Some(v) = arg.vals.get(0) {
return Some(v.to_str().expect(INVALID_UTF8));
}
@ -142,8 +145,8 @@ impl<'a> ArgMatches<'a> {
/// assert_eq!(&*m.value_of_lossy("arg").unwrap(), "Hi \u{FFFD}!");
/// ```
/// [`Arg::values_of_lossy`]: ./struct.ArgMatches.html#method.values_of_lossy
pub fn value_of_lossy<S: AsRef<str>>(&'a self, name: S) -> Option<Cow<'a, str>> {
if let Some(arg) = self.args.get(name.as_ref()) {
pub fn value_of_lossy<T: Key>(&self, id: T) -> Option<Cow<'_, str>> {
if let Some(arg) = self.args.get(&id.key()) {
if let Some(v) = arg.vals.get(0) {
return Some(v.to_string_lossy());
}
@ -178,10 +181,10 @@ impl<'a> ArgMatches<'a> {
/// ```
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
/// [`ArgMatches::values_of_os`]: ./struct.ArgMatches.html#method.values_of_os
pub fn value_of_os<S: AsRef<str>>(&self, name: S) -> Option<&OsStr> {
pub fn value_of_os<T: Key>(&self, id: T) -> Option<&OsStr> {
self.args
.get(name.as_ref())
.and_then(|arg| arg.vals.get(0).map(|v| v.as_os_str()))
.get(&id.key())
.and_then(|arg| arg.vals.get(0).map(OsString::as_os_str))
}
/// Gets a [`Values`] struct which implements [`Iterator`] for values of a specific argument
@ -209,8 +212,8 @@ impl<'a> ArgMatches<'a> {
/// ```
/// [`Values`]: ./struct.Values.html
/// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
pub fn values_of<S: AsRef<str>>(&'a self, name: S) -> Option<Values<'a>> {
if let Some(arg) = self.args.get(name.as_ref()) {
pub fn values_of<T: Key>(&self, id: T) -> Option<Values<'_>> {
if let Some(arg) = self.args.get(&id.key()) {
fn to_str_slice(o: &OsString) -> &str { o.to_str().expect(INVALID_UTF8) }
let to_str_slice: fn(&OsString) -> &str = to_str_slice; // coerce to fn pointer
return Some(Values {
@ -244,8 +247,8 @@ impl<'a> ArgMatches<'a> {
/// assert_eq!(&itr.next().unwrap()[..], "\u{FFFD}!");
/// assert_eq!(itr.next(), None);
/// ```
pub fn values_of_lossy<S: AsRef<str>>(&'a self, name: S) -> Option<Vec<String>> {
if let Some(arg) = self.args.get(name.as_ref()) {
pub fn values_of_lossy<T: Key>(&self, id: T) -> Option<Vec<String>> {
if let Some(arg) = self.args.get(&id.key()) {
return Some(
arg.vals
.iter()
@ -287,10 +290,10 @@ impl<'a> ArgMatches<'a> {
/// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
/// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
pub fn values_of_os<S: AsRef<str>>(&'a self, name: S) -> Option<OsValues<'a>> {
pub fn values_of_os<'a, T: Key>(&'a self, id: T) -> Option<OsValues<'a>> {
fn to_str_slice(o: &OsString) -> &OsStr { &*o }
let to_str_slice: fn(&'a OsString) -> &'a OsStr = to_str_slice; // coerce to fn pointer
if let Some(arg) = self.args.get(name.as_ref()) {
if let Some(arg) = self.args.get(&id.key()) {
return Some(OsValues {
iter: arg.vals.iter().map(to_str_slice),
});
@ -313,13 +316,16 @@ impl<'a> ArgMatches<'a> {
///
/// assert!(m.is_present("debug"));
/// ```
pub fn is_present<S: AsRef<str>>(&self, name: S) -> bool {
pub fn is_present<T: Key>(&self, id: T) -> bool { self._id_is_present(id.key()) }
#[doc(hidden)]
pub fn _id_is_present(&self, arg_id: Id) -> bool {
if let Some(ref sc) = self.subcommand {
if sc.name == name.as_ref() {
if sc.id == arg_id {
return true;
}
}
self.args.contains_key(name.as_ref())
self.args.contains_key(&arg_id)
}
/// Returns the number of times an argument was used at runtime. If an argument isn't present
@ -361,8 +367,8 @@ impl<'a> ArgMatches<'a> {
/// assert_eq!(m.occurrences_of("debug"), 3);
/// assert_eq!(m.occurrences_of("flag"), 1);
/// ```
pub fn occurrences_of<S: AsRef<str>>(&self, name: S) -> u64 {
self.args.get(name.as_ref()).map_or(0, |a| a.occurs)
pub fn occurrences_of<T: Key>(&self, id: T) -> u64 {
self.args.get(&id.key()).map_or(0, |a| a.occurs)
}
/// Gets the starting index of the argument in respect to all other arguments. Indices are
@ -495,8 +501,8 @@ impl<'a> ArgMatches<'a> {
/// ```
/// [`ArgMatches`]: ./struct.ArgMatches.html
/// [delimiter]: ./struct.Arg.html#method.value_delimiter
pub fn index_of<S: AsRef<str>>(&self, name: S) -> Option<usize> {
if let Some(arg) = self.args.get(name.as_ref()) {
pub fn index_of<T: Key>(&self, name: T) -> Option<usize> {
if let Some(arg) = self.args.get(&name.key()) {
if let Some(i) = arg.indices.get(0) {
return Some(*i);
}
@ -577,8 +583,8 @@ impl<'a> ArgMatches<'a> {
/// [`ArgMatches`]: ./struct.ArgMatches.html
/// [`ArgMatches::index_of`]: ./struct.ArgMatches.html#method.index_of
/// [delimiter]: ./struct.Arg.html#method.value_delimiter
pub fn indices_of<S: AsRef<str>>(&'a self, name: S) -> Option<Indices<'a>> {
if let Some(arg) = self.args.get(name.as_ref()) {
pub fn indices_of<T: Key>(&self, id: T) -> Option<Indices<'_>> {
if let Some(arg) = self.args.get(&id.key()) {
return Some(Indices {
iter: arg.indices.iter().cloned(),
});
@ -617,9 +623,9 @@ impl<'a> ArgMatches<'a> {
/// [`Subcommand`]: ./struct..html
/// [`App`]: ./struct.App.html
/// [`ArgMatches`]: ./struct.ArgMatches.html
pub fn subcommand_matches<S: AsRef<str>>(&self, name: S) -> Option<&ArgMatches<'a>> {
pub fn subcommand_matches<T: Key>(&self, id: T) -> Option<&ArgMatches> {
if let Some(ref s) = self.subcommand {
if s.name == name.as_ref() {
if s.id == id.key() {
return Some(&s.matches);
}
}
@ -684,9 +690,7 @@ impl<'a> ArgMatches<'a> {
/// [`Subcommand`]: ./struct..html
/// [`App`]: ./struct.App.html
/// [`ArgMatches`]: ./struct.ArgMatches.html
pub fn subcommand_name(&self) -> Option<&str> {
self.subcommand.as_ref().map(|sc| &sc.name[..])
}
pub fn subcommand_name(&self) -> Option<&str> { self.subcommand.as_ref().map(|sc| &*sc.name) }
/// This brings together [`ArgMatches::subcommand_matches`] and [`ArgMatches::subcommand_name`]
/// by returning a tuple with both pieces of information.
@ -735,7 +739,7 @@ impl<'a> ArgMatches<'a> {
/// ```
/// [`ArgMatches::subcommand_matches`]: ./struct.ArgMatches.html#method.subcommand_matches
/// [`ArgMatches::subcommand_name`]: ./struct.ArgMatches.html#method.subcommand_name
pub fn subcommand(&self) -> (&str, Option<&ArgMatches<'a>>) {
pub fn subcommand(&self) -> (&str, Option<&ArgMatches>) {
self.subcommand
.as_ref()
.map_or(("", None), |sc| (&sc.name[..], Some(&sc.matches)))

View file

@ -27,7 +27,7 @@ impl MatchedArg {
pub(crate) fn contains_val(&self, val: &str) -> bool {
self.vals
.iter()
.map(|v| v.as_os_str())
.map(OsString::as_os_str)
.any(|v| v == OsStr::new(val))
}
}

View file

@ -3,7 +3,9 @@
use yaml_rust::Yaml;
// Internal
use ArgMatches;
use crate::ArgMatches;
type Id = u64;
/// The abstract representation of a command line subcommand.
///
@ -27,9 +29,11 @@ use ArgMatches;
/// [`App`]: ./struct.App.html
/// [arguments]: ./struct.Arg.html
#[derive(Debug, Clone)]
pub struct SubCommand<'a> {
pub struct SubCommand {
#[doc(hidden)]
pub id: Id,
#[doc(hidden)]
pub name: String,
#[doc(hidden)]
pub matches: ArgMatches<'a>,
pub matches: ArgMatches,
}

View file

@ -13,28 +13,30 @@ use std::mem;
use std::os::unix::ffi::OsStrExt;
// Internal
use build::app::Propagation;
use build::AppSettings as AS;
use build::{App, Arg, ArgSettings};
use mkeymap::KeyType;
use output::Help;
use output::Usage;
use parse::errors::Error as ClapError;
use parse::errors::ErrorKind;
use parse::errors::Result as ClapResult;
use parse::features::suggestions;
use parse::Validator;
use parse::{ArgMatcher, SubCommand};
use util::{ChildGraph, OsStrExt2};
use INTERNAL_ERROR_MSG;
use INVALID_UTF8;
use crate::build::app::Propagation;
use crate::build::AppSettings as AS;
use crate::build::{App, Arg, ArgSettings};
use crate::mkeymap::KeyType;
use crate::output::Help;
use crate::output::Usage;
use crate::parse::errors::Error as ClapError;
use crate::parse::errors::ErrorKind;
use crate::parse::errors::Result as ClapResult;
use crate::parse::features::suggestions;
use crate::parse::Validator;
use crate::parse::{ArgMatcher, SubCommand};
use crate::util::{self, ChildGraph, Key, OsStrExt2, EMPTY_HASH};
use crate::INTERNAL_ERROR_MSG;
use crate::INVALID_UTF8;
type Id = u64;
#[derive(Debug, PartialEq, Copy, Clone)]
#[doc(hidden)]
pub enum ParseResult<'a> {
pub enum ParseResult {
Flag,
Opt(&'a str),
Pos(&'a str),
Opt(Id),
Pos(Id),
MaybeHyphenValue,
MaybeNegNum,
NotFound,
@ -42,32 +44,30 @@ pub enum ParseResult<'a> {
}
#[doc(hidden)]
pub struct Parser<'a, 'b, 'c>
pub struct Parser<'b, 'c>
where
'a: 'b,
'b: 'c,
{
pub app: &'c mut App<'a, 'b>,
pub required: ChildGraph<&'a str>,
pub overriden: Vec<&'a str>,
seen: Vec<&'a str>,
pub app: &'c mut App<'b>,
pub required: ChildGraph<Id>,
pub overriden: Vec<Id>,
seen: Vec<Id>,
cur_idx: Cell<usize>,
}
// Initializing Methods
impl<'a, 'b, 'c> Parser<'a, 'b, 'c>
impl<'b, 'c> Parser<'b, 'c>
where
'a: 'b,
'b: 'c,
{
pub fn new(app: &'c mut App<'a, 'b>) -> Self {
pub fn new(app: &'c mut App<'b>) -> Self {
let mut reqs = ChildGraph::with_capacity(5);
for a in app
.args
.args
.iter()
.filter(|a| a.settings.is_set(ArgSettings::Required))
.map(|a| a.name)
.map(|a| a.id)
{
reqs.insert(a);
}
@ -140,7 +140,7 @@ where
// Next we verify that only the highest index has a .multiple(true) (if any)
let only_highest = |a: &Arg| {
a.is_set(ArgSettings::MultipleValues) && (a.index.unwrap_or(0) != highest_idx as u64)
a.is_set(ArgSettings::MultipleValues) && (a.index.unwrap_or(0) != highest_idx)
};
if positionals!(self.app).any(only_highest) {
// First we make sure if there is a positional that allows multiple values
@ -305,7 +305,7 @@ where
// Add args with default requirements
if a.is_set(ArgSettings::Required) {
debugln!("Parser::_build: adding {} to default requires", a.name);
let idx = self.required.insert(a.name);
let idx = self.required.insert(a.id);
// If the arg is required, add all it's requirements to master required list
if let Some(ref areqs) = a.requires {
for name in areqs
@ -338,7 +338,7 @@ where
}) && positionals!(self.app).last().map_or(false, |p_name| {
!self
.app
.find(p_name.name)
.find(p_name.id)
.expect(INTERNAL_ERROR_MSG)
.is_set(ArgSettings::Last)
}) {
@ -347,9 +347,9 @@ where
for group in &self.app.groups {
if group.required {
let idx = self.required.insert(group.name);
let idx = self.required.insert(group.id);
if let Some(ref reqs) = group.requires {
for a in reqs {
for &a in reqs {
self.required.insert_child(idx, a);
}
}
@ -359,16 +359,15 @@ where
}
// Parsing Methods
impl<'a, 'b, 'c> Parser<'a, 'b, 'c>
impl<'b, 'c> Parser<'b, 'c>
where
'a: 'b,
'b: 'c,
{
// The actual parsing function
#[cfg_attr(feature = "lints", allow(while_let_on_iterator, collapsible_if))]
#[allow(clippy::cyclomatic_complexity)]
pub fn get_matches_with<I, T>(
&mut self,
matcher: &mut ArgMatcher<'a>,
matcher: &mut ArgMatcher,
it: &mut Peekable<I>,
) -> ClapResult<()>
where
@ -382,7 +381,7 @@ where
let has_args = self.has_args();
let mut subcmd_name: Option<String> = None;
let mut needs_val_of: ParseResult<'a> = ParseResult::NotFound;
let mut needs_val_of: ParseResult = ParseResult::NotFound;
let mut pos_counter = 1;
while let Some(arg) = it.next() {
let arg_os = arg.into();
@ -474,7 +473,7 @@ where
}
} else if let ParseResult::Opt(name) = needs_val_of {
// Check to see if parsing a value from a previous arg
let arg = self.app.find(&name).expect(INTERNAL_ERROR_MSG);
let arg = self.app.find(name).expect(INTERNAL_ERROR_MSG);
// get the option so we can check the settings
needs_val_of = self.add_val_to_arg(arg, &arg_os, matcher)?;
// get the next value from the iterator
@ -534,7 +533,7 @@ where
if let Some(p) =
positionals!(self.app).find(|p| p.index == Some(pos_counter as u64))
{
ParseResult::Pos(p.name)
ParseResult::Pos(p.id)
} else {
ParseResult::ValuesDone
}
@ -598,12 +597,12 @@ where
{
self.app.settings.set(AS::TrailingValues);
}
self.seen.push(p.name);
self.seen.push(p.id);
let _ = self.add_val_to_arg(p, &arg_os, matcher)?;
matcher.inc_occurrence_of(p.name);
for grp in groups_for_arg!(self.app, &p.name) {
matcher.inc_occurrence_of(&*grp);
matcher.inc_occurrence_of(p.id);
for grp in groups_for_arg!(self.app, p.id) {
matcher.inc_occurrence_of(grp);
}
self.app.settings.set(AS::ValidArgFound);
@ -637,13 +636,15 @@ where
self.app.color(),
));
}
sc_m.add_val_to("", &a);
sc_m.add_val_to(EMPTY_HASH, &a);
}
let id = sc_name.key();
matcher.subcommand(SubCommand {
name: sc_name,
matches: sc_m.into(),
id,
matches: sc_m.into_inner(),
});
break;
} else if !((self.is_set(AS::AllowLeadingHyphen)
|| self.is_set(AS::AllowNegativeNumbers))
&& arg_os.starts_with(b"-"))
@ -748,13 +749,13 @@ where
(false, None)
}
fn parse_help_subcommand<I, T>(&self, it: &mut I) -> ClapResult<ParseResult<'a>>
fn parse_help_subcommand<I, T>(&self, it: &mut I) -> ClapResult<ParseResult>
where
I: Iterator<Item = T>,
T: Into<OsString>,
{
debugln!("Parser::parse_help_subcommand;");
let cmds: Vec<OsString> = it.map(|c| c.into()).collect();
let cmds: Vec<OsString> = it.map(Into::into).collect();
let mut help_help = false;
let mut bin_name = self.app.bin_name.as_ref().unwrap_or(&self.app.name).clone();
let mut sc = {
@ -767,14 +768,17 @@ where
help_help = true;
break; // Maybe?
}
if let Some(id) = find_subcmd!(sc, cmd).map(|x| x.id) {
sc._propagate(Propagation::To(id));
}
if let Some(mut c) = find_subcmd_cloned!(sc, cmd) {
c._build(Propagation::NextLevel);
c._build();
sc = c;
if i == cmds.len() - 1 {
break;
}
} else if let Some(mut c) = find_subcmd_cloned!(sc, &*cmd.to_string_lossy()) {
c._build(Propagation::NextLevel);
c._build();
sc = c;
if i == cmds.len() - 1 {
break;
@ -808,7 +812,7 @@ where
}
// allow wrong self convention due to self.valid_neg_num = true and it's a private method
#[cfg_attr(feature = "lints", allow(wrong_self_convention))]
#[allow(clippy::wrong_self_convention)]
fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult) -> bool {
debugln!("Parser::is_new_arg:{:?}:{:?}", arg_os, needs_val_of);
let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) {
@ -826,11 +830,11 @@ where
};
let arg_allows_tac = match needs_val_of {
ParseResult::Opt(name) => {
let o = self.app.find(&name).expect(INTERNAL_ERROR_MSG);
let o = self.app.find(name).expect(INTERNAL_ERROR_MSG);
(o.is_set(ArgSettings::AllowHyphenValues) || app_wide_settings)
}
ParseResult::Pos(name) => {
let p = self.app.find(&name).expect(INTERNAL_ERROR_MSG);
let p = self.app.find(name).expect(INTERNAL_ERROR_MSG);
(p.is_set(ArgSettings::AllowHyphenValues) || app_wide_settings)
}
ParseResult::ValuesDone => return true,
@ -865,7 +869,7 @@ where
fn parse_subcommand<I, T>(
&mut self,
sc_name: &str,
matcher: &mut ArgMatcher<'a>,
matcher: &mut ArgMatcher,
it: &mut Peekable<I>,
) -> ClapResult<()>
where
@ -883,7 +887,10 @@ where
}
}
mid_string.push_str(" ");
if let Some(ref mut sc) = subcommands_mut!(self.app).find(|s| s.name == sc_name) {
if let Some(id) = find_subcmd!(self.app, sc_name).map(|x| x.id) {
self.app._propagate(Propagation::To(id));
}
if let Some(sc) = subcommands_mut!(self.app).find(|s| s.name == sc_name) {
let mut sc_matcher = ArgMatcher::new();
// bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
// a space
@ -905,16 +912,20 @@ where
));
// Ensure all args are built and ready to parse
sc._build(Propagation::NextLevel);
sc._build();
debugln!("Parser::parse_subcommand: About to parse sc={}", sc.name);
{
let mut p = Parser::new(sc);
p.get_matches_with(&mut sc_matcher, it)?;
}
let name = sc.name.clone();
let mut p = Parser::new(sc);
p.get_matches_with(&mut sc_matcher, it)?;
let sc_id = name.key();
matcher.subcommand(SubCommand {
id: sc_id, // @TODO @maybe: should be sc.id?
name,
matches: sc_matcher.into(),
matches: sc_matcher.into_inner(),
});
}
Ok(())
@ -952,7 +963,7 @@ where
);
// Needs to use app.settings.is_set instead of just is_set() because is_set() checks
// both global and local settings, we only want to check local
if let Some(help) = self.app.find("help") {
if let Some(help) = self.app.find(util::HELP_HASH) {
if let Some(h) = help.short {
if arg == h && !self.app.settings.is_set(AS::NoAutoHelp) {
sdebugln!("Help");
@ -960,7 +971,7 @@ where
}
}
}
if let Some(version) = self.app.find("version") {
if let Some(version) = self.app.find(util::VERSION_HASH) {
if let Some(v) = version.short {
if arg == v && !self.app.settings.is_set(AS::NoAutoVersion) {
sdebugln!("Version");
@ -991,9 +1002,9 @@ where
fn parse_long_arg(
&mut self,
matcher: &mut ArgMatcher<'a>,
matcher: &mut ArgMatcher,
full_arg: &OsStr,
) -> ClapResult<ParseResult<'a>> {
) -> ClapResult<ParseResult> {
// maybe here lifetime should be 'a
debugln!("Parser::parse_long_arg;");
@ -1018,7 +1029,7 @@ where
);
self.app.settings.set(AS::ValidArgFound);
self.seen.push(opt.name);
self.seen.push(opt.id);
if opt.is_set(ArgSettings::TakesValue) {
return Ok(self.parse_opt(val, opt, val.is_some(), matcher)?);
@ -1041,9 +1052,9 @@ where
#[cfg_attr(feature = "lints", allow(len_zero))]
fn parse_short_arg(
&mut self,
matcher: &mut ArgMatcher<'a>,
matcher: &mut ArgMatcher,
full_arg: &OsStr,
) -> ClapResult<ParseResult<'a>> {
) -> ClapResult<ParseResult> {
debugln!("Parser::parse_short_arg: full_arg={:?}", full_arg);
let arg_os = full_arg.trim_left_matches(b'-');
let arg = arg_os.to_string_lossy();
@ -1082,7 +1093,7 @@ where
c
);
self.app.settings.set(AS::ValidArgFound);
self.seen.push(opt.name);
self.seen.push(opt.id);
if !opt.is_set(ArgSettings::TakesValue) {
self.check_for_help_and_version_char(c)?;
ret = self.parse_flag(opt, matcher)?;
@ -1130,10 +1141,10 @@ where
fn parse_opt(
&self,
val: Option<&OsStr>,
opt: &Arg<'a, 'b>,
opt: &Arg<'b>,
had_eq: bool,
matcher: &mut ArgMatcher<'a>,
) -> ClapResult<ParseResult<'a>> {
matcher: &mut ArgMatcher,
) -> ClapResult<ParseResult> {
debugln!("Parser::parse_opt; opt={}, val={:?}", opt.name, val);
debugln!("Parser::parse_opt; opt.settings={:?}", opt.settings);
let mut has_eq = false;
@ -1161,7 +1172,7 @@ where
fv.starts_with(&[b'='])
);
self.add_val_to_arg(opt, v, matcher)?;
} else if needs_eq && !(empty_vals || min_vals_zero) {
} else if needs_eq && !(empty_vals || min_vals_zero) {
sdebugln!("None, but requires equals...Error");
return Err(ClapError::empty_value(
opt,
@ -1172,10 +1183,10 @@ where
sdebugln!("None");
}
matcher.inc_occurrence_of(opt.name);
matcher.inc_occurrence_of(opt.id);
// Increment or create the group "args"
for grp in groups_for_arg!(self.app, &opt.name) {
matcher.inc_occurrence_of(&*grp);
for grp in groups_for_arg!(self.app, opt.id) {
matcher.inc_occurrence_of(grp);
}
let needs_delim = opt.is_set(ArgSettings::RequireDelimiter);
@ -1186,7 +1197,7 @@ where
return Ok(ParseResult::ValuesDone);
} else if no_val || (mult && !needs_delim) && !has_eq && matcher.needs_more_vals(opt) {
debugln!("Parser::parse_opt: More arg vals required...");
return Ok(ParseResult::Opt(opt.name));
return Ok(ParseResult::Opt(opt.id));
}
debugln!("Parser::parse_opt: More arg vals not required...");
Ok(ParseResult::ValuesDone)
@ -1194,10 +1205,10 @@ where
fn add_val_to_arg(
&self,
arg: &Arg<'a, 'b>,
arg: &Arg<'b>,
val: &OsStr,
matcher: &mut ArgMatcher<'a>,
) -> ClapResult<ParseResult<'a>> {
matcher: &mut ArgMatcher,
) -> ClapResult<ParseResult> {
debugln!("Parser::add_val_to_arg; arg={}, val={:?}", arg.name, val);
debugln!(
"Parser::add_val_to_arg; trailing_vals={:?}, DontDelimTrailingVals={:?}",
@ -1231,10 +1242,10 @@ where
fn add_single_val_to_arg(
&self,
arg: &Arg<'a, 'b>,
arg: &Arg<'b>,
v: &OsStr,
matcher: &mut ArgMatcher<'a>,
) -> ClapResult<ParseResult<'a>> {
matcher: &mut ArgMatcher,
) -> ClapResult<ParseResult> {
debugln!("Parser::add_single_val_to_arg;");
debugln!("Parser::add_single_val_to_arg: adding val...{:?}", v);
@ -1248,43 +1259,39 @@ where
}
}
matcher.add_val_to(arg.name, v);
matcher.add_index_to(arg.name, self.cur_idx.get());
matcher.add_val_to(arg.id, v);
matcher.add_index_to(arg.id, self.cur_idx.get());
// Increment or create the group "args"
for grp in groups_for_arg!(self.app, &arg.name) {
matcher.add_val_to(&*grp, v);
for grp in groups_for_arg!(self.app, arg.id) {
matcher.add_val_to(grp, v);
}
if matcher.needs_more_vals(arg) {
return Ok(ParseResult::Opt(arg.name));
return Ok(ParseResult::Opt(arg.id));
}
Ok(ParseResult::ValuesDone)
}
fn parse_flag(
&self,
flag: &Arg<'a, 'b>,
matcher: &mut ArgMatcher<'a>,
) -> ClapResult<ParseResult<'a>> {
fn parse_flag(&self, flag: &Arg<'b>, matcher: &mut ArgMatcher) -> ClapResult<ParseResult> {
debugln!("Parser::parse_flag;");
matcher.inc_occurrence_of(flag.name);
matcher.add_index_to(flag.name, self.cur_idx.get());
matcher.inc_occurrence_of(flag.id);
matcher.add_index_to(flag.id, self.cur_idx.get());
// Increment or create the group "args"
for grp in groups_for_arg!(self.app, &flag.name) {
for grp in groups_for_arg!(self.app, flag.id) {
matcher.inc_occurrence_of(grp);
}
Ok(ParseResult::Flag)
}
fn remove_overrides(&mut self, matcher: &mut ArgMatcher<'a>) {
fn remove_overrides(&mut self, matcher: &mut ArgMatcher) {
debugln!("Parser::remove_overrides;");
let mut to_rem: Vec<&str> = Vec::new();
let mut self_override: Vec<&str> = Vec::new();
let mut to_rem: Vec<Id> = Vec::new();
let mut self_override: Vec<Id> = Vec::new();
let mut arg_overrides = Vec::new();
for name in matcher.arg_names() {
for &name in matcher.arg_names() {
debugln!("Parser::remove_overrides:iter:{};", name);
if let Some(arg) = self.app.find(name) {
let mut handle_self_override = |o| {
@ -1304,34 +1311,34 @@ where
};
if let Some(ref overrides) = arg.overrides {
debugln!("Parser::remove_overrides:iter:{}:{:?};", name, overrides);
for o in overrides {
if o == &arg.name {
for &o in overrides {
if o == arg.id {
if handle_self_override(o) {
continue;
}
} else {
arg_overrides.push((&arg.name, o));
arg_overrides.push((o, &arg.name));
arg_overrides.push((arg.id, o));
arg_overrides.push((o, arg.id));
}
}
}
if self.is_set(AS::AllArgsOverrideSelf) {
let _ = handle_self_override(arg.name);
let _ = handle_self_override(arg.id);
}
}
}
// remove future overrides in reverse seen order
for arg in self.seen.iter().rev() {
for &arg in self.seen.iter().rev() {
for &(a, overr) in arg_overrides.iter().filter(|&&(a, _)| a == arg) {
if !to_rem.contains(a) {
if !to_rem.contains(&a) {
to_rem.push(overr);
}
}
}
// Do self overrides
for name in &self_override {
for &name in &self_override {
debugln!("Parser::remove_overrides:iter:self:{}: resetting;", name);
if let Some(ma) = matcher.get_mut(name) {
if ma.occurs < 2 {
@ -1347,21 +1354,21 @@ where
}
// Finally remove conflicts
for name in &to_rem {
for &name in &to_rem {
debugln!("Parser::remove_overrides:iter:{}: removing;", name);
matcher.remove(name);
self.overriden.push(name);
}
}
pub(crate) fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
pub(crate) fn add_defaults(&mut self, matcher: &mut ArgMatcher) -> ClapResult<()> {
debugln!("Parser::add_defaults;");
macro_rules! add_val {
(@default $_self:ident, $a:ident, $m:ident) => {
if let Some(ref val) = $a.default_val {
debugln!("Parser::add_defaults:iter:{}: has default vals", $a.name);
if $m
.get($a.name)
.get($a.id)
.map(|ma| ma.vals.len())
.map(|len| len == 0)
.unwrap_or(false)
@ -1371,7 +1378,7 @@ where
$a.name
);
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
} else if $m.get($a.name).is_some() {
} else if $m.get($a.id).is_some() {
debugln!(
"Parser::add_defaults:iter:{}: has user defined vals",
$a.name
@ -1392,7 +1399,7 @@ where
if let Some(ref vm) = $a.default_vals_ifs {
sdebugln!(" has conditional defaults");
let mut done = false;
if $m.get($a.name).is_none() {
if $m.get($a.id).is_none() {
for &(arg, val, default) in vm.values() {
let add = if let Some(a) = $m.get(arg) {
if let Some(v) = val {
@ -1432,7 +1439,7 @@ where
Ok(())
}
pub(crate) fn add_env(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
pub(crate) fn add_env(&mut self, matcher: &mut ArgMatcher) -> ClapResult<()> {
for a in self.app.args.args.iter() {
if let Some(ref val) = a.env {
if let Some(ref val) = val.1 {
@ -1445,12 +1452,11 @@ where
}
// Error, Help, and Version Methods
impl<'a, 'b, 'c> Parser<'a, 'b, 'c>
impl<'b, 'c> Parser<'b, 'c>
where
'a: 'b,
'b: 'c,
{
fn did_you_mean_error(&mut self, arg: &str, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
fn did_you_mean_error(&mut self, arg: &str, matcher: &mut ArgMatcher) -> ClapResult<()> {
debugln!("Parser::did_you_mean_error: arg={}", arg);
// Didn't match a flag or option
let longs = self
@ -1475,18 +1481,18 @@ where
// Add the arg to the matches to build a proper usage string
if let Some(ref name) = suffix.1 {
if let Some(opt) = self.app.args.get(&KeyType::Long(OsString::from(name))) {
for g in groups_for_arg!(self.app, &opt.name) {
for g in groups_for_arg!(self.app, opt.id) {
matcher.inc_occurrence_of(g);
}
matcher.insert(&*opt.name);
matcher.insert(opt.id);
}
}
let used: Vec<&str> = matcher
let used: Vec<Id> = matcher
.arg_names()
.filter(|ref n| {
.filter(|n| {
if let Some(a) = self.app.find(**n) {
!(self.required.contains(a.name) || a.is_set(ArgSettings::Hidden))
!(self.required.contains(a.id) || a.is_set(ArgSettings::Hidden))
} else {
true
}
@ -1544,9 +1550,8 @@ where
}
// Query Methods
impl<'a, 'b, 'c> Parser<'a, 'b, 'c>
impl<'b, 'c> Parser<'b, 'c>
where
'a: 'b,
'b: 'c,
{
fn contains_short(&self, s: char) -> bool { self.app.contains_short(s) }

View file

@ -1,31 +1,28 @@
// std
#[allow(unused_imports)]
use std::ascii::AsciiExt;
// Internal
use build::app::AppSettings as AS;
use build::{Arg, ArgSettings};
use output::fmt::{Colorizer, ColorizerOption};
use output::Usage;
use parse::errors::Result as ClapResult;
use parse::errors::{Error, ErrorKind};
use parse::{ArgMatcher, MatchedArg, ParseResult, Parser};
use util::ChildGraph;
use INTERNAL_ERROR_MSG;
use INVALID_UTF8;
use crate::build::app::AppSettings as AS;
use crate::build::{Arg, ArgSettings};
use crate::output::fmt::{Colorizer, ColorizerOption};
use crate::output::Usage;
use crate::parse::errors::Result as ClapResult;
use crate::parse::errors::{Error, ErrorKind};
use crate::parse::{ArgMatcher, MatchedArg, ParseResult, Parser};
use crate::util::ChildGraph;
use crate::INTERNAL_ERROR_MSG;
use crate::INVALID_UTF8;
pub struct Validator<'a, 'b, 'c, 'z>
type Id = u64;
pub struct Validator<'b, 'c, 'z>
where
'a: 'b,
'b: 'c,
'c: 'z,
{
p: &'z mut Parser<'a, 'b, 'c>,
c: ChildGraph<&'a str>,
p: &'z mut Parser<'b, 'c>,
c: ChildGraph<Id>,
}
impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
pub fn new(p: &'z mut Parser<'a, 'b, 'c>) -> Self {
impl<'b, 'c, 'z> Validator<'b, 'c, 'z> {
pub fn new(p: &'z mut Parser<'b, 'c>) -> Self {
Validator {
p,
c: ChildGraph::with_capacity(5),
@ -34,9 +31,9 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
pub fn validate(
&mut self,
needs_val_of: ParseResult<'a>,
needs_val_of: ParseResult,
subcmd_name: &Option<String>,
matcher: &mut ArgMatcher<'a>,
matcher: &mut ArgMatcher,
) -> ClapResult<()> {
debugln!("Validator::validate;");
let mut reqs_validated = false;
@ -47,9 +44,9 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
{
self.validate_required(matcher)?;
}
let o = self.p.app.find(&a).expect(INTERNAL_ERROR_MSG);
let o = self.p.app.find(a).expect(INTERNAL_ERROR_MSG);
reqs_validated = true;
let should_err = if let Some(v) = matcher.0.args.get(&*o.name) {
let should_err = if let Some(v) = matcher.0.args.get(&o.id) {
v.vals.is_empty() && !(o.min_vals.is_some() && o.min_vals.unwrap() == 0)
} else {
true
@ -89,7 +86,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
&self,
arg: &Arg,
ma: &MatchedArg,
matcher: &ArgMatcher<'a>,
matcher: &ArgMatcher,
) -> ClapResult<()> {
debugln!("Validator::validate_arg_values: arg={:?}", arg.name);
for val in &ma.vals {
@ -112,11 +109,11 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
p_vals.contains(&&*val_str)
};
if !ok {
let used: Vec<&str> = matcher
let used: Vec<Id> = matcher
.arg_names()
.filter(|ref n| {
if let Some(a) = self.p.app.find(**n) {
!(self.p.required.contains(a.name) || a.is_set(ArgSettings::Hidden))
.filter(|&&n| {
if let Some(a) = self.p.app.find(n) {
!(self.p.required.contains(a.id) || a.is_set(ArgSettings::Hidden))
} else {
true
}
@ -134,7 +131,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
}
if !arg.is_set(ArgSettings::AllowEmptyValues)
&& val.is_empty()
&& matcher.contains(&*arg.name)
&& matcher.contains(arg.id)
{
debugln!("Validator::validate_arg_values: illegal empty val found");
return Err(Error::empty_value(
@ -169,11 +166,11 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
Ok(())
}
fn build_conflict_err(&self, name: &str, matcher: &ArgMatcher<'a>) -> ClapResult<()> {
fn build_conflict_err(&self, name: Id, matcher: &ArgMatcher) -> ClapResult<()> {
debugln!("build_err!: name={}", name);
let usg = Usage::new(self.p).create_usage_with_title(&[]);
if self.p.app.find(name).is_some() {
for k in matcher.arg_names() {
for &k in matcher.arg_names() {
if let Some(a) = self.p.app.find(k) {
if let Some(ref v) = a.blacklist {
if v.contains(&name) {
@ -187,8 +184,8 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
}
}
}
} else if let Some(g) = self.p.app.groups.iter().find(|x| x.name == name) {
let args_in_group = self.p.app.unroll_args_in_group(g.name);
} else if let Some(g) = self.p.app.groups.iter().find(|x| x.id == name) {
let args_in_group = self.p.app.unroll_args_in_group(g.id);
let first = matcher
.arg_names()
.find(|x| args_in_group.contains(x))
@ -196,10 +193,10 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
let c_with = matcher
.arg_names()
.find(|x| x != &first && args_in_group.contains(x))
.map(|x| self.p.app.find(x).expect(INTERNAL_ERROR_MSG).to_string());
.map(|&x| self.p.app.find(x).expect(INTERNAL_ERROR_MSG).to_string());
debugln!("build_err!:c_with={:?}:group", c_with);
return Err(Error::argument_conflict(
self.p.app.find(first).expect(INTERNAL_ERROR_MSG),
self.p.app.find(*first).expect(INTERNAL_ERROR_MSG),
c_with,
&*usg,
self.p.app.color(),
@ -209,7 +206,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
panic!(INTERNAL_ERROR_MSG);
}
fn validate_conflicts(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
fn validate_conflicts(&mut self, matcher: &mut ArgMatcher) -> ClapResult<()> {
debugln!("Validator::validate_conflicts;");
self.gather_conflicts(matcher);
for name in self.c.iter() {
@ -221,31 +218,31 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
.groups
.iter()
.filter(|g| !g.multiple)
.find(|g| &g.name == name)
.find(|g| &g.id == name)
{
let conf_with_self = self
.p
.app
.unroll_args_in_group(g.name)
.unroll_args_in_group(g.id)
.iter()
.filter(|a| matcher.contains(a))
.filter(|&&a| matcher.contains(a))
.count()
> 1;
let conf_with_arg = if let Some(ref c) = g.conflicts {
c.iter().any(|x| matcher.contains(x))
c.iter().any(|&x| matcher.contains(x))
} else {
false
};
let arg_conf_with_gr = matcher
.arg_names()
.filter_map(|x| self.p.app.find(x))
.filter_map(|&x| self.p.app.find(x))
.filter_map(|x| x.blacklist.as_ref())
.any(|c| c.iter().any(|c| c == &g.name));
.any(|c| c.iter().any(|&c| c == g.id));
should_err = conf_with_self || conf_with_arg || arg_conf_with_gr;
} else if let Some(ma) = matcher.get(name) {
} else if let Some(ma) = matcher.get(*name) {
debugln!(
"Validator::validate_conflicts:iter:{}: matcher contains it...",
name
@ -261,14 +258,14 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
// Gathers potential conflicts based on used argument, but without considering requirements
// and such
fn gather_conflicts(&mut self, matcher: &mut ArgMatcher<'a>) {
fn gather_conflicts(&mut self, matcher: &mut ArgMatcher) {
debugln!("Validator::gather_conflicts;");
for name in matcher.arg_names() {
for &name in matcher.arg_names() {
debugln!("Validator::gather_conflicts:iter:{};", name);
if let Some(arg) = self.p.app.find(name) {
// Since an arg was used, every arg it conflicts with is added to the conflicts
if let Some(ref bl) = arg.blacklist {
for conf in bl {
for &conf in bl {
if self.p.app.find(conf).is_some() {
if conf != name {
self.c.insert(conf);
@ -292,11 +289,11 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
.groups
.iter()
.filter(|g| !g.multiple)
.find(|g| g.name == grp)
.find(|g| g.id == grp)
{
// for g_arg in self.p.app.unroll_args_in_group(&g.name) {
// if &g_arg != name {
self.c.insert(g.name);
self.c.insert(g.id);
// }
// }
}
@ -307,26 +304,26 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
.groups
.iter()
.filter(|g| !g.multiple)
.find(|grp| &grp.name == name)
.find(|grp| grp.id == name)
{
debugln!("Validator::gather_conflicts:iter:{}:group;", name);
self.c.insert(g.name);
self.c.insert(g.id);
}
}
}
fn gather_requirements(&mut self, matcher: &ArgMatcher<'a>) {
fn gather_requirements(&mut self, matcher: &ArgMatcher) {
debugln!("Validator::gather_requirements;");
for name in matcher.arg_names() {
for &name in matcher.arg_names() {
debugln!("Validator::gather_requirements:iter:{};", name);
if let Some(arg) = self.p.app.find(name) {
for req in self.p.app.unroll_requirements_for_arg(arg.name, matcher) {
for req in self.p.app.unroll_requirements_for_arg(arg.id, matcher) {
self.p.required.insert(req);
}
} else if let Some(g) = self.p.app.groups.iter().find(|grp| &grp.name == name) {
} else if let Some(g) = self.p.app.groups.iter().find(|grp| grp.id == name) {
debugln!("Validator::gather_conflicts:iter:{}:group;", name);
if let Some(ref reqs) = g.requires {
for r in reqs {
for &r in reqs {
self.p.required.insert(r);
}
}
@ -334,9 +331,9 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
}
}
fn validate_matched_args(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
fn validate_matched_args(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
debugln!("Validator::validate_matched_args;");
for (name, ma) in matcher.iter() {
for (&name, ma) in matcher.iter() {
debugln!(
"Validator::validate_matched_args:iter:{}: vals={:#?}",
name,
@ -353,7 +350,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
.app
.groups
.iter()
.find(|g| &g.name == name)
.find(|g| g.id == name)
.expect(INTERNAL_ERROR_MSG);
if let Some(ref g_reqs) = grp.requires {
if g_reqs.iter().any(|&n| !matcher.contains(n)) {
@ -366,7 +363,11 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
}
fn validate_arg_num_occurs(&self, a: &Arg, ma: &MatchedArg) -> ClapResult<()> {
debugln!("Validator::validate_arg_num_occurs: a={};", a.name);
debugln!(
"Validator::validate_arg_num_occurs: {}={};",
a.name,
ma.occurs
);
if ma.occurs > 1 && !a.is_set(ArgSettings::MultipleOccurrences) {
// Not the first time, and we don't allow multiples
return Err(Error::unexpected_multiple_usage(
@ -457,9 +458,9 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
fn validate_arg_requires(
&self,
a: &Arg<'a, 'b>,
a: &Arg<'b>,
ma: &MatchedArg,
matcher: &ArgMatcher<'a>,
matcher: &ArgMatcher,
) -> ClapResult<()> {
debugln!("Validator::validate_arg_requires:{};", a.name);
if let Some(ref a_reqs) = a.requires {
@ -467,7 +468,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
let missing_req =
|v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name);
if ma.vals.iter().any(missing_req) {
return self.missing_required_error(matcher, Some(a.name));
return self.missing_required_error(matcher, Some(a.id));
}
}
for &(_, name) in a_reqs.iter().filter(|&&(val, _)| val.is_none()) {
@ -479,26 +480,26 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
Ok(())
}
fn validate_required(&mut self, matcher: &ArgMatcher<'a>) -> ClapResult<()> {
fn validate_required(&mut self, matcher: &ArgMatcher) -> ClapResult<()> {
debugln!(
"Validator::validate_required: required={:?};",
self.p.required
);
self.gather_requirements(matcher);
for arg_or_group in self.p.required.iter().filter(|r| !matcher.contains(r)) {
for &arg_or_group in self.p.required.iter().filter(|&&r| !matcher.contains(r)) {
debugln!("Validator::validate_required:iter:aog={:?};", arg_or_group);
if let Some(arg) = self.p.app.find(arg_or_group) {
if !self.is_missing_required_ok(arg, matcher) {
return self.missing_required_error(matcher, None);
}
} else if let Some(group) = self.p.app.groups.iter().find(|g| &g.name == arg_or_group) {
} else if let Some(group) = self.p.app.groups.iter().find(|g| g.id == arg_or_group) {
if !self
.p
.app
.unroll_args_in_group(group.name)
.unroll_args_in_group(group.id)
.iter()
.any(|a| matcher.contains(a))
.any(|&a| matcher.contains(a))
{
return self.missing_required_error(matcher, None);
}
@ -516,9 +517,9 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
.map(|a| (a, a.r_ifs.as_ref().unwrap()))
{
for (other, val) in r_ifs.iter() {
if let Some(ma) = matcher.get(other) {
if ma.contains_val(val) && !matcher.contains(a.name) {
return self.missing_required_error(matcher, Some(a.name));
if let Some(ma) = matcher.get(*other) {
if ma.contains_val(val) && !matcher.contains(a.id) {
return self.missing_required_error(matcher, Some(a.id));
}
}
}
@ -526,31 +527,31 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
Ok(())
}
fn is_missing_required_ok(&self, a: &Arg<'a, 'b>, matcher: &ArgMatcher<'a>) -> bool {
fn is_missing_required_ok(&self, a: &Arg<'b>, matcher: &ArgMatcher) -> bool {
debugln!("Validator::is_missing_required_ok: {}", a.name);
self.validate_arg_conflicts(a, matcher) || self.p.overriden.contains(&a.name)
self.validate_arg_conflicts(a, matcher) || self.p.overriden.contains(&a.id)
}
fn validate_arg_conflicts(&self, a: &Arg<'a, 'b>, matcher: &ArgMatcher<'a>) -> bool {
fn validate_arg_conflicts(&self, a: &Arg<'b>, matcher: &ArgMatcher) -> bool {
debugln!("Validator::validate_arg_conflicts: a={:?};", a.name);
a.blacklist
.as_ref()
.map(|bl| {
bl.iter().any(|ref conf| {
bl.iter().any(|&conf| {
matcher.contains(conf)
|| self
.p
.app
.groups
.iter()
.find(|g| &g.name == *conf)
.map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
.find(|g| g.id == conf)
.map_or(false, |g| g.args.iter().any(|&arg| matcher.contains(arg)))
})
})
.unwrap_or(false)
}
fn validate_required_unless(&self, matcher: &ArgMatcher<'a>) -> ClapResult<()> {
fn validate_required_unless(&self, matcher: &ArgMatcher) -> ClapResult<()> {
debugln!("Validator::validate_required_unless;");
for a in self
.p
@ -559,11 +560,11 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
.args
.iter()
.filter(|a| a.r_unless.is_some())
.filter(|a| !matcher.contains(a.name))
.filter(|a| !matcher.contains(a.id))
{
debugln!("Validator::validate_required_unless:iter:{};", a.name);
if self.fails_arg_required_unless(a, matcher) {
return self.missing_required_error(matcher, Some(a.name));
return self.missing_required_error(matcher, Some(a.id));
}
}
@ -571,13 +572,13 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
}
// Failing a required unless means, the arg's "unless" wasn't present, and neither were they
fn fails_arg_required_unless(&self, a: &Arg<'a, 'b>, matcher: &ArgMatcher<'a>) -> bool {
fn fails_arg_required_unless(&self, a: &Arg<'b>, matcher: &ArgMatcher) -> bool {
debugln!("Validator::fails_arg_required_unless: a={:?};", a.name);
macro_rules! check {
($how:ident, $_self:expr, $a:ident, $m:ident) => {{
$a.r_unless
.as_ref()
.map(|ru| !ru.iter().$how(|n| $m.contains(n)))
.map(|ru| !ru.iter().$how(|&n| $m.contains(n)))
.unwrap_or(false)
}};
}
@ -591,11 +592,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
}
// `incl`: an arg to include in the error even if not used
fn missing_required_error(
&self,
matcher: &ArgMatcher<'a>,
incl: Option<&str>,
) -> ClapResult<()> {
fn missing_required_error(&self, matcher: &ArgMatcher, incl: Option<Id>) -> ClapResult<()> {
debugln!("Validator::missing_required_error; incl={:?}", incl);
let c = Colorizer::new(&ColorizerOption {
use_stderr: true,
@ -623,11 +620,11 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> {
"Validator::missing_required_error: req_args={:#?}",
req_args
);
let used: Vec<&str> = matcher
let used: Vec<Id> = matcher
.arg_names()
.filter(|ref n| {
if let Some(a) = self.p.app.find(**n) {
!(self.p.required.contains(a.name) || a.is_set(ArgSettings::Hidden))
.filter(|&&n| {
if let Some(a) = self.p.app.find(n) {
!(self.p.required.contains(a.id) || a.is_set(ArgSettings::Hidden))
} else {
true
}

42
src/util/fnv.rs Normal file
View file

@ -0,0 +1,42 @@
use std::hash::{Hash, Hasher};
// precompute some common values
pub static HELP_HASH: u64 = 0x5963_6393_CFFB_FE5F;
pub static VERSION_HASH: u64 = 0x30FF_0B7C_4D07_9478;
pub static EMPTY_HASH: u64 = 0x1C9D_3ADB_639F_298E;
const MAGIC_INIT: u64 = 0x811C_9DC5;
pub trait Key: Hash {
fn key(&self) -> u64;
}
impl<T> Key for T
where
T: Hash,
{
fn key(&self) -> u64 {
let mut hasher = FnvHasher::new();
self.hash(&mut hasher);
hasher.finish()
}
}
pub(crate) struct FnvHasher(u64);
impl FnvHasher {
pub(crate) fn new() -> Self { FnvHasher(MAGIC_INIT) }
}
impl Hasher for FnvHasher {
fn finish(&self) -> u64 { self.0 }
fn write(&mut self, bytes: &[u8]) {
let FnvHasher(mut hash) = *self;
for byte in bytes.iter() {
hash ^= u64::from(*byte);
hash = hash.wrapping_mul(0x100000001b3);
}
*self = FnvHasher(hash);
}
}

View file

@ -1,8 +1,10 @@
mod fnv;
mod graph;
mod map;
mod osstringext;
mod strext;
pub use self::fnv::{Key, EMPTY_HASH, HELP_HASH, VERSION_HASH};
pub use self::graph::ChildGraph;
pub use self::map::{Values, VecMap};
pub use self::osstringext::OsStrExt2;

View file

@ -6,7 +6,7 @@ mod tests {
include!("../clap-test.rs");
use clap::{App, Arg};
fn get_app() -> App<'static, 'static> {
fn get_app() -> App<'static> {
App::new("myprog")
.arg(
Arg::with_name("GLOBAL_ARG")

View file

@ -215,3 +215,12 @@ fn group_multiple_args_error() {
let err = result.unwrap_err();
assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}
#[test]
fn group_acts_like_arg() {
let m = App::new("prog")
.arg(Arg::with_name("debug").long("debug").group("mode"))
.arg(Arg::with_name("verbose").long("verbose").group("mode"))
.get_matches_from(vec!["prog", "--debug"]);
assert!(m.is_present("mode"));
}

View file

@ -532,7 +532,7 @@ OPTIONS:
NETWORKING:
-n, --no-proxy Do not use system proxy settings";
fn setup() -> App<'static, 'static> {
fn setup() -> App<'static> {
App::new("test")
.author("Kevin K.")
.about("tests stuff")
@ -1224,7 +1224,7 @@ fn hidden_default_val() {
));
}
fn issue_1112_setup() -> App<'static, 'static> {
fn issue_1112_setup() -> App<'static> {
App::new("test")
.author("Kevin K.")
.about("tests stuff")

View file

@ -254,7 +254,7 @@ fn group_macro_set_not_required() {
#[test]
fn arg_enum() {
arg_enum!{
arg_enum! {
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Greek {
Alpha,
@ -266,7 +266,7 @@ fn arg_enum() {
#[test]
fn arg_enum_trailing_comma() {
arg_enum!{
arg_enum! {
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Greek {
Alpha,

View file

@ -396,7 +396,7 @@ fn issue_1047_min_zero_vals_default_val() {
assert_eq!(m.value_of("del"), Some("default"));
}
fn issue_1105_setup(argv: Vec<&'static str>) -> Result<ArgMatches<'static>, clap::Error> {
fn issue_1105_setup(argv: Vec<&'static str>) -> Result<ArgMatches, clap::Error> {
App::new("opts")
.arg(Arg::from("-o, --option [opt] 'some option'").setting(ArgSettings::AllowEmptyValues))
.arg(Arg::from("--flag 'some flag'"))

View file

@ -6,7 +6,7 @@ mod tests {
include!("../clap-test.rs");
use clap::{App, Arg, ArgMatches, ArgSettings};
fn get_app() -> App<'static, 'static> {
fn get_app() -> App<'static> {
App::new("myprog")
.arg(
Arg::with_name("GLOBAL_ARG")
@ -26,49 +26,43 @@ mod tests {
.subcommand(App::new("outer").subcommand(App::new("inner")))
}
fn get_matches(app: App<'static, 'static>, argv: &'static str) -> ArgMatches<'static> {
fn get_matches(app: App<'static>, argv: &'static str) -> ArgMatches {
app.get_matches_from(argv.split(" ").collect::<Vec<_>>())
}
fn get_outer_matches<'a>(m: &'a ArgMatches<'static>) -> &'a ArgMatches<'static> {
fn get_outer_matches<'a>(m: &'a ArgMatches) -> &'a ArgMatches {
m.subcommand_matches("outer")
.expect("could not access outer subcommand")
}
fn get_inner_matches<'a>(m: &'a ArgMatches<'static>) -> &'a ArgMatches<'static> {
fn get_inner_matches<'a>(m: &'a ArgMatches) -> &'a ArgMatches {
get_outer_matches(m)
.subcommand_matches("inner")
.expect("could not access inner subcommand")
}
fn top_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches<'static>, val: T) -> bool {
fn top_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches, val: T) -> bool {
m.value_of("GLOBAL_ARG") == val.into()
}
fn inner_can_access_arg<T: Into<Option<&'static str>>>(
m: &ArgMatches<'static>,
val: T,
) -> bool {
fn inner_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches, val: T) -> bool {
get_inner_matches(m).value_of("GLOBAL_ARG") == val.into()
}
fn outer_can_access_arg<T: Into<Option<&'static str>>>(
m: &ArgMatches<'static>,
val: T,
) -> bool {
fn outer_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches, val: T) -> bool {
get_outer_matches(m).value_of("GLOBAL_ARG") == val.into()
}
fn top_can_access_flag(m: &ArgMatches<'static>, present: bool, occurrences: u64) -> bool {
fn top_can_access_flag(m: &ArgMatches, present: bool, occurrences: u64) -> bool {
(m.is_present("GLOBAL_FLAG") == present) && (m.occurrences_of("GLOBAL_FLAG") == occurrences)
}
fn inner_can_access_flag(m: &ArgMatches<'static>, present: bool, occurrences: u64) -> bool {
fn inner_can_access_flag(m: &ArgMatches, present: bool, occurrences: u64) -> bool {
let m = get_inner_matches(m);
(m.is_present("GLOBAL_FLAG") == present) && (m.occurrences_of("GLOBAL_FLAG") == occurrences)
}
fn outer_can_access_flag(m: &ArgMatches<'static>, present: bool, occurrences: u64) -> bool {
fn outer_can_access_flag(m: &ArgMatches, present: bool, occurrences: u64) -> bool {
let m = get_outer_matches(m);
(m.is_present("GLOBAL_FLAG") == present) && (m.occurrences_of("GLOBAL_FLAG") == occurrences)
}

View file

@ -671,7 +671,7 @@ USAGE:
For more information try --help";
fn issue_1158_app() -> App<'static, 'static> {
fn issue_1158_app() -> App<'static> {
App::new("example")
.arg(
Arg::from("-c, --config [FILE] 'Custom config file.'")

View file

@ -128,7 +128,7 @@ fn template_author_version() {
// ----------
fn app_example1<'b, 'c>() -> App<'b, 'c> {
fn app_example1<'b, 'c>() -> App<'c> {
App::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")

View file

@ -224,27 +224,27 @@ pub fn check_complex_output(args: &str, out: &str) {
assert_eq!(res, out);
}
arg_enum!{
arg_enum! {
#[derive(Debug)]
enum Val1 {
ValOne,
ValTwo
}
}
arg_enum!{
arg_enum! {
#[derive(Debug)]
pub enum Val2 {
ValOne,
ValTwo
}
}
arg_enum!{
arg_enum! {
enum Val3 {
ValOne,
ValTwo
}
}
arg_enum!{
arg_enum! {
pub enum Val4 {
ValOne,
ValTwo

19
v3_occ_vs_vals.md Normal file
View file

@ -0,0 +1,19 @@
# Flags
-f?
-f*
-f{$0,3}: flags can't be required by default, hence always 0 or more (bounded/unbounded)
# Options
-o val
-o val?
-o val*
-o val+
-o val{0,3}
(-o val){0,3}
(-o val?){0,3}
(-o val*){0,3}
(-o val+){0,3}
(-o val{0,3}){0,3}

81
v3_warn_cases.md Normal file
View file

@ -0,0 +1,81 @@
These are cases which could be detected by `clap`, and potentially warn at compile time. Maybe even with a nice web URL to more info.
# Abrv. Syntax
First, a little about the syntax to understand the setup of rule. This syntax will make each rule more concise so we don't have to write an entire `clap` definition.
## Arg Types
* `--opt` is an option
* `--flag` is a flag
* `#` (i.e. `1` or `2`) is a positional argument
* `val` is an option value
## Modifiers
Can be used on `val` or Arg types
* `*`: zero or more
* `+`: one or more
* `?`: zero or one
* `{#,#}`: # to # times (i.e. `{1,4}` is one to four times)
* `<>`: required
* `=`: requires equals
* Ends in `,`: requires delimiter
* `(foo,bar)`: values can only be `foo` or `bar`
# --opt val? 1
## Ambiguous Uses
```
$ prog --opt foo
# is foo option val or positional?
```
## Non-Ambiguous Uses
```
$ prog 1 --opt
$ prog --opt -- 1
```
## Fixes
### Require equals on `--opt`
```
$ prog --opt foo
# foo is positional
$ prog --opt=val foo
```
# --opt val+ 1
## Ambiguous Uses
```
$ prog --opt foo bar
# is bar option val or positional?
```
## Non-Ambiguous Uses
```
$ prog 1 --opt val
$ prog --opt val -- 1
```
## Fixes
### `--opt` only one val per occurrence
```
$ prog --opt foo bar
# bar is positional
$ prog --opt val bar --opt foo
# bar is positional
```