diff --git a/.gitignore b/.gitignore
index 11101efcfb3..34253e90833 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,4 @@ Cargo.lock
# Project files
.vscode/*
+.idea/*
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 43a9a897a0c..03431f23b2d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,24 @@
+
+### 2.29.1 (2018-01-09)
+
+
+#### Documentation
+
+* fixes broken links. ([56e734b8](https://github.com/kbknapp/clap-rs/commit/56e734b839303d733d2e5baf7dac39bd7b97b8e4))
+* updates contributors list ([e1313a5a](https://github.com/kbknapp/clap-rs/commit/e1313a5a0f69d8f4016f73b860a63af8318a6676))
+
+#### Performance
+
+* further debloating by removing generics from error cases ([eb8d919e](https://github.com/kbknapp/clap-rs/commit/eb8d919e6f3443db279ba0c902f15d76676c02dc))
+* debloats clap by deduplicating logic and refactors ([03e413d7](https://github.com/kbknapp/clap-rs/commit/03e413d7175d35827cd7d8908d47dbae15a849a3))
+
+#### Bug Fixes
+
+* fixes the ripgrep benchmark by adding a value to a flag that expects it ([d26ab2b9](https://github.com/kbknapp/clap-rs/commit/d26ab2b97cf9c0ea675b440b7b0eaf6ac3ad01f4))
+* **bash completion:** Change the bash completion script code generation to support hyphens. ([ba7f1d18](https://github.com/kbknapp/clap-rs/commit/ba7f1d18eba7a07ce7f57e0981986f66c994b639))
+* **completions/zsh.rs:** Fix completion of long option values ([46365cf8](https://github.com/kbknapp/clap-rs/commit/46365cf8be5331ba04c895eb183e2f230b5aad51))
+
+
## 2.29.0 (2017-12-02)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index d6b83808a6c..c4f238597bf 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -17,69 +17,69 @@ the following is a list of contributors:
:---: |:---: |:---: |:---: |:---: |:---: |
[Arnavion](https://github.com/Arnavion) |[japaric](https://github.com/japaric) |[untitaker](https://github.com/untitaker) |[afiune](https://github.com/afiune) |[crazymerlyn](https://github.com/crazymerlyn) |[SuperFluffy](https://github.com/SuperFluffy) |
-[](https://github.com/malbarbo) |[](https://github.com/matthiasbeyer) |[](https://github.com/gohyda) |[](https://github.com/tshepang) |[](https://github.com/golem131) |[](https://github.com/jimmycuadra) |
+[](https://github.com/matthiasbeyer) |[](https://github.com/malbarbo) |[](https://github.com/tshepang) |[](https://github.com/golem131) |[](https://github.com/jimmycuadra) |[](https://github.com/Nemo157) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[malbarbo](https://github.com/malbarbo) |[matthiasbeyer](https://github.com/matthiasbeyer) |[gohyda](https://github.com/gohyda) |[tshepang](https://github.com/tshepang) |[golem131](https://github.com/golem131) |[jimmycuadra](https://github.com/jimmycuadra) |
+[matthiasbeyer](https://github.com/matthiasbeyer) |[malbarbo](https://github.com/malbarbo) |[tshepang](https://github.com/tshepang) |[golem131](https://github.com/golem131) |[jimmycuadra](https://github.com/jimmycuadra) |[Nemo157](https://github.com/Nemo157) |
-[](https://github.com/Nemo157) |[](https://github.com/SShrike) |[](https://github.com/Eijebong) |[](https://github.com/cstorey) |[](https://github.com/wdv4758h) |[](https://github.com/frewsxcv) |
+[](https://github.com/severen) |[](https://github.com/Eijebong) |[](https://github.com/cstorey) |[](https://github.com/wdv4758h) |[](https://github.com/frewsxcv) |[](https://github.com/hoodie) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[Nemo157](https://github.com/Nemo157) |[SShrike](https://github.com/SShrike) |[Eijebong](https://github.com/Eijebong) |[cstorey](https://github.com/cstorey) |[wdv4758h](https://github.com/wdv4758h) |[frewsxcv](https://github.com/frewsxcv) |
+[severen](https://github.com/severen) |[Eijebong](https://github.com/Eijebong) |[cstorey](https://github.com/cstorey) |[wdv4758h](https://github.com/wdv4758h) |[frewsxcv](https://github.com/frewsxcv) |[hoodie](https://github.com/hoodie) |
-[](https://github.com/hoodie) |[](https://github.com/huonw) |[](https://github.com/GrappigPanda) |[](https://github.com/shepmaster) |[](https://github.com/porglezomp) |[](https://github.com/kieraneglin) |
+[](https://github.com/huonw) |[](https://github.com/GrappigPanda) |[](https://github.com/shepmaster) |[](https://github.com/porglezomp) |[](https://github.com/kieraneglin) |[](https://github.com/musoke) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |[GrappigPanda](https://github.com/GrappigPanda) |[shepmaster](https://github.com/shepmaster) |[porglezomp](https://github.com/porglezomp) |[kieraneglin](https://github.com/kieraneglin) |
+[huonw](https://github.com/huonw) |[GrappigPanda](https://github.com/GrappigPanda) |[shepmaster](https://github.com/shepmaster) |[porglezomp](https://github.com/porglezomp) |[kieraneglin](https://github.com/kieraneglin) |[musoke](https://github.com/musoke) |
-[](https://github.com/musoke) |[](https://github.com/nelsonjchen) |[](https://github.com/pkgw) |[](https://github.com/Deedasmi) |[](https://github.com/vmchale) |[](https://github.com/messense) |
+[](https://github.com/nelsonjchen) |[](https://github.com/pkgw) |[](https://github.com/Deedasmi) |[](https://github.com/vmchale) |[](https://github.com/messense) |[](https://github.com/Keats) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[musoke](https://github.com/musoke) |[nelsonjchen](https://github.com/nelsonjchen) |[pkgw](https://github.com/pkgw) |[Deedasmi](https://github.com/Deedasmi) |[vmchale](https://github.com/vmchale) |[messense](https://github.com/messense) |
+[nelsonjchen](https://github.com/nelsonjchen) |[pkgw](https://github.com/pkgw) |[Deedasmi](https://github.com/Deedasmi) |[vmchale](https://github.com/vmchale) |[messense](https://github.com/messense) |[Keats](https://github.com/Keats) |
-[](https://github.com/Keats) |[](https://github.com/starkat99) |[](https://github.com/durka) |[](https://github.com/alex-gulyas) |[](https://github.com/cite-reader) |[](https://github.com/alexbool) |
+[](https://github.com/starkat99) |[](https://github.com/durka) |[](https://github.com/alex-gulyas) |[](https://github.com/cite-reader) |[](https://github.com/alexbool) |[](https://github.com/AluisioASG) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[Keats](https://github.com/Keats) |[starkat99](https://github.com/starkat99) |[durka](https://github.com/durka) |[alex-gulyas](https://github.com/alex-gulyas) |[cite-reader](https://github.com/cite-reader) |[alexbool](https://github.com/alexbool) |
+[starkat99](https://github.com/starkat99) |[durka](https://github.com/durka) |[alex-gulyas](https://github.com/alex-gulyas) |[cite-reader](https://github.com/cite-reader) |[alexbool](https://github.com/alexbool) |[AluisioASG](https://github.com/AluisioASG) |
-[](https://github.com/AluisioASG) |[](https://github.com/BurntSushi) |[](https://github.com/nox) |[](https://github.com/pixelistik) |[](https://github.com/brennie) |[](https://github.com/ogham) |
+[](https://github.com/BurntSushi) |[](https://github.com/nox) |[](https://github.com/mitsuhiko) |[](https://github.com/brennie) |[](https://github.com/ogham) |[](https://github.com/pixelistik) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[AluisioASG](https://github.com/AluisioASG) |[BurntSushi](https://github.com/BurntSushi) |[nox](https://github.com/nox) |[pixelistik](https://github.com/pixelistik) |[brennie](https://github.com/brennie) |[ogham](https://github.com/ogham) |
+[BurntSushi](https://github.com/BurntSushi) |[nox](https://github.com/nox) |[mitsuhiko](https://github.com/mitsuhiko) |[brennie](https://github.com/brennie) |[ogham](https://github.com/ogham) |[pixelistik](https://github.com/pixelistik) |
-[](https://github.com/Bilalh) |[](https://github.com/dotdash) |[](https://github.com/bradurani) |[](https://github.com/Seeker14491) |[](https://github.com/brianp) |[](https://github.com/casey) |
+[](https://github.com/dotdash) |[](https://github.com/bradurani) |[](https://github.com/Seeker14491) |[](https://github.com/brianp) |[](https://github.com/cldershem) |[](https://github.com/casey) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[Bilalh](https://github.com/Bilalh) |[dotdash](https://github.com/dotdash) |[bradurani](https://github.com/bradurani) |[Seeker14491](https://github.com/Seeker14491) |[brianp](https://github.com/brianp) |[casey](https://github.com/casey) |
+[dotdash](https://github.com/dotdash) |[bradurani](https://github.com/bradurani) |[Seeker14491](https://github.com/Seeker14491) |[brianp](https://github.com/brianp) |[cldershem](https://github.com/cldershem) |[casey](https://github.com/casey) |
[](https://github.com/volks73) |[](https://github.com/daboross) |[](https://github.com/mernen) |[](https://github.com/dguo) |[](https://github.com/davidszotten) |[](https://github.com/drusellers) |
:---: |:---: |:---: |:---: |:---: |:---: |
[volks73](https://github.com/volks73) |[daboross](https://github.com/daboross) |[mernen](https://github.com/mernen) |[dguo](https://github.com/dguo) |[davidszotten](https://github.com/davidszotten) |[drusellers](https://github.com/drusellers) |
-[](https://github.com/eddyb) |[](https://github.com/Fraser999) |[](https://github.com/birkenfeld) |[](https://github.com/guanqun) |[](https://github.com/tanakh) |[](https://github.com/SirVer) |
+[](https://github.com/eddyb) |[](https://github.com/Enet4) |[](https://github.com/Fraser999) |[](https://github.com/birkenfeld) |[](https://github.com/guanqun) |[](https://github.com/tanakh) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[eddyb](https://github.com/eddyb) |[Fraser999](https://github.com/Fraser999) |[birkenfeld](https://github.com/birkenfeld) |[guanqun](https://github.com/guanqun) |[tanakh](https://github.com/tanakh) |[SirVer](https://github.com/SirVer) |
+[eddyb](https://github.com/eddyb) |[Enet4](https://github.com/Enet4) |[Fraser999](https://github.com/Fraser999) |[birkenfeld](https://github.com/birkenfeld) |[guanqun](https://github.com/guanqun) |[tanakh](https://github.com/tanakh) |
-[](https://github.com/idmit) |[](https://github.com/archer884) |[](https://github.com/jacobmischka) |[](https://github.com/jespino) |[](https://github.com/jfrankenau) |[](https://github.com/jtdowney) |
+[](https://github.com/SirVer) |[](https://github.com/idmit) |[](https://github.com/archer884) |[](https://github.com/jacobmischka) |[](https://github.com/jespino) |[](https://github.com/jfrankenau) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[idmit](https://github.com/idmit) |[archer884](https://github.com/archer884) |[jacobmischka](https://github.com/jacobmischka) |[jespino](https://github.com/jespino) |[jfrankenau](https://github.com/jfrankenau) |[jtdowney](https://github.com/jtdowney) |
+[SirVer](https://github.com/SirVer) |[idmit](https://github.com/idmit) |[archer884](https://github.com/archer884) |[jacobmischka](https://github.com/jacobmischka) |[jespino](https://github.com/jespino) |[jfrankenau](https://github.com/jfrankenau) |
-[](https://github.com/andete) |[](https://github.com/joshtriplett) |[](https://github.com/Kalwyn) |[](https://github.com/manuel-rhdt) |[](https://github.com/Marwes) |[](https://github.com/mdaffin) |
+[](https://github.com/jtdowney) |[](https://github.com/andete) |[](https://github.com/joshtriplett) |[](https://github.com/Kalwyn) |[](https://github.com/manuel-rhdt) |[](https://github.com/Marwes) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[andete](https://github.com/andete) |[joshtriplett](https://github.com/joshtriplett) |[Kalwyn](https://github.com/Kalwyn) |[manuel-rhdt](https://github.com/manuel-rhdt) |[Marwes](https://github.com/Marwes) |[mdaffin](https://github.com/mdaffin) |
+[jtdowney](https://github.com/jtdowney) |[andete](https://github.com/andete) |[joshtriplett](https://github.com/joshtriplett) |[Kalwyn](https://github.com/Kalwyn) |[manuel-rhdt](https://github.com/manuel-rhdt) |[Marwes](https://github.com/Marwes) |
-[](https://github.com/iliekturtles) |[](https://github.com/nicompte) |[](https://github.com/NickeZ) |[](https://github.com/nvzqz) |[](https://github.com/nuew) |[](https://github.com/Geogi) |
+[](https://github.com/mdaffin) |[](https://github.com/iliekturtles) |[](https://github.com/nicompte) |[](https://github.com/NickeZ) |[](https://github.com/nvzqz) |[](https://github.com/nuew) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[iliekturtles](https://github.com/iliekturtles) |[nicompte](https://github.com/nicompte) |[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[nuew](https://github.com/nuew) |[Geogi](https://github.com/Geogi) |
+[mdaffin](https://github.com/mdaffin) |[iliekturtles](https://github.com/iliekturtles) |[nicompte](https://github.com/nicompte) |[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[nuew](https://github.com/nuew) |
-[](https://github.com/focusaurus) |[](https://github.com/flying-sheep) |[](https://github.com/Phlosioneer) |[](https://github.com/peppsac) |[](https://github.com/golddranks) |[](https://github.com/hexjelly) |
+[](https://github.com/Geogi) |[](https://github.com/focusaurus) |[](https://github.com/flying-sheep) |[](https://github.com/Phlosioneer) |[](https://github.com/peppsac) |[](https://github.com/golddranks) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[focusaurus](https://github.com/focusaurus) |[flying-sheep](https://github.com/flying-sheep) |[Phlosioneer](https://github.com/Phlosioneer) |[peppsac](https://github.com/peppsac) |[golddranks](https://github.com/golddranks) |[hexjelly](https://github.com/hexjelly) |
+[Geogi](https://github.com/Geogi) |[focusaurus](https://github.com/focusaurus) |[flying-sheep](https://github.com/flying-sheep) |[Phlosioneer](https://github.com/Phlosioneer) |[peppsac](https://github.com/peppsac) |[golddranks](https://github.com/golddranks) |
-[](https://github.com/rnelson) |[](https://github.com/swatteau) |[](https://github.com/tspiteri) |[](https://github.com/siiptuo) |[](https://github.com/vks) |[](https://github.com/vsupalov) |
+[](https://github.com/hexjelly) |[](https://github.com/rom1v) |[](https://github.com/rnelson) |[](https://github.com/segevfiner) |[](https://github.com/swatteau) |[](https://github.com/tspiteri) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[rnelson](https://github.com/rnelson) |[swatteau](https://github.com/swatteau) |[tspiteri](https://github.com/tspiteri) |[siiptuo](https://github.com/siiptuo) |[vks](https://github.com/vks) |[vsupalov](https://github.com/vsupalov) |
+[hexjelly](https://github.com/hexjelly) |[rom1v](https://github.com/rom1v) |[rnelson](https://github.com/rnelson) |[segevfiner](https://github.com/segevfiner) |[swatteau](https://github.com/swatteau) |[tspiteri](https://github.com/tspiteri) |
-[](https://github.com/mineo) |[](https://github.com/wabain) |[](https://github.com/grossws) |[](https://github.com/kennytm) |[](https://github.com/mvaude) |[](https://github.com/panicbit) |
+[](https://github.com/siiptuo) |[](https://github.com/vks) |[](https://github.com/vsupalov) |[](https://github.com/mineo) |[](https://github.com/wabain) |[](https://github.com/grossws) |
:---: |:---: |:---: |:---: |:---: |:---: |
-[mineo](https://github.com/mineo) |[wabain](https://github.com/wabain) |[grossws](https://github.com/grossws) |[kennytm](https://github.com/kennytm) |[mvaude](https://github.com/mvaude) |[panicbit](https://github.com/panicbit) |
+[siiptuo](https://github.com/siiptuo) |[vks](https://github.com/vks) |[vsupalov](https://github.com/vsupalov) |[mineo](https://github.com/mineo) |[wabain](https://github.com/wabain) |[grossws](https://github.com/grossws) |
-[](https://github.com/mitsuhiko) |
-:---: |
-[mitsuhiko](https://github.com/mitsuhiko) |
+[](https://github.com/kennytm) |[](https://github.com/mvaude) |[](https://github.com/panicbit) |[](https://github.com/Bilalh) |
+:---: |:---: |:---: |:---: |
+[kennytm](https://github.com/kennytm) |[mvaude](https://github.com/mvaude) |[panicbit](https://github.com/panicbit) |[Bilalh](https://github.com/Bilalh) |
diff --git a/Cargo.toml b/Cargo.toml
index 63e9922b975..4c6bb773cb5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "clap"
-version = "2.29.0"
+version = "2.29.1"
authors = ["Kevin K. "]
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
repository = "https://github.com/kbknapp/clap-rs"
diff --git a/README.md b/README.md
index eb488a59fce..95969569871 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,15 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
## What's New
+Here's whats new in 2.29.1:
+
+* Debloats clap by deduplicating logic and refactors for a ~57% decrease in code size! This is with zero functinoality lost, and a slight perf increase!
+* Change the bash completion script code generation to support hyphens.
+* Fix completion of long option values in ZSH completions
+* Fixes broken links in docs
+* Updates contributors list
+* Fixes the ripgrep benchmark by adding a value to a flag that expects it
+
Here's whats new in 2.29.0:
* **Arg:** adds Arg::hide_env_values(bool) which allows one to hide any current env values and display only the key in help messages
@@ -301,7 +310,7 @@ subcommands:
Since this feature requires additional dependencies that not everyone may want, it is *not* compiled in by default and we need to enable a feature flag in Cargo.toml:
-Simply change your `clap = "2.29"` to `clap = {version = "2.87", features = ["yaml"]}`.
+Simply change your `clap = "2.29"` to `clap = {version = "2.29", features = ["yaml"]}`.
Finally we create our `main.rs` file just like we would have with the previous two examples:
diff --git a/benches/05_ripgrep.rs b/benches/05_ripgrep.rs
index 48c0819bd24..7db1552550b 100644
--- a/benches/05_ripgrep.rs
+++ b/benches/05_ripgrep.rs
@@ -43,7 +43,7 @@ fn parse_complex(b: &mut Bencher) {
app_short().get_matches_from(vec!["rg",
"pat",
"-cFlN",
- "-pqr",
+ "-pqr=some",
"--null",
"--no-filename",
"--no-messages",
diff --git a/clap-test.rs b/clap-test.rs
index 2f91b9e818e..3e01edee837 100644
--- a/clap-test.rs
+++ b/clap-test.rs
@@ -39,6 +39,16 @@ mod test {
assert_eq!(stderr, err.use_stderr());
compare(left, right)
}
+ pub fn compare_output2(l: App, args: &str, right1: &str, right2: &str, stderr: bool) -> bool {
+ let mut buf = Cursor::new(Vec::with_capacity(50));
+ let res = l.get_matches_from_safe(args.split(' ').collect::>());
+ let err = res.unwrap_err();
+ err.write_to(&mut buf).unwrap();
+ let content = buf.into_inner();
+ let left = String::from_utf8(content).unwrap();
+ assert_eq!(stderr, err.use_stderr());
+ compare(&*left, right1) || compare(&*left, right2)
+ }
// Legacy tests from the pyhton script days
diff --git a/src/app/macros.rs b/src/app/macros.rs
deleted file mode 100644
index e3f15e96733..00000000000
--- a/src/app/macros.rs
+++ /dev/null
@@ -1,165 +0,0 @@
-macro_rules! remove_overriden {
- (@remove_requires $rem_from:expr, $a:ident.$ov:ident) => {
- if let Some(ora) = $a.$ov() {
- for i in (0 .. $rem_from.len()).rev() {
- let should_remove = ora.iter().any(|&(_, ref name)| name == &$rem_from[i]);
- if should_remove { $rem_from.swap_remove(i); }
- }
- }
- };
- (@remove $rem_from:expr, $a:ident.$ov:ident) => {
- if let Some(ora) = $a.$ov() {
- vec_remove_all!($rem_from, ora.iter());
- }
- };
- (@arg $_self:ident, $arg:ident) => {
- remove_overriden!(@remove_requires $_self.required, $arg.requires);
- remove_overriden!(@remove $_self.blacklist, $arg.blacklist);
- remove_overriden!(@remove $_self.overrides, $arg.overrides);
- };
- ($_self:ident, $name:expr) => {
- debugln!("remove_overriden!;");
- if let Some(o) = $_self.opts.iter() .find(|o| o.b.name == *$name) {
- remove_overriden!(@arg $_self, o);
- } else if let Some(f) = $_self.flags.iter() .find(|f| f.b.name == *$name) {
- remove_overriden!(@arg $_self, f);
- } else {
- let p = $_self.positionals.values()
- .find(|p| p.b.name == *$name)
- .expect(INTERNAL_ERROR_MSG);
- remove_overriden!(@arg $_self, p);
- }
- };
-}
-
-macro_rules! arg_post_processing {
- ($me:ident, $arg:ident, $matcher:ident) => {
- debugln!("arg_post_processing!;");
- // Handle POSIX overrides
- debug!("arg_post_processing!: Is '{}' in overrides...", $arg.to_string());
- if $me.overrides.contains(&$arg.name()) {
- if let Some(ref name) = find_name_from!($me, &$arg.name(), overrides, $matcher) {
- sdebugln!("Yes by {}", name);
- $matcher.remove(name);
- remove_overriden!($me, name);
- }
- } else { sdebugln!("No"); }
-
- // Add overrides
- debug!("arg_post_processing!: Does '{}' have overrides...", $arg.to_string());
- if let Some(or) = $arg.overrides() {
- sdebugln!("Yes");
- $matcher.remove_all(or);
- for pa in or { remove_overriden!($me, pa); }
- $me.overrides.extend(or);
- vec_remove_all!($me.required, or.iter());
- } else { sdebugln!("No"); }
-
- // Handle conflicts
- debug!("arg_post_processing!: Does '{}' have conflicts...", $arg.to_string());
- if let Some(bl) = $arg.blacklist() {
- sdebugln!("Yes");
-
- for c in bl {
- // Inject two-way conflicts
- debug!("arg_post_processing!: Has '{}' already been matched...", c);
- if $matcher.contains(c) {
- sdebugln!("Yes");
- // find who blacklisted us...
- $me.blacklist.push(&$arg.b.name);
- } else {
- sdebugln!("No");
- }
- }
-
- $me.blacklist.extend_from_slice(bl);
- vec_remove_all!($me.overrides, bl.iter());
- // vec_remove_all!($me.required, bl.iter());
- } else { sdebugln!("No"); }
-
- // Add all required args which aren't already found in matcher to the master
- // list
- debug!("arg_post_processing!: Does '{}' have requirements...", $arg.to_string());
- if let Some(reqs) = $arg.requires() {
- for n in reqs.iter()
- .filter(|&&(val, _)| val.is_none())
- .filter(|&&(_, req)| !$matcher.contains(&req))
- .map(|&(_, name)| name) {
-
- $me.required.push(n);
- }
- } else { sdebugln!("No"); }
-
- _handle_group_reqs!($me, $arg);
- };
-}
-
-macro_rules! _handle_group_reqs{
- ($me:ident, $arg:ident) => ({
- use args::AnyArg;
- debugln!("_handle_group_reqs!;");
- for grp in &$me.groups {
- let found = if grp.args.contains(&$arg.name()) {
- if let Some(ref reqs) = grp.requires {
- debugln!("_handle_group_reqs!: Adding {:?} to the required list", reqs);
- $me.required.extend(reqs);
- }
- if let Some(ref bl) = grp.conflicts {
- $me.blacklist.extend(bl);
- }
- true // What if arg is in more than one group with different reqs?
- } else {
- false
- };
- debugln!("_handle_group_reqs!:iter: grp={}, found={:?}", grp.name, found);
- if found {
- for i in (0 .. $me.required.len()).rev() {
- let should_remove = grp.args.contains(&$me.required[i]);
- if should_remove { $me.required.swap_remove(i); }
- }
- debugln!("_handle_group_reqs!:iter: Adding args from group to blacklist...{:?}", grp.args);
- if !grp.multiple {
- $me.blacklist.extend(&grp.args);
- debugln!("_handle_group_reqs!: removing {:?} from blacklist", $arg.name());
- for i in (0 .. $me.blacklist.len()).rev() {
- let should_remove = $me.blacklist[i] == $arg.name();
- if should_remove { $me.blacklist.swap_remove(i); }
- }
- }
- }
- }
- })
-}
-
-macro_rules! parse_positional {
- (
- $_self:ident,
- $p:ident,
- $arg_os:ident,
- $pos_counter:ident,
- $matcher:ident
- ) => {
- debugln!("parse_positional!;");
-
- if !$_self.is_set(AS::TrailingValues) &&
- ($_self.is_set(AS::TrailingVarArg) &&
- $pos_counter == $_self.positionals.len()) {
- $_self.settings.set(AS::TrailingValues);
- }
- let _ = $_self.add_val_to_arg($p, &$arg_os, $matcher)?;
-
- $matcher.inc_occurrence_of($p.b.name);
- let _ = $_self.groups_for_arg($p.b.name)
- .and_then(|vec| Some($matcher.inc_occurrences_of(&*vec)));
- if $_self.cache.map_or(true, |name| name != $p.b.name) {
- arg_post_processing!($_self, $p, $matcher);
- $_self.cache = Some($p.b.name);
- }
-
- $_self.settings.set(AS::ValidArgFound);
- // Only increment the positional counter if it doesn't allow multiples
- if !$p.b.settings.is_set(ArgSettings::Multiple) {
- $pos_counter += 1;
- }
- };
-}
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 9c2d852b74b..908e17170be 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -1,6 +1,4 @@
mod settings;
-#[macro_use]
-mod macros;
pub mod parser;
mod meta;
mod help;
diff --git a/src/app/parser.rs b/src/app/parser.rs
index 22c45c9a769..01e0e1f3561 100644
--- a/src/app/parser.rs
+++ b/src/app/parser.rs
@@ -61,8 +61,7 @@ where
pub global_args: Vec>,
pub required: Vec<&'a str>,
pub r_ifs: Vec<(&'a str, &'b str, &'a str)>,
- pub blacklist: Vec<&'b str>,
- pub overrides: Vec<&'b str>,
+ pub overrides: Vec<(&'b str, &'a str)>,
help_short: Option,
version_short: Option,
cache: Option<&'a str>,
@@ -346,9 +345,9 @@ where
if let Some(ref reqs) = group.requires {
self.required.extend_from_slice(reqs);
}
- if let Some(ref bl) = group.conflicts {
- self.blacklist.extend_from_slice(bl);
- }
+// if let Some(ref bl) = group.conflicts {
+// self.blacklist.extend_from_slice(bl);
+// }
}
if self.groups.iter().any(|g| g.name == group.name) {
let grp = self.groups
@@ -773,12 +772,8 @@ 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))]
- fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult<'a>) -> bool {
- debugln!(
- "Parser::is_new_arg: arg={:?}, Needs Val of={:?}",
- arg_os,
- needs_val_of
- );
+ 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) {
true
} else if self.is_set(AS::AllowNegativeNumbers) {
@@ -807,12 +802,10 @@ where
.expect(INTERNAL_ERROR_MSG);
(p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings)
}
+ ParseResult::ValuesDone => return true,
_ => false,
};
- debugln!(
- "Parser::is_new_arg: Arg::allow_leading_hyphen({:?})",
- arg_allows_tac
- );
+ debugln!( "Parser::is_new_arg: arg_allows_tac={:?}", arg_allows_tac );
// Is this a new argument, or values from a previous option?
let mut ret = if arg_os.starts_with(b"--") {
@@ -913,7 +906,52 @@ where
}
}
- if !starts_new_arg {
+ if starts_new_arg {
+ {
+ let any_arg = find_any_by_name!(self, self.cache.unwrap_or(""));
+ matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required);
+ }
+
+ if arg_os.starts_with(b"--") {
+ needs_val_of = self.parse_long_arg(matcher, &arg_os)?;
+ debugln!( "Parser:get_matches_with: After parse_long_arg {:?}", needs_val_of );
+ match needs_val_of {
+ ParseResult::Flag | ParseResult::Opt(..) | ParseResult::ValuesDone => {
+ continue
+ }
+ _ => (),
+ }
+ } else if arg_os.starts_with(b"-") && arg_os.len_() != 1 {
+ // Try to parse short args like normal, if AllowLeadingHyphen or
+ // AllowNegativeNumbers is set, parse_short_arg will *not* throw
+ // an error, and instead return Ok(None)
+ needs_val_of = self.parse_short_arg(matcher, &arg_os)?;
+ // If it's None, we then check if one of those two AppSettings was set
+ debugln!(
+ "Parser:get_matches_with: After parse_short_arg {:?}",
+ needs_val_of
+ );
+ match needs_val_of {
+ ParseResult::MaybeNegNum => {
+ if !(arg_os.to_string_lossy().parse::().is_ok()
+ || arg_os.to_string_lossy().parse::().is_ok())
+ {
+ return Err(Error::unknown_argument(
+ &*arg_os.to_string_lossy(),
+ "",
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
+ }
+ },
+ ParseResult::Opt(..) | ParseResult::Flag | ParseResult::ValuesDone => {
+ continue
+ }
+ _ => (),
+ }
+ }
+
+ } else {
if let ParseResult::Opt(name) = needs_val_of {
// Check to see if parsing a value from a previous arg
let arg = self.opts
@@ -925,62 +963,20 @@ where
// get the next value from the iterator
continue;
}
- } else if arg_os.starts_with(b"--") {
- needs_val_of = self.parse_long_arg(matcher, &arg_os)?;
- debugln!(
- "Parser:get_matches_with: After parse_long_arg {:?}",
- needs_val_of
- );
- match needs_val_of {
- ParseResult::Flag | ParseResult::Opt(..) | ParseResult::ValuesDone => {
- continue
- }
- _ => (),
- }
- } else if arg_os.starts_with(b"-") && arg_os.len_() != 1 {
- // Try to parse short args like normal, if AllowLeadingHyphen or
- // AllowNegativeNumbers is set, parse_short_arg will *not* throw
- // an error, and instead return Ok(None)
- needs_val_of = self.parse_short_arg(matcher, &arg_os)?;
- // If it's None, we then check if one of those two AppSettings was set
- debugln!(
- "Parser:get_matches_with: After parse_short_arg {:?}",
- needs_val_of
- );
- match needs_val_of {
- ParseResult::MaybeNegNum => {
- if !(arg_os.to_string_lossy().parse::().is_ok()
- || arg_os.to_string_lossy().parse::().is_ok())
- {
- return Err(Error::unknown_argument(
- &*arg_os.to_string_lossy(),
- "",
- &*usage::create_error_usage(self, matcher, None),
- self.color(),
- ));
- }
- }
- ParseResult::Opt(..) | ParseResult::Flag | ParseResult::ValuesDone => {
- continue
- }
- _ => (),
- }
}
+ }
- if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound))
- && !self.is_set(AS::InferSubcommands)
- {
- if let Some(cdate) =
- suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self))
- {
- return Err(Error::invalid_subcommand(
- arg_os.to_string_lossy().into_owned(),
- cdate,
- self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
- &*usage::create_error_usage(self, matcher, None),
- self.color(),
- ));
- }
+ if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound))
+ && !self.is_set(AS::InferSubcommands)
+ {
+ if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self)) {
+ return Err(Error::invalid_subcommand(
+ arg_os.to_string_lossy().into_owned(),
+ cdate,
+ self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
+ &*usage::create_error_usage(self, matcher, None),
+ self.color(),
+ ));
}
}
@@ -1035,7 +1031,29 @@ where
self.color(),
));
}
- parse_positional!(self, p, arg_os, pos_counter, matcher);
+ if !self.is_set(AS::TrailingValues) &&
+ (self.is_set(AS::TrailingVarArg) &&
+ pos_counter == self.positionals.len()) {
+ self.settings.set(AS::TrailingValues);
+ }
+ if self.cache.map_or(true, |name| name != p.b.name) {
+ {
+ let any_arg = find_any_by_name!(self, self.cache.unwrap_or(""));
+ matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required);
+ }
+ self.cache = Some(p.b.name);
+ }
+ let _ = self.add_val_to_arg(p, &arg_os, matcher)?;
+
+ matcher.inc_occurrence_of(p.b.name);
+ let _ = self.groups_for_arg(p.b.name)
+ .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
+
+ self.settings.set(AS::ValidArgFound);
+ // Only increment the positional counter if it doesn't allow multiples
+ if !p.b.settings.is_set(ArgSettings::Multiple) {
+ pos_counter += 1;
+ }
self.settings.set(AS::ValidArgFound);
} else if self.is_set(AS::AllowExternalSubcommands) {
// Get external subcommand name
@@ -1136,9 +1154,34 @@ where
});
}
+ // In case the last arg was new, we need to process it's overrides
+ {
+ let any_arg = find_any_by_name!(self, self.cache.unwrap_or(""));
+ matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required);
+ }
+
+ self.remove_overrides(matcher);
+
Validator::new(self).validate(needs_val_of, subcmd_name, matcher)
}
+ fn remove_overrides(&mut self, matcher: &mut ArgMatcher) {
+ debugln!("Parser::remove_overrides:{:?};", self.overrides);
+ for &(overr, name) in &self.overrides {
+ debugln!("Parser::remove_overrides:iter:({},{});", overr, name);
+ if matcher.is_present(overr) {
+ debugln!("Parser::remove_overrides:iter:({},{}): removing {};", overr, name, name);
+ matcher.remove(name);
+ for i in (0 .. self.required.len()).rev() {
+ debugln!("Parser::remove_overrides:iter:({},{}): removing required {};", overr, name, name);
+ if self.required[i] == name {
+ self.required.swap_remove(i);
+ break;
+ }
+ }
+ }
+ }
+ }
fn propagate_help_version(&mut self) {
debugln!("Parser::propagate_help_version;");
@@ -1483,7 +1526,6 @@ where
self.settings.set(AS::ValidArgFound);
let ret = self.parse_opt(val, opt, val.is_some(), matcher)?;
if self.cache.map_or(true, |name| name != opt.b.name) {
- arg_post_processing!(self, opt, matcher);
self.cache = Some(opt.b.name);
}
@@ -1501,10 +1543,9 @@ where
self.parse_flag(flag, matcher)?;
// Handle conflicts, requirements, etc.
- // if self.cache.map_or(true, |name| name != flag.b.name) {
- arg_post_processing!(self, flag, matcher);
- // self.cache = Some(flag.b.name);
- // }
+ if self.cache.map_or(true, |name| name != flag.b.name) {
+ self.cache = Some(flag.b.name);
+ }
return Ok(ParseResult::Flag);
} else if self.is_set(AS::AllowLeadingHyphen) {
@@ -1580,7 +1621,6 @@ where
let ret = self.parse_opt(val, opt, false, matcher)?;
if self.cache.map_or(true, |name| name != opt.b.name) {
- arg_post_processing!(self, opt, matcher);
self.cache = Some(opt.b.name);
}
@@ -1595,7 +1635,6 @@ where
// Handle conflicts, requirements, overrides, etc.
// Must be called here due to mutablilty
if self.cache.map_or(true, |name| name != flag.b.name) {
- arg_post_processing!(self, flag, matcher);
self.cache = Some(flag.b.name);
}
} else {
@@ -1844,7 +1883,6 @@ where
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) {
- arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name());
}
} else if $m.get($a.b.name).is_some() {
@@ -1855,7 +1893,6 @@ where
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) {
- arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name());
}
}
@@ -1881,7 +1918,6 @@ where
if add {
$_self.add_val_to_arg($a, OsStr::new(default), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) {
- arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name());
}
done = true;
@@ -1920,7 +1956,6 @@ where
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) {
- arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name());
}
}
@@ -1929,7 +1964,6 @@ where
$_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) {
- arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name());
}
}
@@ -1972,7 +2006,7 @@ where
}
}
- pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg> {
+ pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg<'a, 'b>> {
if let Some(f) = find_by_name!(self, name, flags, iter) {
return Some(f);
}
diff --git a/src/app/validator.rs b/src/app/validator.rs
index 01373dd5f9f..9751321a149 100644
--- a/src/app/validator.rs
+++ b/src/app/validator.rs
@@ -78,7 +78,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(())
}
- fn validate_values(
+ fn validate_arg_values(
&self,
arg: &A,
ma: &MatchedArg,
@@ -87,11 +87,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
where
A: AnyArg<'a, 'b> + Display,
{
- debugln!("Validator::validate_values: arg={:?}", arg.name());
+ debugln!("Validator::validate_arg_values: arg={:?}", arg.name());
for val in &ma.vals {
if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
debugln!(
- "Validator::validate_values: invalid UTF-8 found in val {:?}",
+ "Validator::validate_arg_values: invalid UTF-8 found in val {:?}",
val
);
return Err(Error::invalid_utf8(
@@ -100,7 +100,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
));
}
if let Some(p_vals) = arg.possible_vals() {
- debugln!("Validator::validate_values: possible_vals={:?}", p_vals);
+ debugln!("Validator::validate_arg_values: possible_vals={:?}", p_vals);
let val_str = val.to_string_lossy();
let ok = if arg.is_set(ArgSettings::CaseInsensitive) {
p_vals.iter().any(|pv| pv.eq_ignore_ascii_case(&*val_str))
@@ -120,7 +120,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_()
&& matcher.contains(&*arg.name())
{
- debugln!("Validator::validate_values: illegal empty val found");
+ debugln!("Validator::validate_arg_values: illegal empty val found");
return Err(Error::empty_value(
arg,
&*usage::create_error_usage(self.0, matcher, None),
@@ -128,7 +128,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
));
}
if let Some(vtor) = arg.validator() {
- debug!("Validator::validate_values: checking validator...");
+ debug!("Validator::validate_arg_values: checking validator...");
if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
sdebugln!("error");
return Err(Error::value_validation(Some(arg), e, self.0.color()));
@@ -137,7 +137,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
}
}
if let Some(vtor) = arg.validator_os() {
- debug!("Validator::validate_values: checking validator_os...");
+ debug!("Validator::validate_arg_values: checking validator_os...");
if let Err(e) = vtor(val) {
sdebugln!("error");
return Err(Error::value_validation(
@@ -153,44 +153,83 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(())
}
- fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
- debugln!(
- "Validator::validate_blacklist: blacklist={:?}",
- self.0.blacklist
+ fn build_err(&self, name: &str, matcher: &ArgMatcher) -> ClapResult<()> {
+ debugln!("build_err!: name={}", name);
+ let mut c_with = find_from!(self.0, &name, blacklist, &matcher);
+ c_with = c_with.or(
+ self.0.find_any_arg(&name).map_or(None, |aa| aa.blacklist())
+ .map_or(None,
+ |bl| bl.iter().find(|arg| matcher.contains(arg)))
+ .map_or(None, |an| self.0.find_any_arg(an))
+ .map_or(None, |aa| Some(format!("{}", aa)))
);
- macro_rules! build_err {
- ($p:expr, $name:expr, $matcher:ident) => ({
- debugln!("build_err!: name={}", $name);
- let mut c_with = find_from!($p, &$name, blacklist, &$matcher);
- c_with = c_with.or(
- $p.find_any_arg(&$name).map_or(None, |aa| aa.blacklist())
- .map_or(None,
- |bl| bl.iter().find(|arg| $matcher.contains(arg)))
- .map_or(None, |an| $p.find_any_arg(an))
- .map_or(None, |aa| Some(format!("{}", aa)))
- );
- debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &$name);
- $matcher.remove(&$name);
- let usg = usage::create_error_usage($p, $matcher, None);
- if let Some(f) = find_by_name!($p, $name, flags, iter) {
- debugln!("build_err!: It was a flag...");
- Error::argument_conflict(f, c_with, &*usg, self.0.color())
- } else if let Some(o) = find_by_name!($p, $name, opts, iter) {
- debugln!("build_err!: It was an option...");
- Error::argument_conflict(o, c_with, &*usg, self.0.color())
- } else {
- match find_by_name!($p, $name, positionals, values) {
- Some(p) => {
- debugln!("build_err!: It was a positional...");
- Error::argument_conflict(p, c_with, &*usg, self.0.color())
- },
- None => panic!(INTERNAL_ERROR_MSG)
+ debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name);
+// matcher.remove(&name);
+ let usg = usage::create_error_usage(self.0, matcher, None);
+ if let Some(f) = find_by_name!(self.0, name, flags, iter) {
+ debugln!("build_err!: It was a flag...");
+ Err(Error::argument_conflict(f, c_with, &*usg, self.0.color()))
+ } else if let Some(o) = find_by_name!(self.0, name, opts, iter) {
+ debugln!("build_err!: It was an option...");
+ Err(Error::argument_conflict(o, c_with, &*usg, self.0.color()))
+ } else {
+ match find_by_name!(self.0, name, positionals, values) {
+ Some(p) => {
+ debugln!("build_err!: It was a positional...");
+ Err(Error::argument_conflict(p, c_with, &*usg, self.0.color()))
+ },
+ None => panic!(INTERNAL_ERROR_MSG)
+ }
+ }
+ }
+
+ fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
+ debugln!("Validator::validate_blacklist;");
+ let mut conflicts: Vec<&str> = vec![];
+ for (&name, _) in matcher.iter() {
+ debugln!("Validator::validate_blacklist:iter:{};", name);
+ if let Some(grps) = self.0.groups_for_arg(name) {
+ for grp in &grps {
+ if let Some(g) = self.0.groups.iter().find(|g| &g.name == grp) {
+ if !g.multiple {
+ for arg in &g.args {
+ if arg == &name {
+ continue;
+ }
+ conflicts.push(arg);
+ }
+ }
+ if let Some(ref gc) = g.conflicts {
+ conflicts.extend(&*gc);
+ }
}
}
- });
+ }
+ if let Some(arg) = find_any_by_name!(self.0, name) {
+ if let Some(bl) = arg.blacklist() {
+ for conf in bl {
+ if matcher.get(conf).is_some() {
+ conflicts.push(conf);
+ }
+ }
+ }
+ } else {
+ debugln!("Validator::validate_blacklist:iter:{}:group;", name);
+ let args = self.0.arg_names_in_group(name);
+ for arg in &args {
+ debugln!("Validator::validate_blacklist:iter:{}:group:iter:{};", name, arg);
+ if let Some(bl) = find_any_by_name!(self.0, *arg).unwrap().blacklist() {
+ for conf in bl {
+ if matcher.get(conf).is_some() {
+ conflicts.push(conf);
+ }
+ }
+ }
+ }
+ }
}
- for name in &self.0.blacklist {
+ for name in &conflicts {
debugln!(
"Validator::validate_blacklist:iter:{}: Checking blacklisted arg",
name
@@ -213,7 +252,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
name,
n
);
- return Err(build_err!(self.0, n, matcher));
+ return self.build_err(n, matcher);
}
}
} else if let Some(ma) = matcher.get(name) {
@@ -224,7 +263,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
should_err = ma.occurs > 0;
}
if should_err {
- return Err(build_err!(self.0, *name, matcher));
+ return self.build_err(*name, matcher);
}
}
Ok(())
@@ -240,7 +279,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
);
if let Some(opt) = find_by_name!(self.0, *name, opts, iter) {
self.validate_arg_num_vals(opt, ma, matcher)?;
- self.validate_values(opt, ma, matcher)?;
+ self.validate_arg_values(opt, ma, matcher)?;
self.validate_arg_requires(opt, ma, matcher)?;
self.validate_arg_num_occurs(opt, ma, matcher)?;
} else if let Some(flag) = find_by_name!(self.0, *name, flags, iter) {
@@ -249,7 +288,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
} else if let Some(pos) = find_by_name!(self.0, *name, positionals, values) {
self.validate_arg_num_vals(pos, ma, matcher)?;
self.validate_arg_num_occurs(pos, ma, matcher)?;
- self.validate_values(pos, ma, matcher)?;
+ self.validate_arg_values(pos, ma, matcher)?;
self.validate_arg_requires(pos, ma, matcher)?;
} else {
let grp = self.0
@@ -381,7 +420,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
where
A: AnyArg<'a, 'b> + Display,
{
- debugln!("Validator::validate_arg_requires;");
+ debugln!("Validator::validate_arg_requires:{};", a.name());
if let Some(a_reqs) = a.requires() {
for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
let missing_req =
@@ -390,6 +429,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
return self.missing_required_error(matcher, None);
}
}
+ for &(_, name) in a_reqs.iter().filter(|&&(val, _)| val.is_none()) {
+ if !matcher.contains(name) {
+ return self.missing_required_error(matcher, Some(name));
+ }
+ }
}
Ok(())
}
@@ -399,20 +443,13 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
"Validator::validate_required: required={:?};",
self.0.required
);
+
'outer: for name in &self.0.required {
debugln!("Validator::validate_required:iter:{}:", name);
if matcher.contains(name) {
continue 'outer;
}
- if let Some(a) = find_by_name!(self.0, *name, flags, iter) {
- if self.is_missing_required_ok(a, matcher) {
- continue 'outer;
- }
- } else if let Some(a) = find_by_name!(self.0, *name, opts, iter) {
- if self.is_missing_required_ok(a, matcher) {
- continue 'outer;
- }
- } else if let Some(a) = find_by_name!(self.0, *name, positionals, values) {
+ if let Some(a) = find_any_by_name!(self.0, *name) {
if self.is_missing_required_ok(a, matcher) {
continue 'outer;
}
@@ -431,11 +468,8 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(())
}
- fn validate_conflicts(&self, a: &A, matcher: &ArgMatcher) -> Option
- where
- A: AnyArg<'a, 'b>,
- {
- debugln!("Validator::validate_conflicts: a={:?};", a.name());
+ fn validate_arg_conflicts(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option {
+ debugln!("Validator::validate_arg_conflicts: a={:?};", a.name());
a.blacklist().map(|bl| {
bl.iter().any(|conf| {
matcher.contains(conf)
@@ -448,10 +482,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
})
}
- fn validate_required_unless(&self, a: &A, matcher: &ArgMatcher) -> Option
- where
- A: AnyArg<'a, 'b>,
- {
+ fn validate_required_unless(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option {
debugln!("Validator::validate_required_unless: a={:?};", a.name());
macro_rules! check {
($how:ident, $_self:expr, $a:ident, $m:ident) => {{
@@ -506,12 +537,9 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
}
#[inline]
- fn is_missing_required_ok(&self, a: &A, matcher: &ArgMatcher) -> bool
- where
- A: AnyArg<'a, 'b>,
- {
+ fn is_missing_required_ok(&self, a: &AnyArg, matcher: &ArgMatcher) -> bool {
debugln!("Validator::is_missing_required_ok: a={}", a.name());
- self.validate_conflicts(a, matcher).unwrap_or(false)
+ self.validate_arg_conflicts(a, matcher).unwrap_or(false)
|| self.validate_required_unless(a, matcher).unwrap_or(false)
}
}
diff --git a/src/args/any_arg.rs b/src/args/any_arg.rs
index 9fa34c7fa06..eee52283328 100644
--- a/src/args/any_arg.rs
+++ b/src/args/any_arg.rs
@@ -6,6 +6,7 @@ use std::ffi::{OsStr, OsString};
// Internal
use args::settings::ArgSettings;
use map::{self, VecMap};
+use INTERNAL_ERROR_MSG;
#[doc(hidden)]
pub trait AnyArg<'n, 'e>: std_fmt::Display {
@@ -41,3 +42,33 @@ pub trait AnyArg<'n, 'e>: std_fmt::Display {
pub trait DispOrder {
fn disp_ord(&self) -> usize;
}
+
+impl<'n, 'e, 'z, T: ?Sized> AnyArg<'n, 'e> for &'z T where T: AnyArg<'n, 'e> + 'z {
+ fn name(&self) -> &'n str { (*self).name() }
+ fn overrides(&self) -> Option<&[&'e str]> { (*self).overrides() }
+ fn aliases(&self) -> Option> { (*self).aliases() }
+ fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { (*self).requires() }
+ fn blacklist(&self) -> Option<&[&'e str]> { (*self).blacklist() }
+ fn required_unless(&self) -> Option<&[&'e str]> { (*self).required_unless() }
+ fn is_set(&self, a: ArgSettings) -> bool { (*self).is_set(a) }
+ fn set(&mut self, _: ArgSettings) { panic!(INTERNAL_ERROR_MSG) }
+ fn has_switch(&self) -> bool { (*self).has_switch() }
+ fn max_vals(&self) -> Option { (*self).max_vals() }
+ fn min_vals(&self) -> Option { (*self).min_vals() }
+ fn num_vals(&self) -> Option { (*self).num_vals() }
+ fn possible_vals(&self) -> Option<&[&'e str]> { (*self).possible_vals() }
+ fn validator(&self) -> Option<&Rc Result<(), String>>> { (*self).validator() }
+ fn validator_os(&self) -> Option<&Rc Result<(), OsString>>> { (*self).validator_os() }
+ fn short(&self) -> Option { (*self).short() }
+ fn long(&self) -> Option<&'e str> { (*self).long() }
+ fn val_delim(&self) -> Option { (*self).val_delim() }
+ fn takes_value(&self) -> bool { (*self).takes_value() }
+ fn val_names(&self) -> Option<&VecMap<&'e str>> { (*self).val_names() }
+ fn help(&self) -> Option<&'e str> { (*self).help() }
+ fn long_help(&self) -> Option<&'e str> { (*self).long_help() }
+ fn default_val(&self) -> Option<&'e OsStr> { (*self).default_val() }
+ fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { (*self).default_vals_ifs() }
+ fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { (*self).env() }
+ fn longest_filter(&self) -> bool { (*self).longest_filter() }
+ fn val_terminator(&self) -> Option<&'e str> { (*self).val_terminator() }
+}
diff --git a/src/args/arg_matcher.rs b/src/args/arg_matcher.rs
index 4e76802e6ed..25f3fc5d749 100644
--- a/src/args/arg_matcher.rs
+++ b/src/args/arg_matcher.rs
@@ -21,11 +21,36 @@ impl<'a> Default for ArgMatcher<'a> {
impl<'a> ArgMatcher<'a> {
pub fn new() -> Self { ArgMatcher::default() }
+ pub fn process_arg_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>, overrides: &mut Vec<(&'b str, &'a str)>, required: &mut Vec<&'a str>) {
+ debugln!("ArgMatcher::process_arg_overrides:{:?};", a.map_or(None, |a| Some(a.name())));
+ if let Some(aa) = a {
+ if let Some(a_overrides) = aa.overrides() {
+ for overr in a_overrides {
+ debugln!("ArgMatcher::process_arg_overrides:iter:{};", overr);
+ if self.is_present(overr) {
+ debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing from matches;", overr);
+ self.remove(overr);
+ for i in (0 .. required.len()).rev() {
+ if &required[i] == overr {
+ debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing required;", overr);
+ required.swap_remove(i);
+ break;
+ }
+ }
+ } else {
+ overrides.push((overr, aa.name()));
+ }
+ }
+ }
+ }
+ }
+
+ pub fn is_present(&self, name: &str) -> bool {
+ self.0.is_present(name)
+ }
+
pub fn propagate_globals(&mut self, global_arg_vec: &[&'a str]) {
- debugln!(
- "ArgMatcher::get_global_values: global_arg_vec={:?}",
- global_arg_vec
- );
+ debugln!( "ArgMatcher::get_global_values: global_arg_vec={:?}", global_arg_vec );
let mut vals_map = HashMap::new();
self.fill_in_global_values(global_arg_vec, &mut vals_map);
}
diff --git a/src/errors.rs b/src/errors.rs
index c4108a64678..664819d6c90 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -8,7 +8,7 @@ use std::process;
use std::result::Result as StdResult;
// Internal
-use args::{AnyArg, FlagBuilder};
+use args::AnyArg;
use fmt::{ColorWhen, Colorizer, ColorizerOption};
use suggestions;
@@ -404,14 +404,13 @@ impl Error {
pub fn write_to(&self, w: &mut W) -> io::Result<()> { write!(w, "{}", self.message) }
#[doc(hidden)]
- pub fn argument_conflict<'a, 'b, A, O, U>(
- arg: &A,
+ pub fn argument_conflict<'a, 'b, O, U>(
+ arg: &AnyArg,
other: Option,
usage: U,
color: ColorWhen,
) -> Self
where
- A: AnyArg<'a, 'b> + Display,
O: Into,
U: Display,
{
@@ -444,9 +443,8 @@ impl Error {
}
#[doc(hidden)]
- pub fn empty_value<'a, 'b, A, U>(arg: &A, usage: U, color: ColorWhen) -> Self
+ pub fn empty_value<'a, 'b, U>(arg: &AnyArg, usage: U, color: ColorWhen) -> Self
where
- A: AnyArg<'a, 'b> + Display,
U: Display,
{
let c = Colorizer::new(ColorizerOption {
@@ -470,17 +468,16 @@ impl Error {
}
#[doc(hidden)]
- pub fn invalid_value<'a, 'b, B, G, A, U>(
+ pub fn invalid_value<'a, 'b, B, G, U>(
bad_val: B,
good_vals: &[G],
- arg: &A,
+ arg: &AnyArg,
usage: U,
color: ColorWhen,
) -> Self
where
B: AsRef,
G: AsRef + Display,
- A: AnyArg<'a, 'b> + Display,
U: Display,
{
let c = Colorizer::new(ColorizerOption {
@@ -660,10 +657,9 @@ impl Error {
}
#[doc(hidden)]
- pub fn too_many_values<'a, 'b, V, A, U>(val: V, arg: &A, usage: U, color: ColorWhen) -> Self
+ pub fn too_many_values<'a, 'b, V, U>(val: V, arg: &AnyArg, usage: U, color: ColorWhen) -> Self
where
V: AsRef + Display + ToOwned,
- A: AnyArg<'a, 'b> + Display,
U: Display,
{
let v = val.as_ref();
@@ -689,15 +685,14 @@ impl Error {
}
#[doc(hidden)]
- pub fn too_few_values<'a, 'b, A, U>(
- arg: &A,
+ pub fn too_few_values<'a, 'b, U>(
+ arg: &AnyArg,
min_vals: u64,
curr_vals: usize,
usage: U,
color: ColorWhen,
) -> Self
where
- A: AnyArg<'a, 'b> + Display,
U: Display,
{
let c = Colorizer::new(ColorizerOption {
@@ -724,9 +719,7 @@ impl Error {
}
#[doc(hidden)]
- pub fn value_validation<'a, 'b, A>(arg: Option<&A>, err: String, color: ColorWhen) -> Self
- where
- A: AnyArg<'a, 'b> + Display,
+ pub fn value_validation<'a, 'b>(arg: Option<&AnyArg>, err: String, color: ColorWhen) -> Self
{
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
@@ -750,13 +743,13 @@ impl Error {
#[doc(hidden)]
pub fn value_validation_auto(err: String) -> Self {
- let n: Option<&FlagBuilder> = None;
+ let n: Option<&AnyArg> = None;
Error::value_validation(n, err, ColorWhen::Auto)
}
#[doc(hidden)]
- pub fn wrong_number_of_values<'a, 'b, A, S, U>(
- arg: &A,
+ pub fn wrong_number_of_values<'a, 'b, S, U>(
+ arg: &AnyArg,
num_vals: u64,
curr_vals: usize,
suffix: S,
@@ -764,7 +757,6 @@ impl Error {
color: ColorWhen,
) -> Self
where
- A: AnyArg<'a, 'b> + Display,
S: Display,
U: Display,
{
@@ -792,9 +784,8 @@ impl Error {
}
#[doc(hidden)]
- pub fn unexpected_multiple_usage<'a, 'b, A, U>(arg: &A, usage: U, color: ColorWhen) -> Self
+ pub fn unexpected_multiple_usage<'a, 'b, U>(arg: &AnyArg, usage: U, color: ColorWhen) -> Self
where
- A: AnyArg<'a, 'b> + Display,
U: Display,
{
let c = Colorizer::new(ColorizerOption {
diff --git a/src/lib.rs b/src/lib.rs
index de23769c796..d60eddd7642 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -513,7 +513,7 @@
//! this repository for more information.
#![crate_type = "lib"]
-#![doc(html_root_url = "https://docs.rs/clap/2.29.0")]
+#![doc(html_root_url = "https://docs.rs/clap/2.29.1")]
#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
unused_import_braces, unused_allocation)]
// Lints we'd like to deny but are currently failing for upstream crates
diff --git a/src/macros.rs b/src/macros.rs
index 51bb95a7b07..52fb35a4de9 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -853,15 +853,15 @@ macro_rules! write_nspaces {
}
// convenience macro for remove an item from a vec
-macro_rules! vec_remove_all {
- ($vec:expr, $to_rem:expr) => {
- debugln!("vec_remove_all! to_rem={:?}", $to_rem);
- for i in (0 .. $vec.len()).rev() {
- let should_remove = $to_rem.any(|name| name == &$vec[i]);
- if should_remove { $vec.swap_remove(i); }
- }
- };
-}
+//macro_rules! vec_remove_all {
+// ($vec:expr, $to_rem:expr) => {
+// debugln!("vec_remove_all! to_rem={:?}", $to_rem);
+// for i in (0 .. $vec.len()).rev() {
+// let should_remove = $to_rem.any(|name| name == &$vec[i]);
+// if should_remove { $vec.swap_remove(i); }
+// }
+// };
+//}
macro_rules! find_from {
($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
let mut ret = None;
@@ -892,36 +892,49 @@ macro_rules! find_from {
}};
}
-macro_rules! find_name_from {
- ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
- let mut ret = None;
- for k in $matcher.arg_names() {
- if let Some(f) = find_by_name!($_self, k, flags, iter) {
- if let Some(ref v) = f.$from() {
- if v.contains($arg_name) {
- ret = Some(f.b.name);
- }
- }
- }
- if let Some(o) = find_by_name!($_self, k, opts, iter) {
- if let Some(ref v) = o.$from() {
- if v.contains(&$arg_name) {
- ret = Some(o.b.name);
- }
- }
- }
- if let Some(pos) = find_by_name!($_self, k, positionals, values) {
- if let Some(ref v) = pos.$from() {
- if v.contains($arg_name) {
- ret = Some(pos.b.name);
- }
- }
- }
+//macro_rules! find_name_from {
+// ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
+// let mut ret = None;
+// for k in $matcher.arg_names() {
+// if let Some(f) = find_by_name!($_self, k, flags, iter) {
+// if let Some(ref v) = f.$from() {
+// if v.contains($arg_name) {
+// ret = Some(f.b.name);
+// }
+// }
+// }
+// if let Some(o) = find_by_name!($_self, k, opts, iter) {
+// if let Some(ref v) = o.$from() {
+// if v.contains(&$arg_name) {
+// ret = Some(o.b.name);
+// }
+// }
+// }
+// if let Some(pos) = find_by_name!($_self, k, positionals, values) {
+// if let Some(ref v) = pos.$from() {
+// if v.contains($arg_name) {
+// ret = Some(pos.b.name);
+// }
+// }
+// }
+// }
+// ret
+// }};
+//}
+
+
+macro_rules! find_any_by_name {
+ ($p:expr, $name:expr) => {
+ {
+ fn as_trait_obj<'a, 'b, T: AnyArg<'a, 'b>>(x: &T) -> &AnyArg<'a, 'b> { x }
+ find_by_name!($p, $name, flags, iter).map(as_trait_obj).or(
+ find_by_name!($p, $name, opts, iter).map(as_trait_obj).or(
+ find_by_name!($p, $name, positionals, values).map(as_trait_obj)
+ )
+ )
}
- ret
- }};
+ }
}
-
// Finds an arg by name
macro_rules! find_by_name {
($p:expr, $name:expr, $what:ident, $how:ident) => {
diff --git a/tests/global_args.rs b/tests/global_args.rs
index 6bcf11c5a3f..28eaac1124f 100644
--- a/tests/global_args.rs
+++ b/tests/global_args.rs
@@ -4,7 +4,7 @@ extern crate regex;
#[cfg(test)]
mod tests {
include!("../clap-test.rs");
- use clap::{App, Arg, SubCommand, ArgMatches};
+ use clap::{App, Arg, SubCommand};
fn get_app() -> App<'static, 'static> {
App::new("myprog")
diff --git a/tests/groups.rs b/tests/groups.rs
index fa497bfb643..fde3f32c264 100644
--- a/tests/groups.rs
+++ b/tests/groups.rs
@@ -55,36 +55,45 @@ fn non_existing_arg() {
#[test]
fn group_single_value() {
- let m = App::new("group")
+ let res = App::new("group")
.args_from_usage("-f, --flag 'some flag'
-c, --color [color] 'some option'")
.group(ArgGroup::with_name("grp")
.args(&["flag", "color"]))
- .get_matches_from(vec!["", "-c", "blue"]);
+ .get_matches_from_safe(vec!["", "-c", "blue"]);
+ assert!(res.is_ok());
+
+ let m = res.unwrap();
assert!(m.is_present("grp"));
assert_eq!(m.value_of("grp").unwrap(), "blue");
}
#[test]
fn group_single_flag() {
- let m = App::new("group")
+ let res = App::new("group")
.args_from_usage("-f, --flag 'some flag'
-c, --color [color] 'some option'")
.group(ArgGroup::with_name("grp")
.args(&["flag", "color"]))
- .get_matches_from(vec!["", "-f"]);
+ .get_matches_from_safe(vec!["", "-f"]);
+ assert!(res.is_ok());
+
+ let m = res.unwrap();
assert!(m.is_present("grp"));
assert!(m.value_of("grp").is_none());
}
#[test]
fn group_empty() {
- let m = App::new("group")
+ let res = App::new("group")
.args_from_usage("-f, --flag 'some flag'
-c, --color [color] 'some option'")
.group(ArgGroup::with_name("grp")
.args(&["flag", "color"]))
- .get_matches_from(vec![""]);
+ .get_matches_from_safe(vec![""]);
+ assert!(res.is_ok());
+
+ let m = res.unwrap();
assert!(!m.is_present("grp"));
assert!(m.value_of("grp").is_none());
}
@@ -105,12 +114,15 @@ fn group_reqired_flags_empty() {
#[test]
fn group_multi_value_single_arg() {
- let m = App::new("group")
+ let res = App::new("group")
.args_from_usage("-f, --flag 'some flag'
-c, --color [color]... 'some option'")
.group(ArgGroup::with_name("grp")
.args(&["flag", "color"]))
- .get_matches_from(vec!["", "-c", "blue", "red", "green"]);
+ .get_matches_from_safe(vec!["", "-c", "blue", "red", "green"]);
+ assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
+
+ let m = res.unwrap();
assert!(m.is_present("grp"));
assert_eq!(&*m.values_of("grp").unwrap().collect::>(), &["blue", "red", "green"]);
}
@@ -148,19 +160,7 @@ fn req_group_with_conflict_usage_string() {
.args(&["base", "delete"])
.required(true));
- assert!(test::compare_output(app, "clap-test --delete base", REQ_GROUP_CONFLICT_REV, true));
-}
-
-#[test]
-fn req_group_with_conflict_rev_usage_string() {
- let app = App::new("req_group")
- .arg(Arg::from_usage("[base] 'Base commit'").conflicts_with("delete"))
- .arg(Arg::from_usage("-d, --delete 'Remove the base commit information'"))
- .group(ArgGroup::with_name("base_or_delete")
- .args(&["base", "delete"])
- .required(true));
-
- assert!(test::compare_output(app, "clap-test base --delete", REQ_GROUP_CONFLICT_USAGE, true));
+ assert!(test::compare_output2(app, "clap-test --delete base", REQ_GROUP_CONFLICT_REV, REQ_GROUP_CONFLICT_USAGE, true));
}
#[test]
diff --git a/tests/multiple_values.rs b/tests/multiple_values.rs
index 32f8a08e71a..7f35e06a82b 100644
--- a/tests/multiple_values.rs
+++ b/tests/multiple_values.rs
@@ -1106,13 +1106,16 @@ fn multiple_value_terminator_option_other_arg() {
#[test]
fn multiple_vals_with_hyphen() {
- let m = App::new("do")
+ let res = App::new("do")
.arg(Arg::with_name("cmds")
.multiple(true)
.allow_hyphen_values(true)
.value_terminator(";"))
.arg(Arg::with_name("location"))
- .get_matches_from(vec!["do", "find", "-type", "f", "-name", "special", ";", "/home/clap"]);
+ .get_matches_from_safe(vec!["do", "find", "-type", "f", "-name", "special", ";", "/home/clap"]);
+ assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
+
+ let m = res.unwrap();
let cmds: Vec<_> = m.values_of("cmds").unwrap().collect();
assert_eq!(&cmds, &["find", "-type", "f", "-name", "special"]);
assert_eq!(m.value_of("location"), Some("/home/clap"));
diff --git a/tests/posix_compatible.rs b/tests/posix_compatible.rs
index 060bc5f7431..83f14481239 100644
--- a/tests/posix_compatible.rs
+++ b/tests/posix_compatible.rs
@@ -166,14 +166,13 @@ fn pos_required_overridden_by_flag() {
#[test]
fn require_overriden_2() {
let m = App::new("require_overriden")
- .arg(Arg::with_name("flag")
- .index(1)
+ .arg(Arg::with_name("req_pos")
.required(true))
.arg(Arg::from_usage("-c, --color 'other flag'")
- .overrides_with("flag"))
- .get_matches_from(vec!["", "-c", "flag"]);
+ .overrides_with("req_pos"))
+ .get_matches_from(vec!["", "-c", "req_pos"]);
assert!(!m.is_present("color"));
- assert!(m.is_present("flag"));
+ assert!(m.is_present("req_pos"));
}
#[test]
diff --git a/tests/possible_values.rs b/tests/possible_values.rs
index 0085c9e9e83..4939a7d7d8c 100644
--- a/tests/possible_values.rs
+++ b/tests/possible_values.rs
@@ -3,7 +3,7 @@ extern crate regex;
include!("../clap-test.rs");
-#[allow(unsused_imports)]
+#[allow(unused_imports)]
use std::ascii::AsciiExt;
use clap::{App, Arg, ErrorKind};
diff --git a/tests/subcommands.rs b/tests/subcommands.rs
index e15de696974..de2f8b56117 100644
--- a/tests/subcommands.rs
+++ b/tests/subcommands.rs
@@ -32,22 +32,22 @@ SUBCOMMANDS:
test Some help";
#[cfg(feature = "suggestions")]
-static DYM: &'static str = "error: The subcommand 'subcm' wasn't recognized
-\tDid you mean 'subcmd'?
+static DYM_SUBCMD: &'static str = "error: The subcommand 'subcm' wasn't recognized
+ Did you mean 'subcmd'?
-If you believe you received this message in error, try re-running with 'clap-test -- subcm'
+If you believe you received this message in error, try re-running with 'dym -- subcm'
USAGE:
- clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]
+ dym [SUBCOMMAND]
For more information try --help";
#[cfg(feature = "suggestions")]
-static DYM2: &'static str = "error: Found argument '--subcm' which wasn't expected, or isn't valid in this context
+static DYM_ARG: &'static str = "error: Found argument '--subcm' which wasn't expected, or isn't valid in this context
\tDid you mean to put '--subcmdarg' after the subcommand 'subcmd'?
USAGE:
- clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND]
+ dym [SUBCOMMAND]
For more information try --help";
@@ -129,8 +129,18 @@ fn multiple_aliases() {
#[test]
#[cfg(feature="suggestions")]
fn subcmd_did_you_mean_output() {
- assert!(test::compare_output(test::complex_app(), "clap-test subcm", DYM, true));
- assert!(test::compare_output(test::complex_app(), "clap-test --subcm foo", DYM2, true));
+ let app = App::new("dym")
+ .subcommand(SubCommand::with_name("subcmd"));
+ assert!(test::compare_output(app, "dym subcm", DYM_SUBCMD, true));
+}
+
+#[test]
+#[cfg(feature="suggestions")]
+fn subcmd_did_you_mean_output_arg() {
+ let app = App::new("dym")
+ .subcommand(SubCommand::with_name("subcmd")
+ .arg_from_usage("-s --subcmdarg [subcmdarg] 'tests'") );
+ assert!(test::compare_output(app, "dym --subcm foo", DYM_ARG, true));
}
#[test]