mirror of
https://github.com/clap-rs/clap
synced 2025-03-04 23:37:32 +00:00
commit
388f162646
42 changed files with 1031 additions and 770 deletions
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,7 +4,7 @@ clap
|
|||
[](https://crates.io/crates/clap) [](https://crates.io/crates/clap) [](https://github.com/clap-rs/clap/blob/master/LICENSE-APACHE) [](https://github.com/clap-rs/clap/blob/master/LICENSE-MIT) [](https://coveralls.io/github/clap-rs/clap?branch=master) [](https://gitter.im/clap-rs/clap?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
Linux: [](https://travis-ci.org/clap-rs/clap)
|
||||
Windows: [](https://ci.appveyor.com/project/clap-rs/clap/branch/master)
|
||||
Windows: [](https://ci.appveyor.com/project/kbknapp/clap-rs/branch/master)
|
||||
|
||||
Command Line Argument Parser for Rust
|
||||
|
||||
|
|
20
SPONSORS.md
20
SPONSORS.md
|
@ -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| | |
|
|
@ -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");
|
||||
|
|
|
@ -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\")")
|
||||
|
|
|
@ -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,
|
||||
{
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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() {
|
||||
|
|
27
src/lib.rs
27
src/lib.rs
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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" => {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
@ -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
|
||||
///
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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
42
src/util/fnv.rs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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'"))
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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.'")
|
||||
|
|
|
@ -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>")
|
||||
|
|
|
@ -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
19
v3_occ_vs_vals.md
Normal 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
81
v3_warn_cases.md
Normal 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
|
||||
```
|
||||
|
Loading…
Add table
Reference in a new issue