Merge branch 'master' into issue-1135

This commit is contained in:
William Murphy 2018-01-10 06:28:58 -05:00 committed by GitHub
commit 1ab5c2d316
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 549 additions and 501 deletions

1
.gitignore vendored
View file

@ -24,3 +24,4 @@ Cargo.lock
# Project files # Project files
.vscode/* .vscode/*
.idea/*

View file

@ -1,3 +1,24 @@
<a name="2.29.1"></a>
### 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))
<a name="2.29.0"></a> <a name="2.29.0"></a>
## 2.29.0 (2017-12-02) ## 2.29.0 (2017-12-02)

View file

@ -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) | [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) |
[<img alt="malbarbo" src="https://avatars3.githubusercontent.com/u/1678126?v=4&s=117" width="117">](https://github.com/malbarbo) |[<img alt="matthiasbeyer" src="https://avatars0.githubusercontent.com/u/427866?v=4&s=117" width="117">](https://github.com/matthiasbeyer) |[<img alt="gohyda" src="https://avatars3.githubusercontent.com/u/10263838?v=4&s=117" width="117">](https://github.com/gohyda) |[<img alt="tshepang" src="https://avatars0.githubusercontent.com/u/588486?v=4&s=117" width="117">](https://github.com/tshepang) |[<img alt="golem131" src="https://avatars3.githubusercontent.com/u/2429587?v=4&s=117" width="117">](https://github.com/golem131) |[<img alt="jimmycuadra" src="https://avatars2.githubusercontent.com/u/122457?v=4&s=117" width="117">](https://github.com/jimmycuadra) | [<img alt="matthiasbeyer" src="https://avatars0.githubusercontent.com/u/427866?v=4&s=117" width="117">](https://github.com/matthiasbeyer) |[<img alt="malbarbo" src="https://avatars3.githubusercontent.com/u/1678126?v=4&s=117" width="117">](https://github.com/malbarbo) |[<img alt="tshepang" src="https://avatars0.githubusercontent.com/u/588486?v=4&s=117" width="117">](https://github.com/tshepang) |[<img alt="golem131" src="https://avatars3.githubusercontent.com/u/2429587?v=4&s=117" width="117">](https://github.com/golem131) |[<img alt="jimmycuadra" src="https://avatars2.githubusercontent.com/u/122457?v=4&s=117" width="117">](https://github.com/jimmycuadra) |[<img alt="Nemo157" src="https://avatars1.githubusercontent.com/u/81079?v=4&s=117" width="117">](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) |
[<img alt="Nemo157" src="https://avatars1.githubusercontent.com/u/81079?v=4&s=117" width="117">](https://github.com/Nemo157) |[<img alt="SShrike" src="https://avatars1.githubusercontent.com/u/4061736?v=4&s=117" width="117">](https://github.com/SShrike) |[<img alt="Eijebong" src="https://avatars2.githubusercontent.com/u/3650385?v=4&s=117" width="117">](https://github.com/Eijebong) |[<img alt="cstorey" src="https://avatars3.githubusercontent.com/u/743059?v=4&s=117" width="117">](https://github.com/cstorey) |[<img alt="wdv4758h" src="https://avatars1.githubusercontent.com/u/2716047?v=4&s=117" width="117">](https://github.com/wdv4758h) |[<img alt="frewsxcv" src="https://avatars2.githubusercontent.com/u/416575?v=4&s=117" width="117">](https://github.com/frewsxcv) | [<img alt="severen" src="https://avatars1.githubusercontent.com/u/4061736?v=4&s=117" width="117">](https://github.com/severen) |[<img alt="Eijebong" src="https://avatars2.githubusercontent.com/u/3650385?v=4&s=117" width="117">](https://github.com/Eijebong) |[<img alt="cstorey" src="https://avatars3.githubusercontent.com/u/743059?v=4&s=117" width="117">](https://github.com/cstorey) |[<img alt="wdv4758h" src="https://avatars1.githubusercontent.com/u/2716047?v=4&s=117" width="117">](https://github.com/wdv4758h) |[<img alt="frewsxcv" src="https://avatars2.githubusercontent.com/u/416575?v=4&s=117" width="117">](https://github.com/frewsxcv) |[<img alt="hoodie" src="https://avatars1.githubusercontent.com/u/260370?v=4&s=117" width="117">](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) |
[<img alt="hoodie" src="https://avatars1.githubusercontent.com/u/260370?v=4&s=117" width="117">](https://github.com/hoodie) |[<img alt="huonw" src="https://avatars1.githubusercontent.com/u/1203825?v=4&s=117" width="117">](https://github.com/huonw) |[<img alt="GrappigPanda" src="https://avatars0.githubusercontent.com/u/2055372?v=4&s=117" width="117">](https://github.com/GrappigPanda) |[<img alt="shepmaster" src="https://avatars0.githubusercontent.com/u/174509?v=4&s=117" width="117">](https://github.com/shepmaster) |[<img alt="porglezomp" src="https://avatars1.githubusercontent.com/u/1690225?v=4&s=117" width="117">](https://github.com/porglezomp) |[<img alt="kieraneglin" src="https://avatars0.githubusercontent.com/u/569917?v=4&s=117" width="117">](https://github.com/kieraneglin) | [<img alt="huonw" src="https://avatars1.githubusercontent.com/u/1203825?v=4&s=117" width="117">](https://github.com/huonw) |[<img alt="GrappigPanda" src="https://avatars0.githubusercontent.com/u/2055372?v=4&s=117" width="117">](https://github.com/GrappigPanda) |[<img alt="shepmaster" src="https://avatars0.githubusercontent.com/u/174509?v=4&s=117" width="117">](https://github.com/shepmaster) |[<img alt="porglezomp" src="https://avatars1.githubusercontent.com/u/1690225?v=4&s=117" width="117">](https://github.com/porglezomp) |[<img alt="kieraneglin" src="https://avatars0.githubusercontent.com/u/569917?v=4&s=117" width="117">](https://github.com/kieraneglin) |[<img alt="musoke" src="https://avatars0.githubusercontent.com/u/16665084?v=4&s=117" width="117">](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) |
[<img alt="musoke" src="https://avatars0.githubusercontent.com/u/16665084?v=4&s=117" width="117">](https://github.com/musoke) |[<img alt="nelsonjchen" src="https://avatars1.githubusercontent.com/u/5363?v=4&s=117" width="117">](https://github.com/nelsonjchen) |[<img alt="pkgw" src="https://avatars0.githubusercontent.com/u/59598?v=4&s=117" width="117">](https://github.com/pkgw) |[<img alt="Deedasmi" src="https://avatars0.githubusercontent.com/u/5093293?v=4&s=117" width="117">](https://github.com/Deedasmi) |[<img alt="vmchale" src="https://avatars1.githubusercontent.com/u/13259982?v=4&s=117" width="117">](https://github.com/vmchale) |[<img alt="messense" src="https://avatars0.githubusercontent.com/u/1556054?v=4&s=117" width="117">](https://github.com/messense) | [<img alt="nelsonjchen" src="https://avatars1.githubusercontent.com/u/5363?v=4&s=117" width="117">](https://github.com/nelsonjchen) |[<img alt="pkgw" src="https://avatars0.githubusercontent.com/u/59598?v=4&s=117" width="117">](https://github.com/pkgw) |[<img alt="Deedasmi" src="https://avatars0.githubusercontent.com/u/5093293?v=4&s=117" width="117">](https://github.com/Deedasmi) |[<img alt="vmchale" src="https://avatars1.githubusercontent.com/u/13259982?v=4&s=117" width="117">](https://github.com/vmchale) |[<img alt="messense" src="https://avatars0.githubusercontent.com/u/1556054?v=4&s=117" width="117">](https://github.com/messense) |[<img alt="Keats" src="https://avatars2.githubusercontent.com/u/680355?v=4&s=117" width="117">](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) |
[<img alt="Keats" src="https://avatars2.githubusercontent.com/u/680355?v=4&s=117" width="117">](https://github.com/Keats) |[<img alt="starkat99" src="https://avatars1.githubusercontent.com/u/8295111?v=4&s=117" width="117">](https://github.com/starkat99) |[<img alt="durka" src="https://avatars3.githubusercontent.com/u/47007?v=4&s=117" width="117">](https://github.com/durka) |[<img alt="alex-gulyas" src="https://avatars0.githubusercontent.com/u/8698329?v=4&s=117" width="117">](https://github.com/alex-gulyas) |[<img alt="cite-reader" src="https://avatars1.githubusercontent.com/u/4196987?v=4&s=117" width="117">](https://github.com/cite-reader) |[<img alt="alexbool" src="https://avatars3.githubusercontent.com/u/1283792?v=4&s=117" width="117">](https://github.com/alexbool) | [<img alt="starkat99" src="https://avatars1.githubusercontent.com/u/8295111?v=4&s=117" width="117">](https://github.com/starkat99) |[<img alt="durka" src="https://avatars3.githubusercontent.com/u/47007?v=4&s=117" width="117">](https://github.com/durka) |[<img alt="alex-gulyas" src="https://avatars0.githubusercontent.com/u/8698329?v=4&s=117" width="117">](https://github.com/alex-gulyas) |[<img alt="cite-reader" src="https://avatars1.githubusercontent.com/u/4196987?v=4&s=117" width="117">](https://github.com/cite-reader) |[<img alt="alexbool" src="https://avatars3.githubusercontent.com/u/1283792?v=4&s=117" width="117">](https://github.com/alexbool) |[<img alt="AluisioASG" src="https://avatars2.githubusercontent.com/u/1904165?v=4&s=117" width="117">](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) |
[<img alt="AluisioASG" src="https://avatars2.githubusercontent.com/u/1904165?v=4&s=117" width="117">](https://github.com/AluisioASG) |[<img alt="BurntSushi" src="https://avatars3.githubusercontent.com/u/456674?v=4&s=117" width="117">](https://github.com/BurntSushi) |[<img alt="nox" src="https://avatars0.githubusercontent.com/u/123095?v=4&s=117" width="117">](https://github.com/nox) |[<img alt="pixelistik" src="https://avatars1.githubusercontent.com/u/170929?v=4&s=117" width="117">](https://github.com/pixelistik) |[<img alt="brennie" src="https://avatars3.githubusercontent.com/u/156585?v=4&s=117" width="117">](https://github.com/brennie) |[<img alt="ogham" src="https://avatars3.githubusercontent.com/u/503760?v=4&s=117" width="117">](https://github.com/ogham) | [<img alt="BurntSushi" src="https://avatars3.githubusercontent.com/u/456674?v=4&s=117" width="117">](https://github.com/BurntSushi) |[<img alt="nox" src="https://avatars0.githubusercontent.com/u/123095?v=4&s=117" width="117">](https://github.com/nox) |[<img alt="mitsuhiko" src="https://avatars1.githubusercontent.com/u/7396?v=4&s=117" width="117">](https://github.com/mitsuhiko) |[<img alt="brennie" src="https://avatars3.githubusercontent.com/u/156585?v=4&s=117" width="117">](https://github.com/brennie) |[<img alt="ogham" src="https://avatars3.githubusercontent.com/u/503760?v=4&s=117" width="117">](https://github.com/ogham) |[<img alt="pixelistik" src="https://avatars1.githubusercontent.com/u/170929?v=4&s=117" width="117">](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) |
[<img alt="Bilalh" src="https://avatars0.githubusercontent.com/u/171602?v=4&s=117" width="117">](https://github.com/Bilalh) |[<img alt="dotdash" src="https://avatars1.githubusercontent.com/u/230962?v=4&s=117" width="117">](https://github.com/dotdash) |[<img alt="bradurani" src="https://avatars0.githubusercontent.com/u/4195952?v=4&s=117" width="117">](https://github.com/bradurani) |[<img alt="Seeker14491" src="https://avatars2.githubusercontent.com/u/6490497?v=4&s=117" width="117">](https://github.com/Seeker14491) |[<img alt="brianp" src="https://avatars1.githubusercontent.com/u/179134?v=4&s=117" width="117">](https://github.com/brianp) |[<img alt="casey" src="https://avatars2.githubusercontent.com/u/1945?v=4&s=117" width="117">](https://github.com/casey) | [<img alt="dotdash" src="https://avatars1.githubusercontent.com/u/230962?v=4&s=117" width="117">](https://github.com/dotdash) |[<img alt="bradurani" src="https://avatars0.githubusercontent.com/u/4195952?v=4&s=117" width="117">](https://github.com/bradurani) |[<img alt="Seeker14491" src="https://avatars2.githubusercontent.com/u/6490497?v=4&s=117" width="117">](https://github.com/Seeker14491) |[<img alt="brianp" src="https://avatars1.githubusercontent.com/u/179134?v=4&s=117" width="117">](https://github.com/brianp) |[<img alt="cldershem" src="https://avatars3.githubusercontent.com/u/201608?v=4&s=117" width="117">](https://github.com/cldershem) |[<img alt="casey" src="https://avatars2.githubusercontent.com/u/1945?v=4&s=117" width="117">](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) |
[<img alt="volks73" src="https://avatars1.githubusercontent.com/u/1915469?v=4&s=117" width="117">](https://github.com/volks73) |[<img alt="daboross" src="https://avatars1.githubusercontent.com/u/1152146?v=4&s=117" width="117">](https://github.com/daboross) |[<img alt="mernen" src="https://avatars0.githubusercontent.com/u/6412?v=4&s=117" width="117">](https://github.com/mernen) |[<img alt="dguo" src="https://avatars0.githubusercontent.com/u/2763135?v=4&s=117" width="117">](https://github.com/dguo) |[<img alt="davidszotten" src="https://avatars3.githubusercontent.com/u/412005?v=4&s=117" width="117">](https://github.com/davidszotten) |[<img alt="drusellers" src="https://avatars1.githubusercontent.com/u/63355?v=4&s=117" width="117">](https://github.com/drusellers) | [<img alt="volks73" src="https://avatars1.githubusercontent.com/u/1915469?v=4&s=117" width="117">](https://github.com/volks73) |[<img alt="daboross" src="https://avatars1.githubusercontent.com/u/1152146?v=4&s=117" width="117">](https://github.com/daboross) |[<img alt="mernen" src="https://avatars0.githubusercontent.com/u/6412?v=4&s=117" width="117">](https://github.com/mernen) |[<img alt="dguo" src="https://avatars0.githubusercontent.com/u/2763135?v=4&s=117" width="117">](https://github.com/dguo) |[<img alt="davidszotten" src="https://avatars3.githubusercontent.com/u/412005?v=4&s=117" width="117">](https://github.com/davidszotten) |[<img alt="drusellers" src="https://avatars1.githubusercontent.com/u/63355?v=4&s=117" width="117">](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) | [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) |
[<img alt="eddyb" src="https://avatars2.githubusercontent.com/u/77424?v=4&s=117" width="117">](https://github.com/eddyb) |[<img alt="Fraser999" src="https://avatars3.githubusercontent.com/u/190532?v=4&s=117" width="117">](https://github.com/Fraser999) |[<img alt="birkenfeld" src="https://avatars0.githubusercontent.com/u/144359?v=4&s=117" width="117">](https://github.com/birkenfeld) |[<img alt="guanqun" src="https://avatars0.githubusercontent.com/u/53862?v=4&s=117" width="117">](https://github.com/guanqun) |[<img alt="tanakh" src="https://avatars2.githubusercontent.com/u/109069?v=4&s=117" width="117">](https://github.com/tanakh) |[<img alt="SirVer" src="https://avatars0.githubusercontent.com/u/140115?v=4&s=117" width="117">](https://github.com/SirVer) | [<img alt="eddyb" src="https://avatars2.githubusercontent.com/u/77424?v=4&s=117" width="117">](https://github.com/eddyb) |[<img alt="Enet4" src="https://avatars0.githubusercontent.com/u/4738426?v=4&s=117" width="117">](https://github.com/Enet4) |[<img alt="Fraser999" src="https://avatars3.githubusercontent.com/u/190532?v=4&s=117" width="117">](https://github.com/Fraser999) |[<img alt="birkenfeld" src="https://avatars0.githubusercontent.com/u/144359?v=4&s=117" width="117">](https://github.com/birkenfeld) |[<img alt="guanqun" src="https://avatars0.githubusercontent.com/u/53862?v=4&s=117" width="117">](https://github.com/guanqun) |[<img alt="tanakh" src="https://avatars2.githubusercontent.com/u/109069?v=4&s=117" width="117">](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) |
[<img alt="idmit" src="https://avatars1.githubusercontent.com/u/2546728?v=4&s=117" width="117">](https://github.com/idmit) |[<img alt="archer884" src="https://avatars1.githubusercontent.com/u/679494?v=4&s=117" width="117">](https://github.com/archer884) |[<img alt="jacobmischka" src="https://avatars1.githubusercontent.com/u/3939997?v=4&s=117" width="117">](https://github.com/jacobmischka) |[<img alt="jespino" src="https://avatars0.githubusercontent.com/u/290303?v=4&s=117" width="117">](https://github.com/jespino) |[<img alt="jfrankenau" src="https://avatars3.githubusercontent.com/u/2736480?v=4&s=117" width="117">](https://github.com/jfrankenau) |[<img alt="jtdowney" src="https://avatars1.githubusercontent.com/u/44654?v=4&s=117" width="117">](https://github.com/jtdowney) | [<img alt="SirVer" src="https://avatars0.githubusercontent.com/u/140115?v=4&s=117" width="117">](https://github.com/SirVer) |[<img alt="idmit" src="https://avatars1.githubusercontent.com/u/2546728?v=4&s=117" width="117">](https://github.com/idmit) |[<img alt="archer884" src="https://avatars1.githubusercontent.com/u/679494?v=4&s=117" width="117">](https://github.com/archer884) |[<img alt="jacobmischka" src="https://avatars1.githubusercontent.com/u/3939997?v=4&s=117" width="117">](https://github.com/jacobmischka) |[<img alt="jespino" src="https://avatars0.githubusercontent.com/u/290303?v=4&s=117" width="117">](https://github.com/jespino) |[<img alt="jfrankenau" src="https://avatars3.githubusercontent.com/u/2736480?v=4&s=117" width="117">](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) |
[<img alt="andete" src="https://avatars2.githubusercontent.com/u/689017?v=4&s=117" width="117">](https://github.com/andete) |[<img alt="joshtriplett" src="https://avatars2.githubusercontent.com/u/162737?v=4&s=117" width="117">](https://github.com/joshtriplett) |[<img alt="Kalwyn" src="https://avatars3.githubusercontent.com/u/22778640?v=4&s=117" width="117">](https://github.com/Kalwyn) |[<img alt="manuel-rhdt" src="https://avatars1.githubusercontent.com/u/3199013?v=4&s=117" width="117">](https://github.com/manuel-rhdt) |[<img alt="Marwes" src="https://avatars3.githubusercontent.com/u/957312?v=4&s=117" width="117">](https://github.com/Marwes) |[<img alt="mdaffin" src="https://avatars1.githubusercontent.com/u/171232?v=4&s=117" width="117">](https://github.com/mdaffin) | [<img alt="jtdowney" src="https://avatars1.githubusercontent.com/u/44654?v=4&s=117" width="117">](https://github.com/jtdowney) |[<img alt="andete" src="https://avatars2.githubusercontent.com/u/689017?v=4&s=117" width="117">](https://github.com/andete) |[<img alt="joshtriplett" src="https://avatars2.githubusercontent.com/u/162737?v=4&s=117" width="117">](https://github.com/joshtriplett) |[<img alt="Kalwyn" src="https://avatars3.githubusercontent.com/u/22778640?v=4&s=117" width="117">](https://github.com/Kalwyn) |[<img alt="manuel-rhdt" src="https://avatars1.githubusercontent.com/u/3199013?v=4&s=117" width="117">](https://github.com/manuel-rhdt) |[<img alt="Marwes" src="https://avatars3.githubusercontent.com/u/957312?v=4&s=117" width="117">](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) |
[<img alt="iliekturtles" src="https://avatars3.githubusercontent.com/u/5081378?v=4&s=117" width="117">](https://github.com/iliekturtles) |[<img alt="nicompte" src="https://avatars2.githubusercontent.com/u/439369?v=4&s=117" width="117">](https://github.com/nicompte) |[<img alt="NickeZ" src="https://avatars2.githubusercontent.com/u/492753?v=4&s=117" width="117">](https://github.com/NickeZ) |[<img alt="nvzqz" src="https://avatars0.githubusercontent.com/u/10367662?v=4&s=117" width="117">](https://github.com/nvzqz) |[<img alt="nuew" src="https://avatars2.githubusercontent.com/u/26099511?v=4&s=117" width="117">](https://github.com/nuew) |[<img alt="Geogi" src="https://avatars1.githubusercontent.com/u/1818316?v=4&s=117" width="117">](https://github.com/Geogi) | [<img alt="mdaffin" src="https://avatars1.githubusercontent.com/u/171232?v=4&s=117" width="117">](https://github.com/mdaffin) |[<img alt="iliekturtles" src="https://avatars3.githubusercontent.com/u/5081378?v=4&s=117" width="117">](https://github.com/iliekturtles) |[<img alt="nicompte" src="https://avatars2.githubusercontent.com/u/439369?v=4&s=117" width="117">](https://github.com/nicompte) |[<img alt="NickeZ" src="https://avatars2.githubusercontent.com/u/492753?v=4&s=117" width="117">](https://github.com/NickeZ) |[<img alt="nvzqz" src="https://avatars0.githubusercontent.com/u/10367662?v=4&s=117" width="117">](https://github.com/nvzqz) |[<img alt="nuew" src="https://avatars2.githubusercontent.com/u/26099511?v=4&s=117" width="117">](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) |
[<img alt="focusaurus" src="https://avatars1.githubusercontent.com/u/482377?v=4&s=117" width="117">](https://github.com/focusaurus) |[<img alt="flying-sheep" src="https://avatars0.githubusercontent.com/u/291575?v=4&s=117" width="117">](https://github.com/flying-sheep) |[<img alt="Phlosioneer" src="https://avatars2.githubusercontent.com/u/4657718?v=4&s=117" width="117">](https://github.com/Phlosioneer) |[<img alt="peppsac" src="https://avatars3.githubusercontent.com/u/2198295?v=4&s=117" width="117">](https://github.com/peppsac) |[<img alt="golddranks" src="https://avatars1.githubusercontent.com/u/2675542?v=4&s=117" width="117">](https://github.com/golddranks) |[<img alt="hexjelly" src="https://avatars0.githubusercontent.com/u/435283?v=4&s=117" width="117">](https://github.com/hexjelly) | [<img alt="Geogi" src="https://avatars1.githubusercontent.com/u/1818316?v=4&s=117" width="117">](https://github.com/Geogi) |[<img alt="focusaurus" src="https://avatars1.githubusercontent.com/u/482377?v=4&s=117" width="117">](https://github.com/focusaurus) |[<img alt="flying-sheep" src="https://avatars0.githubusercontent.com/u/291575?v=4&s=117" width="117">](https://github.com/flying-sheep) |[<img alt="Phlosioneer" src="https://avatars2.githubusercontent.com/u/4657718?v=4&s=117" width="117">](https://github.com/Phlosioneer) |[<img alt="peppsac" src="https://avatars3.githubusercontent.com/u/2198295?v=4&s=117" width="117">](https://github.com/peppsac) |[<img alt="golddranks" src="https://avatars1.githubusercontent.com/u/2675542?v=4&s=117" width="117">](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) |
[<img alt="rnelson" src="https://avatars3.githubusercontent.com/u/118361?v=4&s=117" width="117">](https://github.com/rnelson) |[<img alt="swatteau" src="https://avatars3.githubusercontent.com/u/5521255?v=4&s=117" width="117">](https://github.com/swatteau) |[<img alt="tspiteri" src="https://avatars0.githubusercontent.com/u/18604588?v=4&s=117" width="117">](https://github.com/tspiteri) |[<img alt="siiptuo" src="https://avatars0.githubusercontent.com/u/10729330?v=4&s=117" width="117">](https://github.com/siiptuo) |[<img alt="vks" src="https://avatars2.githubusercontent.com/u/33460?v=4&s=117" width="117">](https://github.com/vks) |[<img alt="vsupalov" src="https://avatars2.githubusercontent.com/u/2801030?v=4&s=117" width="117">](https://github.com/vsupalov) | [<img alt="hexjelly" src="https://avatars0.githubusercontent.com/u/435283?v=4&s=117" width="117">](https://github.com/hexjelly) |[<img alt="rom1v" src="https://avatars1.githubusercontent.com/u/543275?v=4&s=117" width="117">](https://github.com/rom1v) |[<img alt="rnelson" src="https://avatars3.githubusercontent.com/u/118361?v=4&s=117" width="117">](https://github.com/rnelson) |[<img alt="segevfiner" src="https://avatars0.githubusercontent.com/u/24731903?v=4&s=117" width="117">](https://github.com/segevfiner) |[<img alt="swatteau" src="https://avatars3.githubusercontent.com/u/5521255?v=4&s=117" width="117">](https://github.com/swatteau) |[<img alt="tspiteri" src="https://avatars0.githubusercontent.com/u/18604588?v=4&s=117" width="117">](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) |
[<img alt="mineo" src="https://avatars1.githubusercontent.com/u/78236?v=4&s=117" width="117">](https://github.com/mineo) |[<img alt="wabain" src="https://avatars3.githubusercontent.com/u/7651435?v=4&s=117" width="117">](https://github.com/wabain) |[<img alt="grossws" src="https://avatars2.githubusercontent.com/u/171284?v=4&s=117" width="117">](https://github.com/grossws) |[<img alt="kennytm" src="https://avatars1.githubusercontent.com/u/103023?v=4&s=117" width="117">](https://github.com/kennytm) |[<img alt="mvaude" src="https://avatars1.githubusercontent.com/u/9532611?v=4&s=117" width="117">](https://github.com/mvaude) |[<img alt="panicbit" src="https://avatars2.githubusercontent.com/u/628445?v=4&s=117" width="117">](https://github.com/panicbit) | [<img alt="siiptuo" src="https://avatars0.githubusercontent.com/u/10729330?v=4&s=117" width="117">](https://github.com/siiptuo) |[<img alt="vks" src="https://avatars2.githubusercontent.com/u/33460?v=4&s=117" width="117">](https://github.com/vks) |[<img alt="vsupalov" src="https://avatars2.githubusercontent.com/u/2801030?v=4&s=117" width="117">](https://github.com/vsupalov) |[<img alt="mineo" src="https://avatars1.githubusercontent.com/u/78236?v=4&s=117" width="117">](https://github.com/mineo) |[<img alt="wabain" src="https://avatars3.githubusercontent.com/u/7651435?v=4&s=117" width="117">](https://github.com/wabain) |[<img alt="grossws" src="https://avatars2.githubusercontent.com/u/171284?v=4&s=117" width="117">](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) |
[<img alt="mitsuhiko" src="https://avatars1.githubusercontent.com/u/7396?v=4&s=117" width="117">](https://github.com/mitsuhiko) | [<img alt="kennytm" src="https://avatars1.githubusercontent.com/u/103023?v=4&s=117" width="117">](https://github.com/kennytm) |[<img alt="mvaude" src="https://avatars1.githubusercontent.com/u/9532611?v=4&s=117" width="117">](https://github.com/mvaude) |[<img alt="panicbit" src="https://avatars2.githubusercontent.com/u/628445?v=4&s=117" width="117">](https://github.com/panicbit) |[<img alt="Bilalh" src="https://avatars0.githubusercontent.com/u/171602?v=4&s=117" width="117">](https://github.com/Bilalh) |
:---: | :---: |:---: |:---: |:---: |
[mitsuhiko](https://github.com/mitsuhiko) | [kennytm](https://github.com/kennytm) |[mvaude](https://github.com/mvaude) |[panicbit](https://github.com/panicbit) |[Bilalh](https://github.com/Bilalh) |

View file

@ -1,7 +1,7 @@
[package] [package]
name = "clap" name = "clap"
version = "2.29.0" version = "2.29.1"
authors = ["Kevin K. <kbknapp@gmail.com>"] authors = ["Kevin K. <kbknapp@gmail.com>"]
exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"] exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
repository = "https://github.com/kbknapp/clap-rs" repository = "https://github.com/kbknapp/clap-rs"

View file

@ -42,6 +42,15 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
## What's New ## 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: 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 * **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: 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: Finally we create our `main.rs` file just like we would have with the previous two examples:

View file

@ -43,7 +43,7 @@ fn parse_complex(b: &mut Bencher) {
app_short().get_matches_from(vec!["rg", app_short().get_matches_from(vec!["rg",
"pat", "pat",
"-cFlN", "-cFlN",
"-pqr", "-pqr=some",
"--null", "--null",
"--no-filename", "--no-filename",
"--no-messages", "--no-messages",

View file

@ -39,6 +39,16 @@ mod test {
assert_eq!(stderr, err.use_stderr()); assert_eq!(stderr, err.use_stderr());
compare(left, right) 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::<Vec<_>>());
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 // Legacy tests from the pyhton script days

View file

@ -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;
}
};
}

View file

@ -1,6 +1,4 @@
mod settings; mod settings;
#[macro_use]
mod macros;
pub mod parser; pub mod parser;
mod meta; mod meta;
mod help; mod help;

View file

@ -61,8 +61,7 @@ where
pub global_args: Vec<Arg<'a, 'b>>, pub global_args: Vec<Arg<'a, 'b>>,
pub required: Vec<&'a str>, pub required: Vec<&'a str>,
pub r_ifs: Vec<(&'a str, &'b str, &'a str)>, pub r_ifs: Vec<(&'a str, &'b str, &'a str)>,
pub blacklist: Vec<&'b str>, pub overrides: Vec<(&'b str, &'a str)>,
pub overrides: Vec<&'b str>,
help_short: Option<char>, help_short: Option<char>,
version_short: Option<char>, version_short: Option<char>,
cache: Option<&'a str>, cache: Option<&'a str>,
@ -346,9 +345,9 @@ where
if let Some(ref reqs) = group.requires { if let Some(ref reqs) = group.requires {
self.required.extend_from_slice(reqs); self.required.extend_from_slice(reqs);
} }
if let Some(ref bl) = group.conflicts { // if let Some(ref bl) = group.conflicts {
self.blacklist.extend_from_slice(bl); // self.blacklist.extend_from_slice(bl);
} // }
} }
if self.groups.iter().any(|g| g.name == group.name) { if self.groups.iter().any(|g| g.name == group.name) {
let grp = self.groups 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 // 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))] #[cfg_attr(feature = "lints", allow(wrong_self_convention))]
fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult<'a>) -> bool { fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult) -> bool {
debugln!( debugln!( "Parser::is_new_arg:{:?}:{:?}", arg_os, needs_val_of);
"Parser::is_new_arg: arg={:?}, Needs Val of={:?}",
arg_os,
needs_val_of
);
let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) { let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) {
true true
} else if self.is_set(AS::AllowNegativeNumbers) { } else if self.is_set(AS::AllowNegativeNumbers) {
@ -807,12 +802,10 @@ where
.expect(INTERNAL_ERROR_MSG); .expect(INTERNAL_ERROR_MSG);
(p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings) (p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings)
} }
ParseResult::ValuesDone => return true,
_ => false, _ => false,
}; };
debugln!( debugln!( "Parser::is_new_arg: arg_allows_tac={:?}", arg_allows_tac );
"Parser::is_new_arg: Arg::allow_leading_hyphen({:?})",
arg_allows_tac
);
// Is this a new argument, or values from a previous option? // Is this a new argument, or values from a previous option?
let mut ret = if arg_os.starts_with(b"--") { 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::<i64>().is_ok()
|| arg_os.to_string_lossy().parse::<f64>().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 { if let ParseResult::Opt(name) = needs_val_of {
// Check to see if parsing a value from a previous arg // Check to see if parsing a value from a previous arg
let arg = self.opts let arg = self.opts
@ -925,62 +963,20 @@ where
// get the next value from the iterator // get the next value from the iterator
continue; 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::<i64>().is_ok()
|| arg_os.to_string_lossy().parse::<f64>().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)) if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound))
&& !self.is_set(AS::InferSubcommands) && !self.is_set(AS::InferSubcommands)
{ {
if let Some(cdate) = if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self)) {
suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self)) return Err(Error::invalid_subcommand(
{ arg_os.to_string_lossy().into_owned(),
return Err(Error::invalid_subcommand( cdate,
arg_os.to_string_lossy().into_owned(), self.meta.bin_name.as_ref().unwrap_or(&self.meta.name),
cdate, &*usage::create_error_usage(self, matcher, None),
self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), self.color(),
&*usage::create_error_usage(self, matcher, None), ));
self.color(),
));
}
} }
} }
@ -1035,7 +1031,29 @@ where
self.color(), 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); self.settings.set(AS::ValidArgFound);
} else if self.is_set(AS::AllowExternalSubcommands) { } else if self.is_set(AS::AllowExternalSubcommands) {
// Get external subcommand name // 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) 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) { fn propagate_help_version(&mut self) {
debugln!("Parser::propagate_help_version;"); debugln!("Parser::propagate_help_version;");
@ -1483,7 +1526,6 @@ where
self.settings.set(AS::ValidArgFound); self.settings.set(AS::ValidArgFound);
let ret = self.parse_opt(val, opt, val.is_some(), matcher)?; let ret = self.parse_opt(val, opt, val.is_some(), matcher)?;
if self.cache.map_or(true, |name| name != opt.b.name) { if self.cache.map_or(true, |name| name != opt.b.name) {
arg_post_processing!(self, opt, matcher);
self.cache = Some(opt.b.name); self.cache = Some(opt.b.name);
} }
@ -1501,10 +1543,9 @@ where
self.parse_flag(flag, matcher)?; self.parse_flag(flag, matcher)?;
// Handle conflicts, requirements, etc. // Handle conflicts, requirements, etc.
// if self.cache.map_or(true, |name| name != flag.b.name) { if self.cache.map_or(true, |name| name != flag.b.name) {
arg_post_processing!(self, flag, matcher); self.cache = Some(flag.b.name);
// self.cache = Some(flag.b.name); }
// }
return Ok(ParseResult::Flag); return Ok(ParseResult::Flag);
} else if self.is_set(AS::AllowLeadingHyphen) { } else if self.is_set(AS::AllowLeadingHyphen) {
@ -1580,7 +1621,6 @@ where
let ret = self.parse_opt(val, opt, false, matcher)?; let ret = self.parse_opt(val, opt, false, matcher)?;
if self.cache.map_or(true, |name| name != opt.b.name) { if self.cache.map_or(true, |name| name != opt.b.name) {
arg_post_processing!(self, opt, matcher);
self.cache = Some(opt.b.name); self.cache = Some(opt.b.name);
} }
@ -1595,7 +1635,6 @@ where
// Handle conflicts, requirements, overrides, etc. // Handle conflicts, requirements, overrides, etc.
// Must be called here due to mutablilty // Must be called here due to mutablilty
if self.cache.map_or(true, |name| name != flag.b.name) { if self.cache.map_or(true, |name| name != flag.b.name) {
arg_post_processing!(self, flag, matcher);
self.cache = Some(flag.b.name); self.cache = Some(flag.b.name);
} }
} else { } else {
@ -1844,7 +1883,6 @@ where
$_self.add_val_to_arg($a, OsStr::new(val), $m)?; $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) { if $_self.cache.map_or(true, |name| name != $a.name()) {
arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name()); $_self.cache = Some($a.name());
} }
} else if $m.get($a.b.name).is_some() { } else if $m.get($a.b.name).is_some() {
@ -1855,7 +1893,6 @@ where
$_self.add_val_to_arg($a, OsStr::new(val), $m)?; $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) { if $_self.cache.map_or(true, |name| name != $a.name()) {
arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name()); $_self.cache = Some($a.name());
} }
} }
@ -1881,7 +1918,6 @@ where
if add { if add {
$_self.add_val_to_arg($a, OsStr::new(default), $m)?; $_self.add_val_to_arg($a, OsStr::new(default), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) { if $_self.cache.map_or(true, |name| name != $a.name()) {
arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name()); $_self.cache = Some($a.name());
} }
done = true; done = true;
@ -1920,7 +1956,6 @@ where
$_self.add_val_to_arg($a, OsStr::new(val), $m)?; $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) { if $_self.cache.map_or(true, |name| name != $a.name()) {
arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name()); $_self.cache = Some($a.name());
} }
} }
@ -1929,7 +1964,6 @@ where
$_self.add_val_to_arg($a, OsStr::new(val), $m)?; $_self.add_val_to_arg($a, OsStr::new(val), $m)?;
if $_self.cache.map_or(true, |name| name != $a.name()) { if $_self.cache.map_or(true, |name| name != $a.name()) {
arg_post_processing!($_self, $a, $m);
$_self.cache = Some($a.name()); $_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) { if let Some(f) = find_by_name!(self, name, flags, iter) {
return Some(f); return Some(f);
} }

View file

@ -78,7 +78,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(()) Ok(())
} }
fn validate_values<A>( fn validate_arg_values<A>(
&self, &self,
arg: &A, arg: &A,
ma: &MatchedArg, ma: &MatchedArg,
@ -87,11 +87,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
where where
A: AnyArg<'a, 'b> + Display, 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 { for val in &ma.vals {
if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() { if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
debugln!( debugln!(
"Validator::validate_values: invalid UTF-8 found in val {:?}", "Validator::validate_arg_values: invalid UTF-8 found in val {:?}",
val val
); );
return Err(Error::invalid_utf8( 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() { 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 val_str = val.to_string_lossy();
let ok = if arg.is_set(ArgSettings::CaseInsensitive) { let ok = if arg.is_set(ArgSettings::CaseInsensitive) {
p_vals.iter().any(|pv| pv.eq_ignore_ascii_case(&*val_str)) 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_() if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_()
&& matcher.contains(&*arg.name()) && 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( return Err(Error::empty_value(
arg, arg,
&*usage::create_error_usage(self.0, matcher, None), &*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() { 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()) { if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
sdebugln!("error"); sdebugln!("error");
return Err(Error::value_validation(Some(arg), e, self.0.color())); 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() { 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) { if let Err(e) = vtor(val) {
sdebugln!("error"); sdebugln!("error");
return Err(Error::value_validation( return Err(Error::value_validation(
@ -153,44 +153,83 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(()) Ok(())
} }
fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> { fn build_err(&self, name: &str, matcher: &ArgMatcher) -> ClapResult<()> {
debugln!( debugln!("build_err!: name={}", name);
"Validator::validate_blacklist: blacklist={:?}", let mut c_with = find_from!(self.0, &name, blacklist, &matcher);
self.0.blacklist 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 { debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name);
($p:expr, $name:expr, $matcher:ident) => ({ // matcher.remove(&name);
debugln!("build_err!: name={}", $name); let usg = usage::create_error_usage(self.0, matcher, None);
let mut c_with = find_from!($p, &$name, blacklist, &$matcher); if let Some(f) = find_by_name!(self.0, name, flags, iter) {
c_with = c_with.or( debugln!("build_err!: It was a flag...");
$p.find_any_arg(&$name).map_or(None, |aa| aa.blacklist()) Err(Error::argument_conflict(f, c_with, &*usg, self.0.color()))
.map_or(None, } else if let Some(o) = find_by_name!(self.0, name, opts, iter) {
|bl| bl.iter().find(|arg| $matcher.contains(arg))) debugln!("build_err!: It was an option...");
.map_or(None, |an| $p.find_any_arg(an)) Err(Error::argument_conflict(o, c_with, &*usg, self.0.color()))
.map_or(None, |aa| Some(format!("{}", aa))) } else {
); match find_by_name!(self.0, name, positionals, values) {
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &$name); Some(p) => {
$matcher.remove(&$name); debugln!("build_err!: It was a positional...");
let usg = usage::create_error_usage($p, $matcher, None); Err(Error::argument_conflict(p, c_with, &*usg, self.0.color()))
if let Some(f) = find_by_name!($p, $name, flags, iter) { },
debugln!("build_err!: It was a flag..."); None => panic!(INTERNAL_ERROR_MSG)
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 { fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
match find_by_name!($p, $name, positionals, values) { debugln!("Validator::validate_blacklist;");
Some(p) => { let mut conflicts: Vec<&str> = vec![];
debugln!("build_err!: It was a positional..."); for (&name, _) in matcher.iter() {
Error::argument_conflict(p, c_with, &*usg, self.0.color()) debugln!("Validator::validate_blacklist:iter:{};", name);
}, if let Some(grps) = self.0.groups_for_arg(name) {
None => panic!(INTERNAL_ERROR_MSG) 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!( debugln!(
"Validator::validate_blacklist:iter:{}: Checking blacklisted arg", "Validator::validate_blacklist:iter:{}: Checking blacklisted arg",
name name
@ -213,7 +252,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
name, name,
n n
); );
return Err(build_err!(self.0, n, matcher)); return self.build_err(n, matcher);
} }
} }
} else if let Some(ma) = matcher.get(name) { } 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; should_err = ma.occurs > 0;
} }
if should_err { if should_err {
return Err(build_err!(self.0, *name, matcher)); return self.build_err(*name, matcher);
} }
} }
Ok(()) 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) { if let Some(opt) = find_by_name!(self.0, *name, opts, iter) {
self.validate_arg_num_vals(opt, ma, matcher)?; 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_requires(opt, ma, matcher)?;
self.validate_arg_num_occurs(opt, ma, matcher)?; self.validate_arg_num_occurs(opt, ma, matcher)?;
} else if let Some(flag) = find_by_name!(self.0, *name, flags, iter) { } 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) { } 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_vals(pos, ma, matcher)?;
self.validate_arg_num_occurs(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)?; self.validate_arg_requires(pos, ma, matcher)?;
} else { } else {
let grp = self.0 let grp = self.0
@ -381,7 +420,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
where where
A: AnyArg<'a, 'b> + Display, A: AnyArg<'a, 'b> + Display,
{ {
debugln!("Validator::validate_arg_requires;"); debugln!("Validator::validate_arg_requires:{};", a.name());
if let Some(a_reqs) = a.requires() { if let Some(a_reqs) = a.requires() {
for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) { for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
let missing_req = let missing_req =
@ -390,6 +429,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
return self.missing_required_error(matcher, None); 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(()) Ok(())
} }
@ -399,20 +443,13 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
"Validator::validate_required: required={:?};", "Validator::validate_required: required={:?};",
self.0.required self.0.required
); );
'outer: for name in &self.0.required { 'outer: for name in &self.0.required {
debugln!("Validator::validate_required:iter:{}:", name); debugln!("Validator::validate_required:iter:{}:", name);
if matcher.contains(name) { if matcher.contains(name) {
continue 'outer; continue 'outer;
} }
if let Some(a) = find_by_name!(self.0, *name, flags, iter) { if let Some(a) = find_any_by_name!(self.0, *name) {
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 self.is_missing_required_ok(a, matcher) { if self.is_missing_required_ok(a, matcher) {
continue 'outer; continue 'outer;
} }
@ -431,11 +468,8 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(()) Ok(())
} }
fn validate_conflicts<A>(&self, a: &A, matcher: &ArgMatcher) -> Option<bool> fn validate_arg_conflicts(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> {
where debugln!("Validator::validate_arg_conflicts: a={:?};", a.name());
A: AnyArg<'a, 'b>,
{
debugln!("Validator::validate_conflicts: a={:?};", a.name());
a.blacklist().map(|bl| { a.blacklist().map(|bl| {
bl.iter().any(|conf| { bl.iter().any(|conf| {
matcher.contains(conf) matcher.contains(conf)
@ -448,10 +482,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
}) })
} }
fn validate_required_unless<A>(&self, a: &A, matcher: &ArgMatcher) -> Option<bool> fn validate_required_unless(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> {
where
A: AnyArg<'a, 'b>,
{
debugln!("Validator::validate_required_unless: a={:?};", a.name()); debugln!("Validator::validate_required_unless: a={:?};", a.name());
macro_rules! check { macro_rules! check {
($how:ident, $_self:expr, $a:ident, $m:ident) => {{ ($how:ident, $_self:expr, $a:ident, $m:ident) => {{
@ -506,12 +537,9 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
} }
#[inline] #[inline]
fn is_missing_required_ok<A>(&self, a: &A, matcher: &ArgMatcher) -> bool fn is_missing_required_ok(&self, a: &AnyArg, matcher: &ArgMatcher) -> bool {
where
A: AnyArg<'a, 'b>,
{
debugln!("Validator::is_missing_required_ok: a={}", a.name()); 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) || self.validate_required_unless(a, matcher).unwrap_or(false)
} }
} }

View file

@ -6,6 +6,7 @@ use std::ffi::{OsStr, OsString};
// Internal // Internal
use args::settings::ArgSettings; use args::settings::ArgSettings;
use map::{self, VecMap}; use map::{self, VecMap};
use INTERNAL_ERROR_MSG;
#[doc(hidden)] #[doc(hidden)]
pub trait AnyArg<'n, 'e>: std_fmt::Display { pub trait AnyArg<'n, 'e>: std_fmt::Display {
@ -41,3 +42,33 @@ pub trait AnyArg<'n, 'e>: std_fmt::Display {
pub trait DispOrder { pub trait DispOrder {
fn disp_ord(&self) -> usize; 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<Vec<&'e str>> { (*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<u64> { (*self).max_vals() }
fn min_vals(&self) -> Option<u64> { (*self).min_vals() }
fn num_vals(&self) -> Option<u64> { (*self).num_vals() }
fn possible_vals(&self) -> Option<&[&'e str]> { (*self).possible_vals() }
fn validator(&self) -> Option<&Rc<Fn(String) -> Result<(), String>>> { (*self).validator() }
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> Result<(), OsString>>> { (*self).validator_os() }
fn short(&self) -> Option<char> { (*self).short() }
fn long(&self) -> Option<&'e str> { (*self).long() }
fn val_delim(&self) -> Option<char> { (*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<map::Values<(&'n str, Option<&'e OsStr>, &'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() }
}

View file

@ -21,11 +21,36 @@ impl<'a> Default for ArgMatcher<'a> {
impl<'a> ArgMatcher<'a> { impl<'a> ArgMatcher<'a> {
pub fn new() -> Self { ArgMatcher::default() } 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]) { pub fn propagate_globals(&mut self, global_arg_vec: &[&'a str]) {
debugln!( debugln!( "ArgMatcher::get_global_values: global_arg_vec={:?}", global_arg_vec );
"ArgMatcher::get_global_values: global_arg_vec={:?}",
global_arg_vec
);
let mut vals_map = HashMap::new(); let mut vals_map = HashMap::new();
self.fill_in_global_values(global_arg_vec, &mut vals_map); self.fill_in_global_values(global_arg_vec, &mut vals_map);
} }

View file

@ -81,10 +81,11 @@ complete -F _{name} -o bashdefault -o default {name}
subcmds = format!( subcmds = format!(
"{} "{}
{name}) {name})
cmd+=\"__{name}\" cmd+=\"__{fn_name}\"
;;", ;;",
subcmds, subcmds,
name = sc.replace("-", "__") name = sc,
fn_name = sc.replace("-", "__")
); );
} }

View file

@ -371,7 +371,7 @@ fn write_opts_of(p: &Parser) -> String {
} }
if let Some(long) = o.long() { if let Some(long) = o.long() {
let l = format!( let l = format!(
"'{conflicts}{multiple}--{arg}+[{help}]{possible_values}' \\", "'{conflicts}{multiple}--{arg}=[{help}]{possible_values}' \\",
conflicts = conflicts, conflicts = conflicts,
multiple = multiple, multiple = multiple,
arg = long, arg = long,

View file

@ -8,7 +8,7 @@ use std::process;
use std::result::Result as StdResult; use std::result::Result as StdResult;
// Internal // Internal
use args::{AnyArg, FlagBuilder}; use args::AnyArg;
use fmt::{ColorWhen, Colorizer, ColorizerOption}; use fmt::{ColorWhen, Colorizer, ColorizerOption};
use suggestions; use suggestions;
@ -404,14 +404,13 @@ impl Error {
pub fn write_to<W: Write>(&self, w: &mut W) -> io::Result<()> { write!(w, "{}", self.message) } pub fn write_to<W: Write>(&self, w: &mut W) -> io::Result<()> { write!(w, "{}", self.message) }
#[doc(hidden)] #[doc(hidden)]
pub fn argument_conflict<'a, 'b, A, O, U>( pub fn argument_conflict<'a, 'b, O, U>(
arg: &A, arg: &AnyArg,
other: Option<O>, other: Option<O>,
usage: U, usage: U,
color: ColorWhen, color: ColorWhen,
) -> Self ) -> Self
where where
A: AnyArg<'a, 'b> + Display,
O: Into<String>, O: Into<String>,
U: Display, U: Display,
{ {
@ -444,9 +443,8 @@ impl Error {
} }
#[doc(hidden)] #[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 where
A: AnyArg<'a, 'b> + Display,
U: Display, U: Display,
{ {
let c = Colorizer::new(ColorizerOption { let c = Colorizer::new(ColorizerOption {
@ -470,17 +468,16 @@ impl Error {
} }
#[doc(hidden)] #[doc(hidden)]
pub fn invalid_value<'a, 'b, B, G, A, U>( pub fn invalid_value<'a, 'b, B, G, U>(
bad_val: B, bad_val: B,
good_vals: &[G], good_vals: &[G],
arg: &A, arg: &AnyArg,
usage: U, usage: U,
color: ColorWhen, color: ColorWhen,
) -> Self ) -> Self
where where
B: AsRef<str>, B: AsRef<str>,
G: AsRef<str> + Display, G: AsRef<str> + Display,
A: AnyArg<'a, 'b> + Display,
U: Display, U: Display,
{ {
let c = Colorizer::new(ColorizerOption { let c = Colorizer::new(ColorizerOption {
@ -660,10 +657,9 @@ impl Error {
} }
#[doc(hidden)] #[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 where
V: AsRef<str> + Display + ToOwned, V: AsRef<str> + Display + ToOwned,
A: AnyArg<'a, 'b> + Display,
U: Display, U: Display,
{ {
let v = val.as_ref(); let v = val.as_ref();
@ -689,15 +685,14 @@ impl Error {
} }
#[doc(hidden)] #[doc(hidden)]
pub fn too_few_values<'a, 'b, A, U>( pub fn too_few_values<'a, 'b, U>(
arg: &A, arg: &AnyArg,
min_vals: u64, min_vals: u64,
curr_vals: usize, curr_vals: usize,
usage: U, usage: U,
color: ColorWhen, color: ColorWhen,
) -> Self ) -> Self
where where
A: AnyArg<'a, 'b> + Display,
U: Display, U: Display,
{ {
let c = Colorizer::new(ColorizerOption { let c = Colorizer::new(ColorizerOption {
@ -724,9 +719,7 @@ impl Error {
} }
#[doc(hidden)] #[doc(hidden)]
pub fn value_validation<'a, 'b, A>(arg: Option<&A>, err: String, color: ColorWhen) -> Self pub fn value_validation<'a, 'b>(arg: Option<&AnyArg>, err: String, color: ColorWhen) -> Self
where
A: AnyArg<'a, 'b> + Display,
{ {
let c = Colorizer::new(ColorizerOption { let c = Colorizer::new(ColorizerOption {
use_stderr: true, use_stderr: true,
@ -750,13 +743,13 @@ impl Error {
#[doc(hidden)] #[doc(hidden)]
pub fn value_validation_auto(err: String) -> Self { 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) Error::value_validation(n, err, ColorWhen::Auto)
} }
#[doc(hidden)] #[doc(hidden)]
pub fn wrong_number_of_values<'a, 'b, A, S, U>( pub fn wrong_number_of_values<'a, 'b, S, U>(
arg: &A, arg: &AnyArg,
num_vals: u64, num_vals: u64,
curr_vals: usize, curr_vals: usize,
suffix: S, suffix: S,
@ -764,7 +757,6 @@ impl Error {
color: ColorWhen, color: ColorWhen,
) -> Self ) -> Self
where where
A: AnyArg<'a, 'b> + Display,
S: Display, S: Display,
U: Display, U: Display,
{ {
@ -792,9 +784,8 @@ impl Error {
} }
#[doc(hidden)] #[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 where
A: AnyArg<'a, 'b> + Display,
U: Display, U: Display,
{ {
let c = Colorizer::new(ColorizerOption { let c = Colorizer::new(ColorizerOption {

View file

@ -29,7 +29,7 @@
//! //!
//! The following examples show a quick example of some of the very basic functionality of `clap`. //! The following examples show a quick example of some of the very basic functionality of `clap`.
//! For more advanced usage, such as requirements, conflicts, groups, multiple values and //! For more advanced usage, such as requirements, conflicts, groups, multiple values and
//! occurrences see the [documentation](https://docs.rs/clap/), [examples/](examples) directory of //! occurrences see the [documentation](https://docs.rs/clap/), [examples/](https://github.com/kbknapp/clap-rs/tree/master/examples) directory of
//! this repository or the [video tutorials](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U). //! this repository or the [video tutorials](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U).
//! //!
//! **NOTE:** All of these examples are functionally the same, but show different styles in which to //! **NOTE:** All of these examples are functionally the same, but show different styles in which to
@ -366,13 +366,13 @@
//! * **Red** Color: **NOT** included by default (must use cargo `features` to enable) //! * **Red** Color: **NOT** included by default (must use cargo `features` to enable)
//! * **Blue** Color: Dev dependency, only used while developing. //! * **Blue** Color: Dev dependency, only used while developing.
//! //!
//! ![clap dependencies](clap_dep_graph.png) //! ![clap dependencies](https://raw.githubusercontent.com/kbknapp/clap-rs/master/clap_dep_graph.png)
//! //!
//! ### More Information //! ### More Information
//! //!
//! You can find complete documentation on the [docs.rs](https://docs.rs/clap/) for this project. //! You can find complete documentation on the [docs.rs](https://docs.rs/clap/) for this project.
//! //!
//! You can also find usage examples in the [examples/](examples) directory of this repo. //! You can also find usage examples in the [examples/](https://github.com/kbknapp/clap-rs/tree/master/examples) directory of this repo.
//! //!
//! #### Video Tutorials //! #### Video Tutorials
//! //!
@ -391,7 +391,7 @@
//! `clap`. You can either add it to the [examples/](examples) directory, or file an issue and tell //! `clap`. You can either add it to the [examples/](examples) directory, or file an issue and tell
//! me. I'm all about giving credit where credit is due :) //! me. I'm all about giving credit where credit is due :)
//! //!
//! Please read [CONTRIBUTING.md](.github/CONTRIBUTING.md) before you start contributing. //! Please read [CONTRIBUTING.md](https://raw.githubusercontent.com/kbknapp/clap-rs/master/.github/CONTRIBUTING.md) before you start contributing.
//! //!
//! //!
//! ### Testing Code //! ### Testing Code
@ -513,7 +513,7 @@
//! this repository for more information. //! this repository for more information.
#![crate_type = "lib"] #![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, #![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
unused_import_braces, unused_allocation)] unused_import_braces, unused_allocation)]
// Lints we'd like to deny but are currently failing for upstream crates // Lints we'd like to deny but are currently failing for upstream crates

View file

@ -853,15 +853,15 @@ macro_rules! write_nspaces {
} }
// convenience macro for remove an item from a vec // convenience macro for remove an item from a vec
macro_rules! vec_remove_all { //macro_rules! vec_remove_all {
($vec:expr, $to_rem:expr) => { // ($vec:expr, $to_rem:expr) => {
debugln!("vec_remove_all! to_rem={:?}", $to_rem); // debugln!("vec_remove_all! to_rem={:?}", $to_rem);
for i in (0 .. $vec.len()).rev() { // for i in (0 .. $vec.len()).rev() {
let should_remove = $to_rem.any(|name| name == &$vec[i]); // let should_remove = $to_rem.any(|name| name == &$vec[i]);
if should_remove { $vec.swap_remove(i); } // if should_remove { $vec.swap_remove(i); }
} // }
}; // };
} //}
macro_rules! find_from { macro_rules! find_from {
($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{ ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
let mut ret = None; let mut ret = None;
@ -892,36 +892,49 @@ macro_rules! find_from {
}}; }};
} }
macro_rules! find_name_from { //macro_rules! find_name_from {
($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{ // ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
let mut ret = None; // let mut ret = None;
for k in $matcher.arg_names() { // for k in $matcher.arg_names() {
if let Some(f) = find_by_name!($_self, k, flags, iter) { // if let Some(f) = find_by_name!($_self, k, flags, iter) {
if let Some(ref v) = f.$from() { // if let Some(ref v) = f.$from() {
if v.contains($arg_name) { // if v.contains($arg_name) {
ret = Some(f.b.name); // ret = Some(f.b.name);
} // }
} // }
} // }
if let Some(o) = find_by_name!($_self, k, opts, iter) { // if let Some(o) = find_by_name!($_self, k, opts, iter) {
if let Some(ref v) = o.$from() { // if let Some(ref v) = o.$from() {
if v.contains(&$arg_name) { // if v.contains(&$arg_name) {
ret = Some(o.b.name); // ret = Some(o.b.name);
} // }
} // }
} // }
if let Some(pos) = find_by_name!($_self, k, positionals, values) { // if let Some(pos) = find_by_name!($_self, k, positionals, values) {
if let Some(ref v) = pos.$from() { // if let Some(ref v) = pos.$from() {
if v.contains($arg_name) { // if v.contains($arg_name) {
ret = Some(pos.b.name); // ret = Some(pos.b.name);
} // }
} // }
} // }
} // }
ret // 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)
)
)
}
}
}
// Finds an arg by name // Finds an arg by name
macro_rules! find_by_name { macro_rules! find_by_name {
($p:expr, $name:expr, $what:ident, $how:ident) => { ($p:expr, $name:expr, $what:ident, $how:ident) => {

View file

@ -108,7 +108,7 @@ _myapp() {
case $line[1] in case $line[1] in
(test) (test)
_arguments -s -S -C \ _arguments -s -S -C \
'--case+[the case to test]' \ '--case=[the case to test]' \
'-h[Prints help information]' \ '-h[Prints help information]' \
'--help[Prints help information]' \ '--help[Prints help information]' \
'-V[Prints version information]' \ '-V[Prints version information]' \
@ -270,7 +270,7 @@ static POWERSHELL: &'static str = r#"
"#; "#;
#[cfg(not(target_os="windows"))] #[cfg(not(target_os="windows"))]
static POWERSHELL_WUS: &'static str = r#" static POWERSHELL_SPECIAL_CMDS: &'static str = r#"
@('my_app', './my_app') | %{ @('my_app', './my_app') | %{
Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock { Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition) param($wordToComplete, $commandAst, $cursorPosition)
@ -330,7 +330,7 @@ static POWERSHELL_WUS: &'static str = r#"
"#; "#;
#[cfg(target_os="windows")] #[cfg(target_os="windows")]
static POWERSHELL_WUS: &'static str = r#" static POWERSHELL_SPECIAL_CMDS: &'static str = r#"
@('my_app', './my_app', 'my_app.exe', '.\my_app', '.\my_app.exe', './my_app.exe') | %{ @('my_app', './my_app', 'my_app.exe', '.\my_app', '.\my_app.exe', './my_app.exe') | %{
Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock { Register-ArgumentCompleter -Native -CommandName $_ -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition) param($wordToComplete, $commandAst, $cursorPosition)
@ -376,7 +376,7 @@ static POWERSHELL_WUS: &'static str = r#"
} }
"#; "#;
static ZSH_WUS: &'static str = r#"#compdef my_app static ZSH_SPECIAL_CMDS: &'static str = r#"#compdef my_app
_my_app() { _my_app() {
typeset -A opt_args typeset -A opt_args
@ -397,7 +397,7 @@ _my_app() {
case $line[1] in case $line[1] in
(test) (test)
_arguments -s -S -C \ _arguments -s -S -C \
'--case+[the case to test]' \ '--case=[the case to test]' \
'-h[Prints help information]' \ '-h[Prints help information]' \
'--help[Prints help information]' \ '--help[Prints help information]' \
'-V[Prints version information]' \ '-V[Prints version information]' \
@ -406,7 +406,15 @@ _arguments -s -S -C \
;; ;;
(some_cmd) (some_cmd)
_arguments -s -S -C \ _arguments -s -S -C \
'--config+[the other case to test]' \ '--config=[the other case to test]' \
'-h[Prints help information]' \
'--help[Prints help information]' \
'-V[Prints version information]' \
'--version[Prints version information]' \
&& ret=0
;;
(some-cmd-with-hypens)
_arguments -s -S -C \
'-h[Prints help information]' \ '-h[Prints help information]' \
'--help[Prints help information]' \ '--help[Prints help information]' \
'-V[Prints version information]' \ '-V[Prints version information]' \
@ -431,6 +439,7 @@ _my_app_commands() {
local commands; commands=( local commands; commands=(
"test:tests things" \ "test:tests things" \
"some_cmd:tests other things" \ "some_cmd:tests other things" \
"some-cmd-with-hypens:" \
"help:Prints this message or the help of the given subcommand(s)" \ "help:Prints this message or the help of the given subcommand(s)" \
"FILE:some input file" \ "FILE:some input file" \
) )
@ -443,6 +452,13 @@ _my_app__help_commands() {
) )
_describe -t commands 'my_app help commands' commands "$@" _describe -t commands 'my_app help commands' commands "$@"
} }
(( $+functions[_my_app__some-cmd-with-hypens_commands] )) ||
_my_app__some-cmd-with-hypens_commands() {
local commands; commands=(
)
_describe -t commands 'my_app some-cmd-with-hypens commands' commands "$@"
}
(( $+functions[_my_app__some_cmd_commands] )) || (( $+functions[_my_app__some_cmd_commands] )) ||
_my_app__some_cmd_commands() { _my_app__some_cmd_commands() {
local commands; commands=( local commands; commands=(
@ -460,7 +476,7 @@ _my_app__test_commands() {
_my_app "$@""#; _my_app "$@""#;
static FISH_WUS: &'static str = r#"function __fish_using_command static FISH_SPECIAL_CMDS: &'static str = r#"function __fish_using_command
set cmd (commandline -opc) set cmd (commandline -opc)
if [ (count $cmd) -eq (count $argv) ] if [ (count $cmd) -eq (count $argv) ]
for i in (seq (count $argv)) for i in (seq (count $argv))
@ -477,6 +493,7 @@ complete -c my_app -n "__fish_using_command my_app" -s h -l help -d 'Prints help
complete -c my_app -n "__fish_using_command my_app" -s V -l version -d 'Prints version information' complete -c my_app -n "__fish_using_command my_app" -s V -l version -d 'Prints version information'
complete -c my_app -n "__fish_using_command my_app" -f -a "test" -d 'tests things' complete -c my_app -n "__fish_using_command my_app" -f -a "test" -d 'tests things'
complete -c my_app -n "__fish_using_command my_app" -f -a "some_cmd" -d 'tests other things' complete -c my_app -n "__fish_using_command my_app" -f -a "some_cmd" -d 'tests other things'
complete -c my_app -n "__fish_using_command my_app" -f -a "some-cmd-with-hypens"
complete -c my_app -n "__fish_using_command my_app" -f -a "help" -d 'Prints this message or the help of the given subcommand(s)' complete -c my_app -n "__fish_using_command my_app" -f -a "help" -d 'Prints this message or the help of the given subcommand(s)'
complete -c my_app -n "__fish_using_command my_app test" -l case -d 'the case to test' complete -c my_app -n "__fish_using_command my_app test" -l case -d 'the case to test'
complete -c my_app -n "__fish_using_command my_app test" -s h -l help -d 'Prints help information' complete -c my_app -n "__fish_using_command my_app test" -s h -l help -d 'Prints help information'
@ -484,11 +501,13 @@ complete -c my_app -n "__fish_using_command my_app test" -s V -l version -d 'Pri
complete -c my_app -n "__fish_using_command my_app some_cmd" -l config -d 'the other case to test' complete -c my_app -n "__fish_using_command my_app some_cmd" -l config -d 'the other case to test'
complete -c my_app -n "__fish_using_command my_app some_cmd" -s h -l help -d 'Prints help information' complete -c my_app -n "__fish_using_command my_app some_cmd" -s h -l help -d 'Prints help information'
complete -c my_app -n "__fish_using_command my_app some_cmd" -s V -l version -d 'Prints version information' complete -c my_app -n "__fish_using_command my_app some_cmd" -s V -l version -d 'Prints version information'
complete -c my_app -n "__fish_using_command my_app some-cmd-with-hypens" -s h -l help -d 'Prints help information'
complete -c my_app -n "__fish_using_command my_app some-cmd-with-hypens" -s V -l version -d 'Prints version information'
complete -c my_app -n "__fish_using_command my_app help" -s h -l help -d 'Prints help information' complete -c my_app -n "__fish_using_command my_app help" -s h -l help -d 'Prints help information'
complete -c my_app -n "__fish_using_command my_app help" -s V -l version -d 'Prints version information' complete -c my_app -n "__fish_using_command my_app help" -s V -l version -d 'Prints version information'
"#; "#;
static BASH_WUS: &'static str = r#"_my_app() { static BASH_SPECIAL_CMDS: &'static str = r#"_my_app() {
local i cur prev opts cmds local i cur prev opts cmds
COMPREPLY=() COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}" cur="${COMP_WORDS[COMP_CWORD]}"
@ -506,6 +525,9 @@ static BASH_WUS: &'static str = r#"_my_app() {
help) help)
cmd+="__help" cmd+="__help"
;; ;;
some-cmd-with-hypens)
cmd+="__some__cmd__with__hypens"
;;
some_cmd) some_cmd)
cmd+="__some_cmd" cmd+="__some_cmd"
;; ;;
@ -519,7 +541,7 @@ static BASH_WUS: &'static str = r#"_my_app() {
case "${cmd}" in case "${cmd}" in
my_app) my_app)
opts=" -h -V --help --version <file> test some_cmd help" opts=" -h -V --help --version <file> test some_cmd some-cmd-with-hypens help"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0 return 0
@ -549,6 +571,21 @@ static BASH_WUS: &'static str = r#"_my_app() {
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0 return 0
;; ;;
my_app__some__cmd__with__hypens)
opts=" -h -V --help --version "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
case "${prev}" in
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
;;
my_app__some_cmd) my_app__some_cmd)
opts=" -h -V --help --version --config " opts=" -h -V --help --version --config "
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
@ -593,7 +630,7 @@ static BASH_WUS: &'static str = r#"_my_app() {
complete -F _my_app -o bashdefault -o default my_app complete -F _my_app -o bashdefault -o default my_app
"#; "#;
static FISH_SPECIAL: &'static str = r#"function __fish_using_command static FISH_SPECIAL_HELP: &'static str = r#"function __fish_using_command
set cmd (commandline -opc) set cmd (commandline -opc)
if [ (count $cmd) -eq (count $argv) ] if [ (count $cmd) -eq (count $argv) ]
for i in (seq (count $argv)) for i in (seq (count $argv))
@ -616,7 +653,7 @@ complete -c my_app -n "__fish_using_command my_app" -s h -l help -d 'Prints help
complete -c my_app -n "__fish_using_command my_app" -s V -l version -d 'Prints version information' complete -c my_app -n "__fish_using_command my_app" -s V -l version -d 'Prints version information'
"#; "#;
static ZSH_SPECIAL: &'static str = r#"#compdef my_app static ZSH_SPECIAL_HELP: &'static str = r#"#compdef my_app
_my_app() { _my_app() {
typeset -A opt_args typeset -A opt_args
@ -685,16 +722,18 @@ fn build_app_with_name(s: &'static str) -> App<'static, 'static> {
.help("the case to test"))) .help("the case to test")))
} }
fn build_app_with_underscore() -> App<'static, 'static> { fn build_app_special_commands() -> App<'static, 'static> {
build_app_with_name("my_app").subcommand(SubCommand::with_name("some_cmd") build_app_with_name("my_app")
.about("tests other things") .subcommand(SubCommand::with_name("some_cmd")
.arg(Arg::with_name("config") .about("tests other things")
.long("--config") .arg(Arg::with_name("config")
.takes_value(true) .long("--config")
.help("the other case to test"))) .takes_value(true)
.help("the other case to test")))
.subcommand(SubCommand::with_name("some-cmd-with-hypens"))
} }
fn build_app_special() -> App<'static, 'static> { fn build_app_special_help() -> App<'static, 'static> {
App::new("my_app") App::new("my_app")
.arg(Arg::with_name("single-quotes") .arg(Arg::with_name("single-quotes")
.long("single-quotes") .long("single-quotes")
@ -759,61 +798,61 @@ fn fish() {
// Disabled until I figure out this windows line ending and AppVeyor issues // Disabled until I figure out this windows line ending and AppVeyor issues
//#[test] //#[test]
// fn powershell_with_underscore() { // fn powershell_with_special_commands() {
// let mut app = build_app_with_underscore(); // let mut app = build_app_special_commands();
// let mut buf = vec![]; // let mut buf = vec![];
// app.gen_completions_to("my_app", Shell::PowerShell, &mut buf); // app.gen_completions_to("my_app", Shell::PowerShell, &mut buf);
// let string = String::from_utf8(buf).unwrap(); // let string = String::from_utf8(buf).unwrap();
// //
// assert!(compare(&*string, POWERSHELL_WUS)); // assert!(compare(&*string, POWERSHELL_SPECIAL_CMDS));
// } // }
#[test] #[test]
fn bash_with_underscore() { fn bash_with_special_commands() {
let mut app = build_app_with_underscore(); let mut app = build_app_special_commands();
let mut buf = vec![]; let mut buf = vec![];
app.gen_completions_to("my_app", Shell::Bash, &mut buf); app.gen_completions_to("my_app", Shell::Bash, &mut buf);
let string = String::from_utf8(buf).unwrap(); let string = String::from_utf8(buf).unwrap();
assert!(compare(&*string, BASH_WUS)); assert!(compare(&*string, BASH_SPECIAL_CMDS));
} }
#[test] #[test]
fn fish_with_underscore() { fn fish_with_special_commands() {
let mut app = build_app_with_underscore(); let mut app = build_app_special_commands();
let mut buf = vec![]; let mut buf = vec![];
app.gen_completions_to("my_app", Shell::Fish, &mut buf); app.gen_completions_to("my_app", Shell::Fish, &mut buf);
let string = String::from_utf8(buf).unwrap(); let string = String::from_utf8(buf).unwrap();
assert!(compare(&*string, FISH_WUS)); assert!(compare(&*string, FISH_SPECIAL_CMDS));
} }
#[test] #[test]
fn zsh_with_underscore() { fn zsh_with_special_commands() {
let mut app = build_app_with_underscore(); let mut app = build_app_special_commands();
let mut buf = vec![]; let mut buf = vec![];
app.gen_completions_to("my_app", Shell::Zsh, &mut buf); app.gen_completions_to("my_app", Shell::Zsh, &mut buf);
let string = String::from_utf8(buf).unwrap(); let string = String::from_utf8(buf).unwrap();
assert!(compare(&*string, ZSH_WUS)); assert!(compare(&*string, ZSH_SPECIAL_CMDS));
} }
#[test] #[test]
fn fish_special() { fn fish_with_special_help() {
let mut app = build_app_special(); let mut app = build_app_special_help();
let mut buf = vec![]; let mut buf = vec![];
app.gen_completions_to("my_app", Shell::Fish, &mut buf); app.gen_completions_to("my_app", Shell::Fish, &mut buf);
let string = String::from_utf8(buf).unwrap(); let string = String::from_utf8(buf).unwrap();
assert!(compare(&*string, FISH_SPECIAL)); assert!(compare(&*string, FISH_SPECIAL_HELP));
} }
#[test] #[test]
fn zsh_special() { fn zsh_with_special_help() {
let mut app = build_app_special(); let mut app = build_app_special_help();
let mut buf = vec![]; let mut buf = vec![];
app.gen_completions_to("my_app", Shell::Zsh, &mut buf); app.gen_completions_to("my_app", Shell::Zsh, &mut buf);
let string = String::from_utf8(buf).unwrap(); let string = String::from_utf8(buf).unwrap();
assert!(compare(&*string, ZSH_SPECIAL)); assert!(compare(&*string, ZSH_SPECIAL_HELP));
} }

View file

@ -4,7 +4,7 @@ extern crate regex;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
include!("../clap-test.rs"); include!("../clap-test.rs");
use clap::{App, Arg, SubCommand, ArgMatches}; use clap::{App, Arg, SubCommand};
fn get_app() -> App<'static, 'static> { fn get_app() -> App<'static, 'static> {
App::new("myprog") App::new("myprog")

View file

@ -55,36 +55,45 @@ fn non_existing_arg() {
#[test] #[test]
fn group_single_value() { fn group_single_value() {
let m = App::new("group") let res = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage("-f, --flag 'some flag'
-c, --color [color] 'some option'") -c, --color [color] 'some option'")
.group(ArgGroup::with_name("grp") .group(ArgGroup::with_name("grp")
.args(&["flag", "color"])) .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!(m.is_present("grp"));
assert_eq!(m.value_of("grp").unwrap(), "blue"); assert_eq!(m.value_of("grp").unwrap(), "blue");
} }
#[test] #[test]
fn group_single_flag() { fn group_single_flag() {
let m = App::new("group") let res = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage("-f, --flag 'some flag'
-c, --color [color] 'some option'") -c, --color [color] 'some option'")
.group(ArgGroup::with_name("grp") .group(ArgGroup::with_name("grp")
.args(&["flag", "color"])) .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.is_present("grp"));
assert!(m.value_of("grp").is_none()); assert!(m.value_of("grp").is_none());
} }
#[test] #[test]
fn group_empty() { fn group_empty() {
let m = App::new("group") let res = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage("-f, --flag 'some flag'
-c, --color [color] 'some option'") -c, --color [color] 'some option'")
.group(ArgGroup::with_name("grp") .group(ArgGroup::with_name("grp")
.args(&["flag", "color"])) .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.is_present("grp"));
assert!(m.value_of("grp").is_none()); assert!(m.value_of("grp").is_none());
} }
@ -105,12 +114,15 @@ fn group_reqired_flags_empty() {
#[test] #[test]
fn group_multi_value_single_arg() { fn group_multi_value_single_arg() {
let m = App::new("group") let res = App::new("group")
.args_from_usage("-f, --flag 'some flag' .args_from_usage("-f, --flag 'some flag'
-c, --color [color]... 'some option'") -c, --color [color]... 'some option'")
.group(ArgGroup::with_name("grp") .group(ArgGroup::with_name("grp")
.args(&["flag", "color"])) .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!(m.is_present("grp"));
assert_eq!(&*m.values_of("grp").unwrap().collect::<Vec<_>>(), &["blue", "red", "green"]); assert_eq!(&*m.values_of("grp").unwrap().collect::<Vec<_>>(), &["blue", "red", "green"]);
} }
@ -148,19 +160,7 @@ fn req_group_with_conflict_usage_string() {
.args(&["base", "delete"]) .args(&["base", "delete"])
.required(true)); .required(true));
assert!(test::compare_output(app, "clap-test --delete base", REQ_GROUP_CONFLICT_REV, true)); assert!(test::compare_output2(app, "clap-test --delete base", REQ_GROUP_CONFLICT_REV, REQ_GROUP_CONFLICT_USAGE, 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));
} }
#[test] #[test]

View file

@ -1106,13 +1106,16 @@ fn multiple_value_terminator_option_other_arg() {
#[test] #[test]
fn multiple_vals_with_hyphen() { fn multiple_vals_with_hyphen() {
let m = App::new("do") let res = App::new("do")
.arg(Arg::with_name("cmds") .arg(Arg::with_name("cmds")
.multiple(true) .multiple(true)
.allow_hyphen_values(true) .allow_hyphen_values(true)
.value_terminator(";")) .value_terminator(";"))
.arg(Arg::with_name("location")) .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(); let cmds: Vec<_> = m.values_of("cmds").unwrap().collect();
assert_eq!(&cmds, &["find", "-type", "f", "-name", "special"]); assert_eq!(&cmds, &["find", "-type", "f", "-name", "special"]);
assert_eq!(m.value_of("location"), Some("/home/clap")); assert_eq!(m.value_of("location"), Some("/home/clap"));

View file

@ -166,14 +166,13 @@ fn pos_required_overridden_by_flag() {
#[test] #[test]
fn require_overriden_2() { fn require_overriden_2() {
let m = App::new("require_overriden") let m = App::new("require_overriden")
.arg(Arg::with_name("flag") .arg(Arg::with_name("req_pos")
.index(1)
.required(true)) .required(true))
.arg(Arg::from_usage("-c, --color 'other flag'") .arg(Arg::from_usage("-c, --color 'other flag'")
.overrides_with("flag")) .overrides_with("req_pos"))
.get_matches_from(vec!["", "-c", "flag"]); .get_matches_from(vec!["", "-c", "req_pos"]);
assert!(!m.is_present("color")); assert!(!m.is_present("color"));
assert!(m.is_present("flag")); assert!(m.is_present("req_pos"));
} }
#[test] #[test]

View file

@ -3,7 +3,7 @@ extern crate regex;
include!("../clap-test.rs"); include!("../clap-test.rs");
#[allow(unsused_imports)] #[allow(unused_imports)]
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use clap::{App, Arg, ErrorKind}; use clap::{App, Arg, ErrorKind};

View file

@ -32,22 +32,22 @@ SUBCOMMANDS:
test Some help"; test Some help";
#[cfg(feature = "suggestions")] #[cfg(feature = "suggestions")]
static DYM: &'static str = "error: The subcommand 'subcm' wasn't recognized static DYM_SUBCMD: &'static str = "error: The subcommand 'subcm' wasn't recognized
\tDid you mean 'subcmd'? 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: USAGE:
clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND] dym [SUBCOMMAND]
For more information try --help"; For more information try --help";
#[cfg(feature = "suggestions")] #[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'? \tDid you mean to put '--subcmdarg' after the subcommand 'subcmd'?
USAGE: USAGE:
clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND] dym [SUBCOMMAND]
For more information try --help"; For more information try --help";
@ -129,8 +129,18 @@ fn multiple_aliases() {
#[test] #[test]
#[cfg(feature="suggestions")] #[cfg(feature="suggestions")]
fn subcmd_did_you_mean_output() { fn subcmd_did_you_mean_output() {
assert!(test::compare_output(test::complex_app(), "clap-test subcm", DYM, true)); let app = App::new("dym")
assert!(test::compare_output(test::complex_app(), "clap-test --subcm foo", DYM2, true)); .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] #[test]