Merge pull request #1119 from kbknapp/case-insensitive

Case insensitive
This commit is contained in:
Kevin K 2017-11-29 00:35:31 +09:00 committed by GitHub
commit bc9ab21934
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 2541 additions and 1722 deletions

View file

@ -1,23 +1,23 @@
<a name="2.28.0"></a>
## 2.28.0 (2017-11-27)
## 2.28.0 (2017-11-28)
The minimum required Rust is now 1.20. This was done to start using bitflags 1.0 and having >1.0 deps is a *very good* thing!
#### Documentation
#### API Additions
* Adds the traits to be used with the `clap-derive` crate to be able to use Custom Derive ([6f4c3412](https://github.com/kbknapp/clap-rs/commit/6f4c3412415e882f5ca2cc3fbd6d4dce79440828))
* changes the demo version to 2.28 to stay in sync ([ce6ca492](https://github.com/kbknapp/clap-rs/commit/ce6ca492c7510ab6474075806360b96081b021a9))
* Fix URL path to github hosted files ([ce72aada](https://github.com/kbknapp/clap-rs/commit/ce72aada56a9581d4a6cb4bf9bdb861c3906f8df), closes [#1106](https://github.com/kbknapp/clap-rs/issues/1106))
* fix typo ([002b07fc](https://github.com/kbknapp/clap-rs/commit/002b07fc98a1c85acb66296b1eec0b2aba906125))
* **README.md:** updates the readme and pulls out some redundant sections ([db6caf86](https://github.com/kbknapp/clap-rs/commit/db6caf8663747e679d2f4ed3bd127f33476754aa))
#### Improvements
* adds '[SUBCOMMAND]' to usage strings with only AppSettings::AllowExternalSubcommands is used with no other subcommands ([e78bb757](https://github.com/kbknapp/clap-rs/commit/e78bb757a3df16e82d539e450c06767a6bfcf859), closes [#1093](https://github.com/kbknapp/clap-rs/issues/1093))
* uses `.bash` for Bash completion scripts now instead of `.bash-completion` due to convention and `.bash-completion` not being supported by completion projects ([4740cde4](https://github.com/kbknapp/clap-rs/commit/4740cde404121a443c64d644eb4a0722c0b0a823)
#### Documentation
#### API Additions
* Fix URL path to github hosted files ([ce72aada](https://github.com/kbknapp/clap-rs/commit/ce72aada56a9581d4a6cb4bf9bdb861c3906f8df), closes [#1106](https://github.com/kbknapp/clap-rs/issues/1106))
* fix typo ([002b07fc](https://github.com/kbknapp/clap-rs/commit/002b07fc98a1c85acb66296b1eec0b2aba906125))
* **README.md:** updates the readme and pulls out some redundant sections ([db6caf86](https://github.com/kbknapp/clap-rs/commit/db6caf8663747e679d2f4ed3bd127f33476754aa))
* Adds Arg::case_insensitive(bool) which allows matching Arg::possible_values without worrying about ASCII case ([1fec268e](https://github.com/kbknapp/clap-rs/commit/1fec268e51736602e38e67c76266f439e2e0ef12), closes [#1118](https://github.com/kbknapp/clap-rs/issues/1118))
* Adds the traits to be used with the clap-derive crate to be able to use Custom Derive ([6f4c3412](https://github.com/kbknapp/clap-rs/commit/6f4c3412415e882f5ca2cc3fbd6d4dce79440828))
#### Bug Fixes
@ -25,7 +25,6 @@ The minimum required Rust is now 1.20. This was done to start using bitflags 1.0
* fixes a bug that allowed options to pass parsing when no value was provided ([2fb75821](https://github.com/kbknapp/clap-rs/commit/2fb758219c7a60d639da67692e100b855a8165ac), closes [#1105](https://github.com/kbknapp/clap-rs/issues/1105))
* ignore PropagateGlobalValuesDown deprecation warning ([f61ce3f5](https://github.com/kbknapp/clap-rs/commit/f61ce3f55fe65e16b3db0bd4facdc4575de22767), closes [#1086](https://github.com/kbknapp/clap-rs/issues/1086))
#### Deps
* Updates `bitflags` to 1.0

View file

@ -9,73 +9,77 @@ the following is a list of contributors:
:---: |:---: |:---: |:---: |:---: |:---: |
[willmurphyscode](https://github.com/willmurphyscode) |[mgeisler](https://github.com/mgeisler) |[nabijaczleweli](https://github.com/nabijaczleweli) |[Byron](https://github.com/Byron) |[hgrecco](https://github.com/hgrecco) |[bluejekyll](https://github.com/bluejekyll) |
[<img alt="james-darkfox" src="https://avatars3.githubusercontent.com/u/637155?v=4&s=117" width="117">](https://github.com/james-darkfox) |[<img alt="H2CO3" src="https://avatars2.githubusercontent.com/u/742370?v=4&s=117" width="117">](https://github.com/H2CO3) |[<img alt="nateozem" src="https://avatars2.githubusercontent.com/u/22719441?v=4&s=117" width="117">](https://github.com/nateozem) |[<img alt="glowing-chemist" src="https://avatars0.githubusercontent.com/u/17074682?v=4&s=117" width="117">](https://github.com/glowing-chemist) |[<img alt="Arnavion" src="https://avatars2.githubusercontent.com/u/1096010?v=4&s=117" width="117">](https://github.com/Arnavion) |[<img alt="rtaycher" src="https://avatars0.githubusercontent.com/u/324733?v=4&s=117" width="117">](https://github.com/rtaycher) |
[<img alt="ignatenkobrain" src="https://avatars1.githubusercontent.com/u/2866862?v=4&s=117" width="117">](https://github.com/ignatenkobrain) |[<img alt="james-darkfox" src="https://avatars3.githubusercontent.com/u/637155?v=4&s=117" width="117">](https://github.com/james-darkfox) |[<img alt="H2CO3" src="https://avatars2.githubusercontent.com/u/742370?v=4&s=117" width="117">](https://github.com/H2CO3) |[<img alt="nateozem" src="https://avatars2.githubusercontent.com/u/22719441?v=4&s=117" width="117">](https://github.com/nateozem) |[<img alt="glowing-chemist" src="https://avatars0.githubusercontent.com/u/17074682?v=4&s=117" width="117">](https://github.com/glowing-chemist) |[<img alt="rtaycher" src="https://avatars0.githubusercontent.com/u/324733?v=4&s=117" width="117">](https://github.com/rtaycher) |
:---: |:---: |:---: |:---: |:---: |:---: |
[james-darkfox](https://github.com/james-darkfox) |[H2CO3](https://github.com/H2CO3) |[nateozem](https://github.com/nateozem) |[glowing-chemist](https://github.com/glowing-chemist) |[Arnavion](https://github.com/Arnavion) |[rtaycher](https://github.com/rtaycher) |
[ignatenkobrain](https://github.com/ignatenkobrain) |[james-darkfox](https://github.com/james-darkfox) |[H2CO3](https://github.com/H2CO3) |[nateozem](https://github.com/nateozem) |[glowing-chemist](https://github.com/glowing-chemist) |[rtaycher](https://github.com/rtaycher) |
[<img alt="japaric" src="https://avatars3.githubusercontent.com/u/5018213?v=4&s=117" width="117">](https://github.com/japaric) |[<img alt="untitaker" src="https://avatars0.githubusercontent.com/u/837573?v=4&s=117" width="117">](https://github.com/untitaker) |[<img alt="afiune" src="https://avatars0.githubusercontent.com/u/5712253?v=4&s=117" width="117">](https://github.com/afiune) |[<img alt="crazymerlyn" src="https://avatars1.githubusercontent.com/u/6919679?v=4&s=117" width="117">](https://github.com/crazymerlyn) |[<img alt="SuperFluffy" src="https://avatars0.githubusercontent.com/u/701177?v=4&s=117" width="117">](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="Arnavion" src="https://avatars2.githubusercontent.com/u/1096010?v=4&s=117" width="117">](https://github.com/Arnavion) |[<img alt="japaric" src="https://avatars3.githubusercontent.com/u/5018213?v=4&s=117" width="117">](https://github.com/japaric) |[<img alt="untitaker" src="https://avatars0.githubusercontent.com/u/837573?v=4&s=117" width="117">](https://github.com/untitaker) |[<img alt="afiune" src="https://avatars0.githubusercontent.com/u/5712253?v=4&s=117" width="117">](https://github.com/afiune) |[<img alt="crazymerlyn" src="https://avatars1.githubusercontent.com/u/6919679?v=4&s=117" width="117">](https://github.com/crazymerlyn) |[<img alt="SuperFluffy" src="https://avatars0.githubusercontent.com/u/701177?v=4&s=117" width="117">](https://github.com/SuperFluffy) |
:---: |:---: |:---: |:---: |:---: |:---: |
[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) |[malbarbo](https://github.com/malbarbo) |
[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="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="Nemo157" src="https://avatars1.githubusercontent.com/u/81079?v=4&s=117" width="117">](https://github.com/Nemo157) |
[<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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[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) |[Nemo157](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) |
[<img alt="SShrike" src="https://avatars1.githubusercontent.com/u/4061736?v=4&s=117" width="117">](https://github.com/SShrike) |[<img alt="porglezomp" src="https://avatars1.githubusercontent.com/u/1690225?v=4&s=117" width="117">](https://github.com/porglezomp) |[<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) |[<img alt="huonw" src="https://avatars1.githubusercontent.com/u/1203825?v=4&s=117" width="117">](https://github.com/huonw) |
[<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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[SShrike](https://github.com/SShrike) |[porglezomp](https://github.com/porglezomp) |[wdv4758h](https://github.com/wdv4758h) |[frewsxcv](https://github.com/frewsxcv) |[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |
[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) |
[<img alt="GrappigPanda" src="https://avatars0.githubusercontent.com/u/2055372?v=4&s=117" width="117">](https://github.com/GrappigPanda) |[<img alt="ignatenkobrain" src="https://avatars1.githubusercontent.com/u/2866862?v=4&s=117" width="117">](https://github.com/ignatenkobrain) |[<img alt="shepmaster" src="https://avatars0.githubusercontent.com/u/174509?v=4&s=117" width="117">](https://github.com/shepmaster) |[<img alt="cstorey" src="https://avatars3.githubusercontent.com/u/743059?v=4&s=117" width="117">](https://github.com/cstorey) |[<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) |
[<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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[GrappigPanda](https://github.com/GrappigPanda) |[ignatenkobrain](https://github.com/ignatenkobrain) |[shepmaster](https://github.com/shepmaster) |[cstorey](https://github.com/cstorey) |[kieraneglin](https://github.com/kieraneglin) |[musoke](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) |
[<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) |
[<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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[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) |
[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) |
[<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) |
[<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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[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) |
[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) |
[<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="Bilalh" src="https://avatars0.githubusercontent.com/u/171602?v=4&s=117" width="117">](https://github.com/Bilalh) |
[<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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[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) |[Bilalh](https://github.com/Bilalh) |
[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) |
[<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="volks73" src="https://avatars1.githubusercontent.com/u/1915469?v=4&s=117" width="117">](https://github.com/volks73) |
[<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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[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) |[volks73](https://github.com/volks73) |
[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) |
[<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="eddyb" src="https://avatars2.githubusercontent.com/u/77424?v=4&s=117" width="117">](https://github.com/eddyb) |
[<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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[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) |[eddyb](https://github.com/eddyb) |
[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="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="idmit" src="https://avatars1.githubusercontent.com/u/2546728?v=4&s=117" width="117">](https://github.com/idmit) |
[<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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[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) |[idmit](https://github.com/idmit) |
[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) |
[<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="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="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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[archer884](https://github.com/archer884) |[jacobmischka](https://github.com/jacobmischka) |[jespino](https://github.com/jespino) |[jtdowney](https://github.com/jtdowney) |[andete](https://github.com/andete) |[joshtriplett](https://github.com/joshtriplett) |
[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) |
[<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="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="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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[Kalwyn](https://github.com/Kalwyn) |[manuel-rhdt](https://github.com/manuel-rhdt) |[Marwes](https://github.com/Marwes) |[mdaffin](https://github.com/mdaffin) |[iliekturtles](https://github.com/iliekturtles) |[nicompte](https://github.com/nicompte) |
[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) |
[<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="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="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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[nuew](https://github.com/nuew) |[Geogi](https://github.com/Geogi) |[flying-sheep](https://github.com/flying-sheep) |[Phlosioneer](https://github.com/Phlosioneer) |
[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) |
[<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="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="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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[peppsac](https://github.com/peppsac) |[golddranks](https://github.com/golddranks) |[hexjelly](https://github.com/hexjelly) |[rnelson](https://github.com/rnelson) |[swatteau](https://github.com/swatteau) |[tspiteri](https://github.com/tspiteri) |
[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) |
[<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) |
[<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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[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) |
[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) |
[<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="mitsuhiko" src="https://avatars1.githubusercontent.com/u/7396?v=4&s=117" width="117">](https://github.com/mitsuhiko) |
:---: |:---: |:---: |:---: |
[kennytm](https://github.com/kennytm) |[mvaude](https://github.com/mvaude) |[panicbit](https://github.com/panicbit) |[mitsuhiko](https://github.com/mitsuhiko) |
[<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) |
:---: |:---: |:---: |:---: |:---: |:---: |
[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) |
[<img alt="mitsuhiko" src="https://avatars1.githubusercontent.com/u/7396?v=4&s=117" width="117">](https://github.com/mitsuhiko) |
:---: |
[mitsuhiko](https://github.com/mitsuhiko) |

View file

@ -48,6 +48,7 @@ The minimum required Rust is now 1.20. This was done to start using bitflags 1.0
* Updates `bitflags` to 1.0
* Adds the traits to be used with the `clap-derive` crate to be able to use Custom Derive (for now must be accessed with `unstable` feature flag)
* Adds Arg::case_insensitive(bool) which allows matching Arg::possible_values without worrying about ASCII case
* Fixes a regression where --help couldn't be overridden
* adds '[SUBCOMMAND]' to usage strings with only AppSettings::AllowExternalSubcommands is used with no other subcommands
* uses `.bash` for Bash completion scripts now instead of `.bash-completion` due to convention and `.bash-completion` not being supported by completion projects

View file

@ -85,7 +85,7 @@ macro_rules! arg_post_processing {
.filter(|&&(val, _)| val.is_none())
.filter(|&&(_, req)| !$matcher.contains(&req))
.map(|&(_, name)| name) {
$me.required.push(n);
}
} else { sdebugln!("No"); }

View file

@ -23,5 +23,11 @@ pub struct AppMeta<'b> {
impl<'b> AppMeta<'b> {
pub fn new() -> Self { Default::default() }
pub fn with_name(s: String) -> Self { AppMeta { name: s, disp_ord: 999, ..Default::default() } }
}
pub fn with_name(s: String) -> Self {
AppMeta {
name: s,
disp_ord: 999,
..Default::default()
}
}
}

View file

@ -60,10 +60,10 @@ use map::{self, VecMap};
/// [`App::get_matches`]: ./struct.App.html#method.get_matches
#[allow(missing_debug_implementations)]
pub struct App<'a, 'b>
where 'a: 'b
where
'a: 'b,
{
#[doc(hidden)]
pub p: Parser<'a, 'b>,
#[doc(hidden)] pub p: Parser<'a, 'b>,
}
@ -79,7 +79,11 @@ impl<'a, 'b> App<'a, 'b> {
/// let prog = App::new("My Program")
/// # ;
/// ```
pub fn new<S: Into<String>>(n: S) -> Self { App { p: Parser::with_name(n.into()) } }
pub fn new<S: Into<String>>(n: S) -> Self {
App {
p: Parser::with_name(n.into()),
}
}
/// Get the name of the app
pub fn get_name(&self) -> &str { &self.p.meta.name }
@ -103,7 +107,9 @@ impl<'a, 'b> App<'a, 'b> {
/// [`App::version`]: ./struct.App.html#method.author
#[deprecated(since="2.14.1", note="Can never work; use explicit App::author() and App::version() calls instead")]
pub fn with_defaults<S: Into<String>>(n: S) -> Self {
let mut a = App { p: Parser::with_name(n.into()) };
let mut a = App {
p: Parser::with_name(n.into()),
};
a.p.meta.author = Some("Kevin K. <kbknapp@gmail.com>");
a.p.meta.version = Some("2.19.2");
a
@ -1073,7 +1079,8 @@ impl<'a, 'b> App<'a, 'b> {
/// [`SubCommand`]: ./struct.SubCommand.html
/// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
pub fn subcommands<I>(mut self, subcmds: I) -> Self
where I: IntoIterator<Item = App<'a, 'b>>
where
I: IntoIterator<Item = App<'a, 'b>>,
{
for subcmd in subcmds {
self.p.add_subcommand(subcmd);
@ -1380,10 +1387,12 @@ impl<'a, 'b> App<'a, 'b> {
/// `<project>/target/debug/build/myapp-<hash>/out/myapp.bash`.
///
/// Fish shell completions will use the file format `{bin_name}.fish`
pub fn gen_completions<T: Into<OsString>, S: Into<String>>(&mut self,
bin_name: S,
for_shell: Shell,
out_dir: T) {
pub fn gen_completions<T: Into<OsString>, S: Into<String>>(
&mut self,
bin_name: S,
for_shell: Shell,
out_dir: T,
) {
self.p.meta.bin_name = Some(bin_name.into());
self.p.gen_completions(for_shell, out_dir.into());
}
@ -1421,10 +1430,12 @@ impl<'a, 'b> App<'a, 'b> {
/// ```shell
/// $ myapp generate-bash-completions > /usr/share/bash-completion/completions/myapp.bash
/// ```
pub fn gen_completions_to<W: Write, S: Into<String>>(&mut self,
bin_name: S,
for_shell: Shell,
buf: &mut W) {
pub fn gen_completions_to<W: Write, S: Into<String>>(
&mut self,
bin_name: S,
for_shell: Shell,
buf: &mut W,
) {
self.p.meta.bin_name = Some(bin_name.into());
self.p.gen_completions_to(for_shell, buf);
}
@ -1497,8 +1508,9 @@ impl<'a, 'b> App<'a, 'b> {
/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
/// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
pub fn get_matches_from<I, T>(mut self, itr: I) -> ArgMatches<'a>
where I: IntoIterator<Item = T>,
T: Into<OsString> + Clone
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
self.get_matches_from_safe_borrow(itr).unwrap_or_else(|e| {
// Otherwise, write to stderr and exit
@ -1553,8 +1565,9 @@ impl<'a, 'b> App<'a, 'b> {
/// [`kind`]: ./struct.Error.html
/// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
pub fn get_matches_from_safe<I, T>(mut self, itr: I) -> ClapResult<ArgMatches<'a>>
where I: IntoIterator<Item = T>,
T: Into<OsString> + Clone
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
self.get_matches_from_safe_borrow(itr)
}
@ -1581,8 +1594,9 @@ impl<'a, 'b> App<'a, 'b> {
/// [`App::get_matches_from_safe`]: ./struct.App.html#method.get_matches_from_safe
/// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName
pub fn get_matches_from_safe_borrow<I, T>(&mut self, itr: I) -> ClapResult<ArgMatches<'a>>
where I: IntoIterator<Item = T>,
T: Into<OsString> + Clone
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
// If there are global arguments, or settings we need to propgate them down to subcommands
// before parsing incase we run into a subcommand
@ -1622,7 +1636,7 @@ impl<'a, 'b> App<'a, 'b> {
return Err(e);
}
let global_arg_vec : Vec<&str> = (&self).p.global_args.iter().map(|ga| ga.b.name).collect();
let global_arg_vec: Vec<&str> = (&self).p.global_args.iter().map(|ga| ga.b.name).collect();
matcher.propagate_globals(&global_arg_vec);
Ok(matcher.into())
@ -1674,14 +1688,18 @@ impl<'a> From<&'a Yaml> for App<'a, 'a> {
if let Some(v) = yaml["display_order"].as_i64() {
a = a.display_order(v as usize);
} else if yaml["display_order"] != Yaml::BadValue {
panic!("Failed to convert YAML value {:?} to a u64",
yaml["display_order"]);
panic!(
"Failed to convert YAML value {:?} to a u64",
yaml["display_order"]
);
}
if let Some(v) = yaml["setting"].as_str() {
a = a.setting(v.parse().expect("unknown AppSetting found in YAML file"));
} else if yaml["setting"] != Yaml::BadValue {
panic!("Failed to convert YAML value {:?} to an AppSetting",
yaml["setting"]);
panic!(
"Failed to convert YAML value {:?} to an AppSetting",
yaml["setting"]
);
}
if let Some(v) = yaml["settings"].as_vec() {
for ys in v {
@ -1692,27 +1710,32 @@ impl<'a> From<&'a Yaml> for App<'a, 'a> {
} else if let Some(v) = yaml["settings"].as_str() {
a = a.setting(v.parse().expect("unknown AppSetting found in YAML file"));
} else if yaml["settings"] != Yaml::BadValue {
panic!("Failed to convert YAML value {:?} to a string",
yaml["settings"]);
panic!(
"Failed to convert YAML value {:?} to a string",
yaml["settings"]
);
}
if let Some(v) = yaml["global_setting"].as_str() {
a = a.setting(v.parse().expect("unknown AppSetting found in YAML file"));
} else if yaml["global_setting"] != Yaml::BadValue {
panic!("Failed to convert YAML value {:?} to an AppSetting",
yaml["setting"]);
panic!(
"Failed to convert YAML value {:?} to an AppSetting",
yaml["setting"]
);
}
if let Some(v) = yaml["global_settings"].as_vec() {
for ys in v {
if let Some(s) = ys.as_str() {
a = a.global_setting(s.parse()
.expect("unknown AppSetting found in YAML file"));
a = a.global_setting(s.parse().expect("unknown AppSetting found in YAML file"));
}
}
} else if let Some(v) = yaml["global_settings"].as_str() {
a = a.global_setting(v.parse().expect("unknown AppSetting found in YAML file"));
} else if yaml["global_settings"] != Yaml::BadValue {
panic!("Failed to convert YAML value {:?} to a string",
yaml["global_settings"]);
panic!(
"Failed to convert YAML value {:?} to a string",
yaml["global_settings"]
);
}
macro_rules! vec_or_str {
@ -1800,8 +1823,10 @@ impl<'n, 'e> AnyArg<'n, 'e> for App<'n, 'e> {
fn longest_filter(&self) -> bool { true }
fn aliases(&self) -> Option<Vec<&'e str>> {
if let Some(ref aliases) = self.p.meta.aliases {
let vis_aliases: Vec<_> =
aliases.iter().filter_map(|&(n, v)| if v { Some(n) } else { None }).collect();
let vis_aliases: Vec<_> = aliases
.iter()
.filter_map(|&(n, v)| if v { Some(n) } else { None })
.collect();
if vis_aliases.is_empty() {
None
} else {

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
// Std
#[allow(unused_imports)]
#[allow(unused_imports)]
use std::ascii::AsciiExt;
use std::str::FromStr;
use std::ops::BitOr;
@ -60,7 +60,10 @@ impl BitOr for AppFlags {
impl Default for AppFlags {
fn default() -> Self {
AppFlags(Flags::NEEDS_LONG_VERSION | Flags::NEEDS_LONG_HELP | Flags::NEEDS_SC_HELP | Flags::UTF8_NONE | Flags::COLOR_AUTO)
AppFlags(
Flags::NEEDS_LONG_VERSION | Flags::NEEDS_LONG_HELP | Flags::NEEDS_SC_HELP
| Flags::UTF8_NONE | Flags::COLOR_AUTO,
)
}
}
@ -138,8 +141,8 @@ pub enum AppSettings {
///
/// # Examples
///
#[cfg_attr(not(unix), doc=" ```ignore")]
#[cfg_attr( unix , doc=" ```")]
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, AppSettings};
/// use std::ffi::OsString;
/// use std::os::unix::ffi::{OsStrExt,OsStringExt};
@ -592,9 +595,9 @@ pub enum AppSettings {
NextLineHelp,
/// **DEPRECATED**: This setting is no longer required in order to propagate values up or down
///
///
/// Specifies that the parser should propagate global arg's values down or up through any *used*
/// child subcommands. Meaning, if a subcommand wasn't used, the values won't be propagated to
/// child subcommands. Meaning, if a subcommand wasn't used, the values won't be propagated to
/// said subcommand.
///
/// # Examples
@ -710,8 +713,8 @@ pub enum AppSettings {
///
/// # Examples
///
#[cfg_attr(not(unix), doc=" ```ignore")]
#[cfg_attr( unix , doc=" ```")]
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, AppSettings, ErrorKind};
/// use std::ffi::OsString;
/// use std::os::unix::ffi::OsStringExt;
@ -839,32 +842,23 @@ pub enum AppSettings {
/// [`SubCommand`]: ./struct.SubCommand.html
WaitOnError,
#[doc(hidden)]
NeedsLongVersion,
#[doc(hidden)] NeedsLongVersion,
#[doc(hidden)]
NeedsLongHelp,
#[doc(hidden)] NeedsLongHelp,
#[doc(hidden)]
NeedsSubcommandHelp,
#[doc(hidden)] NeedsSubcommandHelp,
#[doc(hidden)]
LowIndexMultiplePositional,
#[doc(hidden)] LowIndexMultiplePositional,
#[doc(hidden)]
TrailingValues,
#[doc(hidden)] TrailingValues,
#[doc(hidden)]
ValidNegNumFound,
#[doc(hidden)] ValidNegNumFound,
#[doc(hidden)]
Propagated,
#[doc(hidden)] Propagated,
#[doc(hidden)]
ValidArgFound,
#[doc(hidden)] ValidArgFound,
#[doc(hidden)]
ContainsLast,
#[doc(hidden)] ContainsLast,
}
impl FromStr for AppSettings {
@ -916,74 +910,142 @@ mod test {
#[test]
fn app_settings_fromstr() {
assert_eq!("argsnegatesubcommands".parse::<AppSettings>().unwrap(),
AppSettings::ArgsNegateSubcommands);
assert_eq!("argrequiredelsehelp".parse::<AppSettings>().unwrap(),
AppSettings::ArgRequiredElseHelp);
assert_eq!("allowexternalsubcommands".parse::<AppSettings>().unwrap(),
AppSettings::AllowExternalSubcommands);
assert_eq!("allowinvalidutf8".parse::<AppSettings>().unwrap(),
AppSettings::AllowInvalidUtf8);
assert_eq!("allowleadinghyphen".parse::<AppSettings>().unwrap(),
AppSettings::AllowLeadingHyphen);
assert_eq!("allownegativenumbers".parse::<AppSettings>().unwrap(),
AppSettings::AllowNegativeNumbers);
assert_eq!("coloredhelp".parse::<AppSettings>().unwrap(),
AppSettings::ColoredHelp);
assert_eq!("colorauto".parse::<AppSettings>().unwrap(),
AppSettings::ColorAuto);
assert_eq!("coloralways".parse::<AppSettings>().unwrap(),
AppSettings::ColorAlways);
assert_eq!("colornever".parse::<AppSettings>().unwrap(),
AppSettings::ColorNever);
assert_eq!("disablehelpsubcommand".parse::<AppSettings>().unwrap(),
AppSettings::DisableHelpSubcommand);
assert_eq!("disableversion".parse::<AppSettings>().unwrap(),
AppSettings::DisableVersion);
assert_eq!("dontcollapseargsinusage".parse::<AppSettings>().unwrap(),
AppSettings::DontCollapseArgsInUsage);
assert_eq!("dontdelimittrailingvalues".parse::<AppSettings>().unwrap(),
AppSettings::DontDelimitTrailingValues);
assert_eq!("derivedisplayorder".parse::<AppSettings>().unwrap(),
AppSettings::DeriveDisplayOrder);
assert_eq!("globalversion".parse::<AppSettings>().unwrap(),
AppSettings::GlobalVersion);
assert_eq!("hidden".parse::<AppSettings>().unwrap(),
AppSettings::Hidden);
assert_eq!("hidepossiblevaluesinhelp".parse::<AppSettings>().unwrap(),
AppSettings::HidePossibleValuesInHelp);
assert_eq!("lowindexmultiplePositional".parse::<AppSettings>().unwrap(),
AppSettings::LowIndexMultiplePositional);
assert_eq!("nobinaryname".parse::<AppSettings>().unwrap(),
AppSettings::NoBinaryName);
assert_eq!("nextlinehelp".parse::<AppSettings>().unwrap(),
AppSettings::NextLineHelp);
assert_eq!("subcommandsnegatereqs".parse::<AppSettings>().unwrap(),
AppSettings::SubcommandsNegateReqs);
assert_eq!("subcommandrequired".parse::<AppSettings>().unwrap(),
AppSettings::SubcommandRequired);
assert_eq!("subcommandrequiredelsehelp".parse::<AppSettings>().unwrap(),
AppSettings::SubcommandRequiredElseHelp);
assert_eq!("strictutf8".parse::<AppSettings>().unwrap(),
AppSettings::StrictUtf8);
assert_eq!("trailingvararg".parse::<AppSettings>().unwrap(),
AppSettings::TrailingVarArg);
assert_eq!("unifiedhelpmessage".parse::<AppSettings>().unwrap(),
AppSettings::UnifiedHelpMessage);
assert_eq!("versionlesssubcommands".parse::<AppSettings>().unwrap(),
AppSettings::VersionlessSubcommands);
assert_eq!("waitonerror".parse::<AppSettings>().unwrap(),
AppSettings::WaitOnError);
assert_eq!("validnegnumfound".parse::<AppSettings>().unwrap(),
AppSettings::ValidNegNumFound);
assert_eq!("validargfound".parse::<AppSettings>().unwrap(),
AppSettings::ValidArgFound);
assert_eq!("propagated".parse::<AppSettings>().unwrap(),
AppSettings::Propagated);
assert_eq!("trailingvalues".parse::<AppSettings>().unwrap(),
AppSettings::TrailingValues);
assert_eq!("infersubcommands".parse::<AppSettings>().unwrap(),
AppSettings::InferSubcommands);
assert_eq!(
"argsnegatesubcommands".parse::<AppSettings>().unwrap(),
AppSettings::ArgsNegateSubcommands
);
assert_eq!(
"argrequiredelsehelp".parse::<AppSettings>().unwrap(),
AppSettings::ArgRequiredElseHelp
);
assert_eq!(
"allowexternalsubcommands".parse::<AppSettings>().unwrap(),
AppSettings::AllowExternalSubcommands
);
assert_eq!(
"allowinvalidutf8".parse::<AppSettings>().unwrap(),
AppSettings::AllowInvalidUtf8
);
assert_eq!(
"allowleadinghyphen".parse::<AppSettings>().unwrap(),
AppSettings::AllowLeadingHyphen
);
assert_eq!(
"allownegativenumbers".parse::<AppSettings>().unwrap(),
AppSettings::AllowNegativeNumbers
);
assert_eq!(
"coloredhelp".parse::<AppSettings>().unwrap(),
AppSettings::ColoredHelp
);
assert_eq!(
"colorauto".parse::<AppSettings>().unwrap(),
AppSettings::ColorAuto
);
assert_eq!(
"coloralways".parse::<AppSettings>().unwrap(),
AppSettings::ColorAlways
);
assert_eq!(
"colornever".parse::<AppSettings>().unwrap(),
AppSettings::ColorNever
);
assert_eq!(
"disablehelpsubcommand".parse::<AppSettings>().unwrap(),
AppSettings::DisableHelpSubcommand
);
assert_eq!(
"disableversion".parse::<AppSettings>().unwrap(),
AppSettings::DisableVersion
);
assert_eq!(
"dontcollapseargsinusage".parse::<AppSettings>().unwrap(),
AppSettings::DontCollapseArgsInUsage
);
assert_eq!(
"dontdelimittrailingvalues".parse::<AppSettings>().unwrap(),
AppSettings::DontDelimitTrailingValues
);
assert_eq!(
"derivedisplayorder".parse::<AppSettings>().unwrap(),
AppSettings::DeriveDisplayOrder
);
assert_eq!(
"globalversion".parse::<AppSettings>().unwrap(),
AppSettings::GlobalVersion
);
assert_eq!(
"hidden".parse::<AppSettings>().unwrap(),
AppSettings::Hidden
);
assert_eq!(
"hidepossiblevaluesinhelp".parse::<AppSettings>().unwrap(),
AppSettings::HidePossibleValuesInHelp
);
assert_eq!(
"lowindexmultiplePositional".parse::<AppSettings>().unwrap(),
AppSettings::LowIndexMultiplePositional
);
assert_eq!(
"nobinaryname".parse::<AppSettings>().unwrap(),
AppSettings::NoBinaryName
);
assert_eq!(
"nextlinehelp".parse::<AppSettings>().unwrap(),
AppSettings::NextLineHelp
);
assert_eq!(
"subcommandsnegatereqs".parse::<AppSettings>().unwrap(),
AppSettings::SubcommandsNegateReqs
);
assert_eq!(
"subcommandrequired".parse::<AppSettings>().unwrap(),
AppSettings::SubcommandRequired
);
assert_eq!(
"subcommandrequiredelsehelp".parse::<AppSettings>().unwrap(),
AppSettings::SubcommandRequiredElseHelp
);
assert_eq!(
"strictutf8".parse::<AppSettings>().unwrap(),
AppSettings::StrictUtf8
);
assert_eq!(
"trailingvararg".parse::<AppSettings>().unwrap(),
AppSettings::TrailingVarArg
);
assert_eq!(
"unifiedhelpmessage".parse::<AppSettings>().unwrap(),
AppSettings::UnifiedHelpMessage
);
assert_eq!(
"versionlesssubcommands".parse::<AppSettings>().unwrap(),
AppSettings::VersionlessSubcommands
);
assert_eq!(
"waitonerror".parse::<AppSettings>().unwrap(),
AppSettings::WaitOnError
);
assert_eq!(
"validnegnumfound".parse::<AppSettings>().unwrap(),
AppSettings::ValidNegNumFound
);
assert_eq!(
"validargfound".parse::<AppSettings>().unwrap(),
AppSettings::ValidArgFound
);
assert_eq!(
"propagated".parse::<AppSettings>().unwrap(),
AppSettings::Propagated
);
assert_eq!(
"trailingvalues".parse::<AppSettings>().unwrap(),
AppSettings::TrailingValues
);
assert_eq!(
"infersubcommands".parse::<AppSettings>().unwrap(),
AppSettings::InferSubcommands
);
assert!("hahahaha".parse::<AppSettings>().is_err());
}
}

View file

@ -19,11 +19,13 @@ pub fn create_usage_with_title(p: &Parser, used: &[&str]) -> String {
}
// Creates a usage string to be used in error message (i.e. one with currently used args)
pub fn create_error_usage<'a, 'b>(p: &Parser<'a, 'b>,
matcher: &'b ArgMatcher<'a>,
extra: Option<&str>)
-> String {
let mut args: Vec<_> = matcher.arg_names()
pub fn create_error_usage<'a, 'b>(
p: &Parser<'a, 'b>,
matcher: &'b ArgMatcher<'a>,
extra: Option<&str>,
) -> String {
let mut args: Vec<_> = matcher
.arg_names()
.iter()
.filter(|n| {
if let Some(o) = find_by_name!(p, **n, opts, iter) {
@ -60,20 +62,15 @@ pub fn create_help_usage(p: &Parser, incl_reqs: bool) -> String {
let name = p.meta
.usage
.as_ref()
.unwrap_or_else(|| {
p.meta
.bin_name
.as_ref()
.unwrap_or(&p.meta.name)
});
.unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name));
usage.push_str(&*name);
let req_string = if incl_reqs {
let mut reqs: Vec<&str> = p.required().map(|r| &**r).collect();
reqs.sort();
reqs.dedup();
get_required_usage_from(p, &reqs, None, None, false).iter().fold(String::new(), |a, s| {
a + &format!(" {}", s)[..]
})
get_required_usage_from(p, &reqs, None, None, false)
.iter()
.fold(String::new(), |a, s| a + &format!(" {}", s)[..])
} else {
String::new()
};
@ -84,8 +81,9 @@ pub fn create_help_usage(p: &Parser, incl_reqs: bool) -> String {
} else if flags {
usage.push_str(" [OPTIONS]");
}
if !p.is_set(AS::UnifiedHelpMessage) &&
p.opts.iter().any(|o| !o.is_set(ArgSettings::Required) && !o.is_set(ArgSettings::Hidden)) {
if !p.is_set(AS::UnifiedHelpMessage) && p.opts.iter().any(|o| {
!o.is_set(ArgSettings::Required) && !o.is_set(ArgSettings::Hidden)
}) {
usage.push_str(" [OPTIONS]");
}
@ -94,13 +92,19 @@ pub fn create_help_usage(p: &Parser, incl_reqs: bool) -> String {
let has_last = p.positionals.values().any(|p| p.is_set(ArgSettings::Last));
// places a '--' in the usage string if there are args and options
// supporting multiple values
if p.opts.iter().any(|o| o.is_set(ArgSettings::Multiple)) &&
p.positionals.values().any(|p| !p.is_set(ArgSettings::Required)) &&
!(p.has_visible_subcommands() || p.is_set(AS::AllowExternalSubcommands)) && !has_last {
if p.opts.iter().any(|o| o.is_set(ArgSettings::Multiple))
&& p.positionals
.values()
.any(|p| !p.is_set(ArgSettings::Required))
&& !(p.has_visible_subcommands() || p.is_set(AS::AllowExternalSubcommands))
&& !has_last
{
usage.push_str(" [--]");
}
let not_req_or_hidden =
|p: &PosBuilder| (!p.is_set(ArgSettings::Required) || p.is_set(ArgSettings::Last)) && !p.is_set(ArgSettings::Hidden);
let not_req_or_hidden = |p: &PosBuilder| {
(!p.is_set(ArgSettings::Required) || p.is_set(ArgSettings::Last))
&& !p.is_set(ArgSettings::Hidden)
};
if p.has_positionals() && p.positionals.values().any(not_req_or_hidden) {
if let Some(args_tag) = get_args_tag(p, incl_reqs) {
usage.push_str(&*args_tag);
@ -114,7 +118,11 @@ pub fn create_help_usage(p: &Parser, incl_reqs: bool) -> String {
.expect(INTERNAL_ERROR_MSG);
debugln!("usage::create_help_usage: '{}' has .last(true)", pos.name());
let req = pos.is_set(ArgSettings::Required);
if req && p.positionals.values().any(|p| !p.is_set(ArgSettings::Required)) {
if req
&& p.positionals
.values()
.any(|p| !p.is_set(ArgSettings::Required))
{
usage.push_str(" -- <");
} else if req {
usage.push_str(" [--] <");
@ -161,21 +169,16 @@ fn create_smart_usage(p: &Parser, used: &[&str]) -> String {
let mut hs: Vec<&str> = p.required().map(|s| &**s).collect();
hs.extend_from_slice(used);
let r_string =
get_required_usage_from(p, &hs, None, None, false).iter().fold(String::new(), |acc, s| {
acc + &format!(" {}", s)[..]
});
let r_string = get_required_usage_from(p, &hs, None, None, false)
.iter()
.fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
usage.push_str(&p.meta
.usage
.as_ref()
.unwrap_or_else(|| {
p.meta
.bin_name
.as_ref()
.unwrap_or(&p.meta.name)
})
[..]);
usage.push_str(
&p.meta
.usage
.as_ref()
.unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name))[..],
);
usage.push_str(&*r_string);
if p.is_set(AS::SubcommandRequired) {
usage.push_str(" <SUBCOMMAND>");
@ -189,10 +192,11 @@ fn get_args_tag(p: &Parser, incl_reqs: bool) -> Option<String> {
debugln!("usage::get_args_tag;");
let mut count = 0;
'outer: for pos in p.positionals
.values()
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last)) {
.values()
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
{
debugln!("usage::get_args_tag:iter:{}:", pos.b.name);
if let Some(g_vec) = p.groups_for_arg(pos.b.name) {
for grp_s in &g_vec {
@ -204,8 +208,10 @@ fn get_args_tag(p: &Parser, incl_reqs: bool) -> Option<String> {
}
}
count += 1;
debugln!("usage::get_args_tag:iter: {} Args not required or hidden",
count);
debugln!(
"usage::get_args_tag:iter: {} Args not required or hidden",
count
);
}
if !p.is_set(AS::DontCollapseArgsInUsage) && count > 1 {
debugln!("usage::get_args_tag:iter: More than one, returning [ARGS]");
@ -214,52 +220,65 @@ fn get_args_tag(p: &Parser, incl_reqs: bool) -> Option<String> {
let pos = p.positionals
.values()
.find(|pos| {
!pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Hidden) &&
!pos.is_set(ArgSettings::Last)
})
!pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Hidden)
&& !pos.is_set(ArgSettings::Last)
})
.expect(INTERNAL_ERROR_MSG);
debugln!("usage::get_args_tag:iter: Exactly one, returning '{}'",
pos.name());
return Some(format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str()));
debugln!(
"usage::get_args_tag:iter: Exactly one, returning '{}'",
pos.name()
);
return Some(format!(
" [{}]{}",
pos.name_no_brackets(),
pos.multiple_str()
));
} else if p.is_set(AS::DontCollapseArgsInUsage) && !p.positionals.is_empty() && incl_reqs {
debugln!("usage::get_args_tag:iter: Don't collapse returning all");
return Some(p.positionals
.values()
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.map(|pos| {
format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())
})
.collect::<Vec<_>>()
.join(""));
return Some(
p.positionals
.values()
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.map(|pos| {
format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())
})
.collect::<Vec<_>>()
.join(""),
);
} else if !incl_reqs {
debugln!("usage::get_args_tag:iter: incl_reqs=false, building secondary usage string");
let highest_req_pos = p.positionals
.iter()
.filter_map(|(idx, pos)| if pos.b.is_set(ArgSettings::Required) &&
!pos.b.is_set(ArgSettings::Last) {
Some(idx)
} else {
None
})
.filter_map(|(idx, pos)| {
if pos.b.is_set(ArgSettings::Required) && !pos.b.is_set(ArgSettings::Last) {
Some(idx)
} else {
None
}
})
.max()
.unwrap_or_else(|| p.positionals.len());
return Some(p.positionals
.iter()
.filter_map(|(idx, pos)| if idx <= highest_req_pos {
Some(pos)
} else {
None
})
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.map(|pos| {
format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())
})
.collect::<Vec<_>>()
.join(""));
return Some(
p.positionals
.iter()
.filter_map(|(idx, pos)| {
if idx <= highest_req_pos {
Some(pos)
} else {
None
}
})
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.map(|pos| {
format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())
})
.collect::<Vec<_>>()
.join(""),
);
}
Some("".into())
}
@ -296,15 +315,18 @@ fn needs_flags_tag(p: &Parser) -> bool {
}
// Returns the required args in usage string form by fully unrolling all groups
pub fn get_required_usage_from<'a, 'b>(p: &Parser<'a, 'b>,
reqs: &[&'a str],
matcher: Option<&ArgMatcher<'a>>,
extra: Option<&str>,
incl_last: bool)
-> VecDeque<String> {
debugln!("usage::get_required_usage_from: reqs={:?}, extra={:?}",
reqs,
extra);
pub fn get_required_usage_from<'a, 'b>(
p: &Parser<'a, 'b>,
reqs: &[&'a str],
matcher: Option<&ArgMatcher<'a>>,
extra: Option<&str>,
incl_last: bool,
) -> VecDeque<String> {
debugln!(
"usage::get_required_usage_from: reqs={:?}, extra={:?}",
reqs,
extra
);
let mut desc_reqs: Vec<&str> = vec![];
desc_reqs.extend(extra);
let mut new_reqs: Vec<&str> = vec![];
@ -346,8 +368,10 @@ pub fn get_required_usage_from<'a, 'b>(p: &Parser<'a, 'b>,
get_requires!(@group a, new_reqs, reqs);
}
desc_reqs.extend_from_slice(&*new_reqs);
debugln!("usage::get_required_usage_from: after init desc_reqs={:?}",
desc_reqs);
debugln!(
"usage::get_required_usage_from: after init desc_reqs={:?}",
desc_reqs
);
loop {
let mut tmp = vec![];
for a in &new_reqs {
@ -361,20 +385,26 @@ pub fn get_required_usage_from<'a, 'b>(p: &Parser<'a, 'b>,
break;
} else {
debugln!("usage::get_required_usage_from: after iter tmp={:?}", tmp);
debugln!("usage::get_required_usage_from: after iter new_reqs={:?}",
new_reqs);
debugln!(
"usage::get_required_usage_from: after iter new_reqs={:?}",
new_reqs
);
desc_reqs.extend_from_slice(&*new_reqs);
new_reqs.clear();
new_reqs.extend_from_slice(&*tmp);
debugln!("usage::get_required_usage_from: after iter desc_reqs={:?}",
desc_reqs);
debugln!(
"usage::get_required_usage_from: after iter desc_reqs={:?}",
desc_reqs
);
}
}
desc_reqs.extend_from_slice(reqs);
desc_reqs.sort();
desc_reqs.dedup();
debugln!("usage::get_required_usage_from: final desc_reqs={:?}",
desc_reqs);
debugln!(
"usage::get_required_usage_from: final desc_reqs={:?}",
desc_reqs
);
let mut ret_val = VecDeque::new();
let args_in_groups = p.groups
.iter()
@ -383,7 +413,8 @@ pub fn get_required_usage_from<'a, 'b>(p: &Parser<'a, 'b>,
.collect::<Vec<_>>();
let pmap = if let Some(m) = matcher {
desc_reqs.iter()
desc_reqs
.iter()
.filter(|a| p.positionals.values().any(|p| &&p.b.name == a))
.filter(|&pos| !m.contains(pos))
.filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos))
@ -392,7 +423,8 @@ pub fn get_required_usage_from<'a, 'b>(p: &Parser<'a, 'b>,
.map(|pos| (pos.index, pos))
.collect::<BTreeMap<u64, &PosBuilder>>() // sort by index
} else {
desc_reqs.iter()
desc_reqs
.iter()
.filter(|a| p.positionals.values().any(|pos| &&pos.b.name == a))
.filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos))
.filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
@ -400,31 +432,39 @@ pub fn get_required_usage_from<'a, 'b>(p: &Parser<'a, 'b>,
.map(|pos| (pos.index, pos))
.collect::<BTreeMap<u64, &PosBuilder>>() // sort by index
};
debugln!("usage::get_required_usage_from: args_in_groups={:?}",
args_in_groups);
debugln!(
"usage::get_required_usage_from: args_in_groups={:?}",
args_in_groups
);
for &p in pmap.values() {
let s = p.to_string();
if args_in_groups.is_empty() || !args_in_groups.contains(&&*s) {
ret_val.push_back(s);
}
}
for a in desc_reqs.iter()
.filter(|name| !p.positionals.values().any(|p| &&p.b.name == name))
.filter(|name| !p.groups.iter().any(|g| &&g.name == name))
.filter(|name| !args_in_groups.contains(name))
.filter(|name| !(matcher.is_some() && matcher.as_ref().unwrap().contains(name))) {
for a in desc_reqs
.iter()
.filter(|name| !p.positionals.values().any(|p| &&p.b.name == name))
.filter(|name| !p.groups.iter().any(|g| &&g.name == name))
.filter(|name| !args_in_groups.contains(name))
.filter(|name| {
!(matcher.is_some() && matcher.as_ref().unwrap().contains(name))
}) {
debugln!("usage::get_required_usage_from:iter:{}:", a);
let arg = find_by_name!(p, *a, flags, iter)
.map(|f| f.to_string())
.unwrap_or_else(|| {
find_by_name!(p, *a, opts, iter)
.map(|o| o.to_string())
.expect(INTERNAL_ERROR_MSG)
});
find_by_name!(p, *a, opts, iter)
.map(|o| o.to_string())
.expect(INTERNAL_ERROR_MSG)
});
ret_val.push_back(arg);
}
let mut g_vec: Vec<String> = vec![];
for g in desc_reqs.iter().filter(|n| p.groups.iter().any(|g| &&g.name == n)) {
for g in desc_reqs
.iter()
.filter(|n| p.groups.iter().any(|g| &&g.name == n))
{
let g_string = p.args_in_group(g).join("|");
let elem = format!("<{}>", &g_string[..g_string.len()]);
if !g_vec.contains(&elem) {

View file

@ -1,5 +1,7 @@
// std
use std::fmt::Display;
#[allow(unused_imports)]
use std::ascii::AsciiExt;
// Internal
use INTERNAL_ERROR_MSG;
@ -10,22 +12,24 @@ use errors::{Error, ErrorKind};
use errors::Result as ClapResult;
use osstringext::OsStrExt2;
use app::settings::AppSettings as AS;
use app::parser::{Parser, ParseResult};
use app::parser::{ParseResult, Parser};
use fmt::{Colorizer, ColorizerOption};
use app::usage;
pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>)
where 'a: 'b,
'b: 'z;
where
'a: 'b,
'b: 'z;
impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
pub fn new(p: &'z mut Parser<'a, 'b>) -> Self { Validator(p) }
pub fn validate(&mut self,
needs_val_of: ParseResult<'a>,
subcmd_name: Option<String>,
matcher: &mut ArgMatcher<'a>)
-> ClapResult<()> {
pub fn validate(
&mut self,
needs_val_of: ParseResult<'a>,
subcmd_name: Option<String>,
matcher: &mut ArgMatcher<'a>,
) -> ClapResult<()> {
debugln!("Validator::validate;");
let mut reqs_validated = false;
self.0.add_env(matcher)?;
@ -45,21 +49,24 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
true
};
if should_err {
return Err(Error::empty_value(o,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color()));
return Err(Error::empty_value(
o,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
));
}
}
if matcher.is_empty() && matcher.subcommand_name().is_none() &&
self.0.is_set(AS::ArgRequiredElseHelp) {
if matcher.is_empty() && matcher.subcommand_name().is_none()
&& self.0.is_set(AS::ArgRequiredElseHelp)
{
let mut out = vec![];
self.0.write_help_err(&mut out)?;
return Err(Error {
message: String::from_utf8_lossy(&*out).into_owned(),
kind: ErrorKind::MissingArgumentOrSubcommand,
info: None,
});
message: String::from_utf8_lossy(&*out).into_owned(),
kind: ErrorKind::MissingArgumentOrSubcommand,
info: None,
});
}
self.validate_blacklist(matcher)?;
if !(self.0.is_set(AS::SubcommandsNegateReqs) && subcmd_name.is_some()) && !reqs_validated {
@ -71,40 +78,54 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(())
}
fn validate_values<A>(&self,
arg: &A,
ma: &MatchedArg,
matcher: &ArgMatcher<'a>)
-> ClapResult<()>
where A: AnyArg<'a, 'b> + Display
fn validate_values<A>(
&self,
arg: &A,
ma: &MatchedArg,
matcher: &ArgMatcher<'a>,
) -> ClapResult<()>
where
A: AnyArg<'a, 'b> + Display,
{
debugln!("Validator::validate_values: arg={:?}", arg.name());
for val in &ma.vals {
if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
debugln!("Validator::validate_values: invalid UTF-8 found in val {:?}",
val);
return Err(Error::invalid_utf8(&*usage::create_error_usage(self.0, matcher, None),
self.0.color()));
debugln!(
"Validator::validate_values: invalid UTF-8 found in val {:?}",
val
);
return Err(Error::invalid_utf8(
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
));
}
if let Some(p_vals) = arg.possible_vals() {
debugln!("Validator::validate_values: possible_vals={:?}", p_vals);
let val_str = val.to_string_lossy();
if !p_vals.contains(&&*val_str) {
return Err(Error::invalid_value(val_str,
p_vals,
arg,
&*usage::create_error_usage(self.0,
matcher,
None),
self.0.color()));
let ok = if arg.is_set(ArgSettings::CaseInsensitive) {
p_vals.iter().any(|pv| pv.eq_ignore_ascii_case(&*val_str))
} else {
p_vals.contains(&&*val_str)
};
if !ok {
return Err(Error::invalid_value(
val_str,
p_vals,
arg,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
));
}
}
if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_() &&
matcher.contains(&*arg.name()) {
if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_()
&& matcher.contains(&*arg.name())
{
debugln!("Validator::validate_values: illegal empty val found");
return Err(Error::empty_value(arg,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color()));
return Err(Error::empty_value(
arg,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
));
}
if let Some(vtor) = arg.validator() {
debug!("Validator::validate_values: checking validator...");
@ -119,9 +140,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
debug!("Validator::validate_values: checking validator_os...");
if let Err(e) = vtor(val) {
sdebugln!("error");
return Err(Error::value_validation(Some(arg),
(*e).to_string_lossy().to_string(),
self.0.color()));
return Err(Error::value_validation(
Some(arg),
(*e).to_string_lossy().to_string(),
self.0.color(),
));
} else {
sdebugln!("good");
}
@ -131,8 +154,10 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
}
fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
debugln!("Validator::validate_blacklist: blacklist={:?}",
self.0.blacklist);
debugln!(
"Validator::validate_blacklist: blacklist={:?}",
self.0.blacklist
);
macro_rules! build_err {
($p:expr, $name:expr, $matcher:ident) => ({
debugln!("build_err!: name={}", $name);
@ -166,19 +191,36 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
}
for name in &self.0.blacklist {
debugln!("Validator::validate_blacklist:iter:{}: Checking blacklisted arg", name);
debugln!(
"Validator::validate_blacklist:iter:{}: Checking blacklisted arg",
name
);
let mut should_err = false;
if self.0.groups.iter().any(|g| &g.name == name) {
debugln!("Validator::validate_blacklist:iter:{}: groups contains it...", name);
debugln!(
"Validator::validate_blacklist:iter:{}: groups contains it...",
name
);
for n in self.0.arg_names_in_group(name) {
debugln!("Validator::validate_blacklist:iter:{}:iter:{}: looking in group...", name, n);
debugln!(
"Validator::validate_blacklist:iter:{}:iter:{}: looking in group...",
name,
n
);
if matcher.contains(n) {
debugln!("Validator::validate_blacklist:iter:{}:iter:{}: matcher contains it...", name, n);
debugln!(
"Validator::validate_blacklist:iter:{}:iter:{}: matcher contains it...",
name,
n
);
return Err(build_err!(self.0, n, matcher));
}
}
} else if let Some(ma) = matcher.get(name) {
debugln!("Validator::validate_blacklist:iter:{}: matcher contains it...", name);
debugln!(
"Validator::validate_blacklist:iter:{}: matcher contains it...",
name
);
should_err = ma.occurs > 0;
}
if should_err {
@ -191,9 +233,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
fn validate_matched_args(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
debugln!("Validator::validate_matched_args;");
for (name, ma) in matcher.iter() {
debugln!("Validator::validate_matched_args:iter:{}: vals={:#?}",
name,
ma.vals);
debugln!(
"Validator::validate_matched_args:iter:{}: vals={:#?}",
name,
ma.vals
);
if let Some(opt) = find_by_name!(self.0, *name, opts, iter) {
self.validate_arg_num_vals(opt, ma, matcher)?;
self.validate_values(opt, ma, matcher)?;
@ -223,31 +267,35 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(())
}
fn validate_arg_num_occurs<A>(&self,
a: &A,
ma: &MatchedArg,
matcher: &ArgMatcher)
-> ClapResult<()>
where A: AnyArg<'a, 'b> + Display
fn validate_arg_num_occurs<A>(
&self,
a: &A,
ma: &MatchedArg,
matcher: &ArgMatcher,
) -> ClapResult<()>
where
A: AnyArg<'a, 'b> + Display,
{
debugln!("Validator::validate_arg_num_occurs: a={};", a.name());
if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) {
// Not the first time, and we don't allow multiples
return Err(Error::unexpected_multiple_usage(a,
&*usage::create_error_usage(self.0,
matcher,
None),
self.0.color()));
return Err(Error::unexpected_multiple_usage(
a,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
));
}
Ok(())
}
fn validate_arg_num_vals<A>(&self,
a: &A,
ma: &MatchedArg,
matcher: &ArgMatcher)
-> ClapResult<()>
where A: AnyArg<'a, 'b> + Display
fn validate_arg_num_vals<A>(
&self,
a: &A,
ma: &MatchedArg,
matcher: &ArgMatcher,
) -> ClapResult<()>
where
A: AnyArg<'a, 'b> + Display,
{
debugln!("Validator::validate_arg_num_vals;");
if let Some(num) = a.num_vals() {
@ -259,74 +307,79 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
};
if should_err {
debugln!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues");
return Err(Error::wrong_number_of_values(a,
num,
if a.is_set(ArgSettings::Multiple) {
(ma.vals.len() % num as usize)
} else {
ma.vals.len()
},
if ma.vals.len() == 1 ||
(a.is_set(ArgSettings::Multiple) &&
(ma.vals.len() % num as usize) ==
1) {
"as"
} else {
"ere"
},
&*usage::create_error_usage(self.0,
matcher,
None),
self.0.color()));
return Err(Error::wrong_number_of_values(
a,
num,
if a.is_set(ArgSettings::Multiple) {
(ma.vals.len() % num as usize)
} else {
ma.vals.len()
},
if ma.vals.len() == 1
|| (a.is_set(ArgSettings::Multiple) && (ma.vals.len() % num as usize) == 1)
{
"as"
} else {
"ere"
},
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
));
}
}
if let Some(num) = a.max_vals() {
debugln!("Validator::validate_arg_num_vals: max_vals set...{}", num);
if (ma.vals.len() as u64) > num {
debugln!("Validator::validate_arg_num_vals: Sending error TooManyValues");
return Err(Error::too_many_values(ma.vals
.iter()
.last()
.expect(INTERNAL_ERROR_MSG)
.to_str()
.expect(INVALID_UTF8),
a,
&*usage::create_error_usage(self.0,
matcher,
None),
self.0.color()));
return Err(Error::too_many_values(
ma.vals
.iter()
.last()
.expect(INTERNAL_ERROR_MSG)
.to_str()
.expect(INVALID_UTF8),
a,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
));
}
}
let min_vals_zero = if let Some(num) = a.min_vals() {
debugln!("Validator::validate_arg_num_vals: min_vals set: {}", num);
if (ma.vals.len() as u64) < num && num != 0 {
debugln!("Validator::validate_arg_num_vals: Sending error TooFewValues");
return Err(Error::too_few_values(a,
num,
ma.vals.len(),
&*usage::create_error_usage(self.0,
matcher,
None),
self.0.color()));
return Err(Error::too_few_values(
a,
num,
ma.vals.len(),
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
));
}
num == 0
} else { false };
} else {
false
};
// Issue 665 (https://github.com/kbknapp/clap-rs/issues/665)
// Issue 1105 (https://github.com/kbknapp/clap-rs/issues/1105)
if a.takes_value() && !min_vals_zero && ma.vals.is_empty() {
return Err(Error::empty_value(a,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color()));
return Err(Error::empty_value(
a,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
));
}
Ok(())
}
fn validate_arg_requires<A>(&self,
a: &A,
ma: &MatchedArg,
matcher: &ArgMatcher)
-> ClapResult<()>
where A: AnyArg<'a, 'b> + Display
fn validate_arg_requires<A>(
&self,
a: &A,
ma: &MatchedArg,
matcher: &ArgMatcher,
) -> ClapResult<()>
where
A: AnyArg<'a, 'b> + Display,
{
debugln!("Validator::validate_arg_requires;");
if let Some(a_reqs) = a.requires() {
@ -342,8 +395,10 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
}
fn validate_required(&self, matcher: &ArgMatcher) -> ClapResult<()> {
debugln!("Validator::validate_required: required={:?};",
self.0.required);
debugln!(
"Validator::validate_required: required={:?};",
self.0.required
);
'outer: for name in &self.0.required {
debugln!("Validator::validate_required:iter:{}:", name);
if matcher.contains(name) {
@ -377,25 +432,25 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
}
fn validate_conflicts<A>(&self, a: &A, matcher: &ArgMatcher) -> Option<bool>
where A: AnyArg<'a, 'b>
where
A: AnyArg<'a, 'b>,
{
debugln!("Validator::validate_conflicts: a={:?};", a.name());
a.blacklist()
.map(|bl| {
bl.iter()
.any(|conf| {
matcher.contains(conf) ||
self.0
.groups
.iter()
.find(|g| &g.name == conf)
.map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
})
a.blacklist().map(|bl| {
bl.iter().any(|conf| {
matcher.contains(conf)
|| self.0
.groups
.iter()
.find(|g| &g.name == conf)
.map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
})
})
}
fn validate_required_unless<A>(&self, a: &A, matcher: &ArgMatcher) -> Option<bool>
where A: AnyArg<'a, 'b>
where
A: AnyArg<'a, 'b>,
{
debugln!("Validator::validate_required_unless: a={:?};", a.name());
macro_rules! check {
@ -426,11 +481,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
use_stderr: true,
when: self.0.color(),
});
let mut reqs = self.0
.required
.iter()
.map(|&r| &*r)
.collect::<Vec<_>>();
let mut reqs = self.0.required.iter().map(|&r| &*r).collect::<Vec<_>>();
if let Some(r) = extra {
reqs.push(r);
}
@ -440,22 +491,27 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
let req_args =
usage::get_required_usage_from(self.0, &reqs[..], Some(matcher), extra, true)
.iter()
.fold(String::new(),
|acc, s| acc + &format!("\n {}", c.error(s))[..]);
debugln!("Validator::missing_required_error: req_args={:#?}",
req_args);
Err(Error::missing_required_argument(&*req_args,
&*usage::create_error_usage(self.0, matcher, extra),
self.0.color()))
.fold(String::new(), |acc, s| {
acc + &format!("\n {}", c.error(s))[..]
});
debugln!(
"Validator::missing_required_error: req_args={:#?}",
req_args
);
Err(Error::missing_required_argument(
&*req_args,
&*usage::create_error_usage(self.0, matcher, extra),
self.0.color(),
))
}
#[inline]
fn is_missing_required_ok<A>(&self, a: &A, matcher: &ArgMatcher) -> bool
where A: AnyArg<'a, 'b>
where
A: AnyArg<'a, 'b>,
{
debugln!("Validator::is_missing_required_ok: a={}", a.name());
self.validate_conflicts(a, matcher).unwrap_or(false) ||
self.validate_required_unless(a, matcher)
.unwrap_or(false)
self.validate_conflicts(a, matcher).unwrap_or(false)
|| self.validate_required_unless(a, matcher).unwrap_or(false)
}
}

View file

@ -1,10 +1,10 @@
#[cfg(feature = "yaml")]
use std::collections::BTreeMap;
use std::rc::Rc;
use std::ffi::{OsString, OsStr};
#[cfg(target_os="windows")]
use std::ffi::{OsStr, OsString};
#[cfg(target_os = "windows")]
use osstringext::OsStrExt3;
#[cfg(not(target_os="windows"))]
#[cfg(not(target_os = "windows"))]
use std::os::unix::ffi::OsStrExt;
use std::env;
@ -14,7 +14,7 @@ use map::VecMap;
use usage_parser::UsageParser;
use args::settings::ArgSettings;
use args::arg_builder::{Base, Valued, Switched};
use args::arg_builder::{Base, Switched, Valued};
/// The abstract representation of a command line argument. Used to set all the options and
/// relationships that define a valid argument for the program.
@ -41,18 +41,14 @@ use args::arg_builder::{Base, Valued, Switched};
#[allow(missing_debug_implementations)]
#[derive(Default, Clone)]
pub struct Arg<'a, 'b>
where 'a: 'b
where
'a: 'b,
{
#[doc(hidden)]
pub b: Base<'a, 'b>,
#[doc(hidden)]
pub s: Switched<'b>,
#[doc(hidden)]
pub v: Valued<'a, 'b>,
#[doc(hidden)]
pub index: Option<u64>,
#[doc(hidden)]
pub r_ifs: Option<Vec<(&'a str, &'b str)>>,
#[doc(hidden)] pub b: Base<'a, 'b>,
#[doc(hidden)] pub s: Switched<'b>,
#[doc(hidden)] pub v: Valued<'a, 'b>,
#[doc(hidden)] pub index: Option<u64>,
#[doc(hidden)] pub r_ifs: Option<Vec<(&'a str, &'b str)>>,
}
impl<'a, 'b> Arg<'a, 'b> {
@ -73,7 +69,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
/// [`Arg`]: ./struct.Arg.html
pub fn with_name(n: &'a str) -> Self { Arg { b: Base::new(n), ..Default::default() } }
pub fn with_name(n: &'a str) -> Self {
Arg {
b: Base::new(n),
..Default::default()
}
}
/// Creates a new instance of [`Arg`] from a .yml (YAML) file.
///
@ -143,11 +144,11 @@ impl<'a, 'b> Arg<'a, 'b> {
a.setb(ArgSettings::RequiredUnlessAll);
a
}
s => {
panic!("Unknown Arg setting '{}' in YAML file for arg '{}'",
s,
name_str)
}
s => panic!(
"Unknown Arg setting '{}' in YAML file for arg '{}'",
s,
name_str
),
}
}
@ -605,10 +606,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// that cannot be read by this program. Obviously I'm going on
/// and on, so I'll stop now.
///
/// -h, --help
/// -h, --help
/// Prints help information
///
/// -V, --version
/// -V, --version
/// Prints version information
/// ```
/// [`Arg::help`]: ./struct.Arg.html#method.help
@ -624,13 +625,13 @@ impl<'a, 'b> Arg<'a, 'b> {
/// allows one to access this arg early using the `--` syntax. Accessing an arg early, even with
/// the `--` syntax is otherwise not possible.
///
/// **NOTE:** This will change the usage string to look like `$ prog [FLAGS] [-- <ARG>]` if
/// **NOTE:** This will change the usage string to look like `$ prog [FLAGS] [-- <ARG>]` if
/// `ARG` is marked as `.last(true)`.
///
/// **NOTE:** This setting will imply [`AppSettings::DontCollapseArgsInUsage`] because failing
/// to set this can make the usage string very confusing.
///
/// **NOTE**: This setting only applies to positional arguments, and has no affect on FLAGS /
/// **NOTE**: This setting only applies to positional arguments, and has no affect on FLAGS /
/// OPTIONS
///
/// **CAUTION:** Setting an argument to `.last(true)` *and* having child subcommands is not
@ -1891,10 +1892,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// **WARNING:**
///
/// Setting `multiple(true)` for an [option] with no other details, allows multiple values
/// **and** multiple occurrences because it isn't possible to have more occurrences than values
/// for options. Because multiple values are allowed, `--option val1 val2 val3` is perfectly
/// valid, be careful when designing a CLI where positional arguments are expected after a
/// option which accepts multiple values, as `clap` will continue parsing *values* until it
/// **and** multiple occurrences because it isn't possible to have more occurrences than values
/// for options. Because multiple values are allowed, `--option val1 val2 val3` is perfectly
/// valid, be careful when designing a CLI where positional arguments are expected after a
/// option which accepts multiple values, as `clap` will continue parsing *values* until it
/// reaches the max or specific number of values defined, or another flag or option.
///
/// **Pro Tip**:
@ -1904,35 +1905,35 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::multiple(true)`].
///
/// **WARNING:**
///
///
/// When using args with `multiple(true)` on [options] or [positionals] (i.e. those args that
/// accept values) and [subcommands], one needs to consider the posibility of an argument value
/// being the same as a valid subcommand. By default `clap` will parse the argument in question
/// as a value *only if* a value is possible at that moment. Otherwise it will be parsed as a
/// subcommand. In effect, this means using `multiple(true)` with no additional parameters and
/// a possible value that coincides with a subcommand name, the subcommand cannot be called
/// a possible value that coincides with a subcommand name, the subcommand cannot be called
/// unless another argument is passed first.
///
///
/// As an example, consider a CLI with an option `--ui-paths=<paths>...` and subcommand `signer`
///
///
/// The following would be parsed as values to `--ui-paths`.
///
///
/// ```notrust
/// $ program --ui-paths path1 path2 signer
/// ```
///
///
/// This is because `--ui-paths` accepts multiple values. `clap` will continue parsing values
/// until another argument is reached and it knows `--ui-paths` is done.
///
///
/// By adding additional parameters to `--ui-paths` we can solve this issue. Consider adding
/// [`Arg::number_of_values(1)`] as discussed above. The following are all valid, and `signer`
/// [`Arg::number_of_values(1)`] as discussed above. The following are all valid, and `signer`
/// is parsed as both a subcommand and a value in the second case.
///
///
/// ```notrust
/// $ program --ui-paths path1 signer
/// $ program --ui-paths path1 --ui-paths signer signer
/// ```
///
///
/// # Examples
///
/// ```rust
@ -2133,8 +2134,8 @@ impl<'a, 'b> Arg<'a, 'b> {
/// Specifies that an argument can be matched to all child [`SubCommand`]s.
///
/// **NOTE:** Global arguments *only* propagate down, **not** up (to parent commands), however
/// their values once a user uses them will be propagated back up to parents. In effect, this
/// means one should *define* all global arguments at the top level, however it doesn't matter
/// their values once a user uses them will be propagated back up to parents. In effect, this
/// means one should *define* all global arguments at the top level, however it doesn't matter
/// where the user *uses* the global argument.
///
/// # Examples
@ -2390,6 +2391,59 @@ impl<'a, 'b> Arg<'a, 'b> {
self
}
/// When used with [`Arg::possible_values`] it allows the argument value to pass validation even if
/// the case differs from that of the specified `possible_value`.
///
/// **Pro Tip:** Use this setting with [`arg_enum!`]
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg};
/// # use std::ascii::AsciiExt;
/// let m = App::new("pv")
/// .arg(Arg::with_name("option")
/// .long("--option")
/// .takes_value(true)
/// .possible_value("test123")
/// .case_insensitive(true))
/// .get_matches_from(vec![
/// "pv", "--option", "TeSt123",
/// ]);
///
/// assert!(m.value_of("option").unwrap().eq_ignore_ascii_case("test123"));
/// ```
///
/// This setting also works when multiple values can be defined:
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("pv")
/// .arg(Arg::with_name("option")
/// .short("-o")
/// .long("--option")
/// .takes_value(true)
/// .possible_value("test123")
/// .possible_value("test321")
/// .multiple(true)
/// .case_insensitive(true))
/// .get_matches_from(vec![
/// "pv", "--option", "TeSt123", "teST123", "tESt321"
/// ]);
///
/// let matched_vals = m.values_of("option").unwrap().collect::<Vec<_>>();
/// assert_eq!(&*matched_vals, &["TeSt123", "teST123", "tESt321"]);
/// ```
/// [`Arg::case_insensitive(true)`]: ./struct.Arg.html#method.possible_values
/// [`arg_enum!`]: ./macro.arg_enum.html
pub fn case_insensitive(self, ci: bool) -> Self {
if ci {
self.set(ArgSettings::CaseInsensitive)
} else {
self.unset(ArgSettings::CaseInsensitive)
}
}
/// Specifies the name of the [`ArgGroup`] the argument belongs to.
///
/// # Examples
@ -2550,19 +2604,20 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Err(String)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
/// [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html
pub fn validator<F>(mut self, f: F) -> Self
where F: Fn(String) -> Result<(), String> + 'static
where
F: Fn(String) -> Result<(), String> + 'static,
{
self.v.validator = Some(Rc::new(f));
self
}
/// Works identically to Validator but is intended to be used with values that could
/// Works identically to Validator but is intended to be used with values that could
/// contain non UTF-8 formatted strings.
///
/// # Examples
///
#[cfg_attr(not(unix), doc=" ```ignore")]
#[cfg_attr( unix , doc=" ```rust")]
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```rust")]
/// # use clap::{App, Arg};
/// # use std::ffi::{OsStr, OsString};
/// # use std::os::unix::ffi::OsStrExt;
@ -2587,7 +2642,8 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Err(String)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
/// [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html
pub fn validator_os<F>(mut self, f: F) -> Self
where F: Fn(&OsStr) -> Result<(), OsString> + 'static
where
F: Fn(&OsStr) -> Result<(), OsString> + 'static,
{
self.v.validator_os = Some(Rc::new(f));
self
@ -2890,9 +2946,11 @@ impl<'a, 'b> Arg<'a, 'b> {
self.unsetb(ArgSettings::ValueDelimiterNotSet);
self.setb(ArgSettings::TakesValue);
self.setb(ArgSettings::UseValueDelimiter);
self.v.val_delim = Some(d.chars()
.nth(0)
.expect("Failed to get value_delimiter from arg"));
self.v.val_delim = Some(
d.chars()
.nth(0)
.expect("Failed to get value_delimiter from arg"),
);
self
}
@ -3210,20 +3268,23 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
pub fn default_value_if(self, arg: &'a str, val: Option<&'b str>, default: &'b str) -> Self {
self.default_value_if_os(arg,
val.map(str::as_bytes).map(OsStr::from_bytes),
OsStr::from_bytes(default.as_bytes()))
self.default_value_if_os(
arg,
val.map(str::as_bytes).map(OsStr::from_bytes),
OsStr::from_bytes(default.as_bytes()),
)
}
/// Provides a conditional default value in the exact same manner as [`Arg::default_value_if`]
/// only using [`OsStr`]s instead.
/// [`Arg::default_value_if`]: ./struct.Arg.html#method.default_value_if
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
pub fn default_value_if_os(mut self,
arg: &'a str,
val: Option<&'b OsStr>,
default: &'b OsStr)
-> Self {
pub fn default_value_if_os(
mut self,
arg: &'a str,
val: Option<&'b OsStr>,
default: &'b OsStr,
) -> Self {
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vm) = self.v.default_vals_ifs {
let l = vm.len();
@ -3322,9 +3383,11 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
pub fn default_value_ifs(mut self, ifs: &[(&'a str, Option<&'b str>, &'b str)]) -> Self {
for &(arg, val, default) in ifs {
self = self.default_value_if_os(arg,
val.map(str::as_bytes).map(OsStr::from_bytes),
OsStr::from_bytes(default.as_bytes()));
self = self.default_value_if_os(
arg,
val.map(str::as_bytes).map(OsStr::from_bytes),
OsStr::from_bytes(default.as_bytes()),
);
}
self
}
@ -3344,7 +3407,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// Specifies that if the value is not passed in as an argument, that it should be retrieved
/// from the environment, if available. If it is not present in the environment, then default
/// rules will apply.
///
///
/// **NOTE:** If the user *does not* use this argument at runtime, [`ArgMatches::occurrences_of`]
/// will return `0` even though the [`ArgMatches::value_of`] will return the default specified.
///
@ -3352,23 +3415,23 @@ impl<'a, 'b> Arg<'a, 'b> {
/// return `true` if the variable is present in the environemnt . If you wish to determine whether
/// the argument was used at runtime or not, consider [`ArgMatches::occurrences_of`] which will
/// return `0` if the argument was *not* used at runtime.
///
///
/// **NOTE:** This implicitly sets [`Arg::takes_value(true)`].
///
///
/// **NOTE:** If [`Arg::multiple(true)`] is set then [`Arg::use_delimiter(true)`] should also be
/// set. Otherwise, only a single argument will be returned from the environment variable. The
/// default delimiter is `,` and follows all the other delimiter rules.
///
///
/// # Examples
///
///
/// In this example, we show the variable coming from the environment:
///
///
/// ```rust
/// # use std::env;
/// # use clap::{App, Arg};
///
/// env::set_var("MY_FLAG", "env");
///
///
/// let m = App::new("prog")
/// .arg(Arg::with_name("flag")
/// .long("flag")
@ -3379,15 +3442,15 @@ impl<'a, 'b> Arg<'a, 'b> {
///
/// assert_eq!(m.value_of("flag"), Some("env"));
/// ```
///
///
/// In this example, we show the variable coming from an option on the CLI:
///
///
/// ```rust
/// # use std::env;
/// # use clap::{App, Arg};
///
/// env::set_var("MY_FLAG", "env");
///
///
/// let m = App::new("prog")
/// .arg(Arg::with_name("flag")
/// .long("flag")
@ -3398,16 +3461,16 @@ impl<'a, 'b> Arg<'a, 'b> {
///
/// assert_eq!(m.value_of("flag"), Some("opt"));
/// ```
///
///
/// In this example, we show the variable coming from the environment even with the
/// presence of a default:
///
///
/// ```rust
/// # use std::env;
/// # use clap::{App, Arg};
///
/// env::set_var("MY_FLAG", "env");
///
///
/// let m = App::new("prog")
/// .arg(Arg::with_name("flag")
/// .long("flag")
@ -3419,15 +3482,15 @@ impl<'a, 'b> Arg<'a, 'b> {
///
/// assert_eq!(m.value_of("flag"), Some("env"));
/// ```
///
///
/// In this example, we show the use of multiple values in a single environment variable:
///
///
/// ```rust
/// # use std::env;
/// # use clap::{App, Arg};
///
/// env::set_var("MY_FLAG_MULTI", "env1,env2");
///
///
/// let m = App::new("prog")
/// .arg(Arg::with_name("flag")
/// .long("flag")
@ -3440,9 +3503,7 @@ impl<'a, 'b> Arg<'a, 'b> {
///
/// assert_eq!(m.values_of("flag").unwrap().collect::<Vec<_>>(), vec!["env1", "env2"]);
/// ```
pub fn env(self, name: &'a str) -> Self {
self.env_os(OsStr::new(name))
}
pub fn env(self, name: &'a str) -> Self { self.env_os(OsStr::new(name)) }
/// Specifies that if the value is not passed in as an argument, that it should be retrieved
/// from the environment if available in the exact same manner as [`Arg::env`] only using
@ -3606,7 +3667,5 @@ impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for Arg<'a, 'b> {
}
impl<'n, 'e> PartialEq for Arg<'n, 'e> {
fn eq(&self, other: &Arg<'n, 'e>) -> bool {
self.b == other.b
}
fn eq(&self, other: &Arg<'n, 'e>) -> bool { self.b == other.b }
}

View file

@ -1,9 +1,9 @@
use args::{ArgSettings, Arg, ArgFlags};
use args::{Arg, ArgFlags, ArgSettings};
#[derive(Debug, Clone, Default)]
pub struct Base<'a, 'b>
where 'a: 'b
where
'a: 'b,
{
pub name: &'a str,
pub help: Option<&'b str>,
@ -17,7 +17,12 @@ pub struct Base<'a, 'b>
}
impl<'n, 'e> Base<'n, 'e> {
pub fn new(name: &'n str) -> Self { Base { name: name, ..Default::default() } }
pub fn new(name: &'n str) -> Self {
Base {
name: name,
..Default::default()
}
}
pub fn set(&mut self, s: ArgSettings) { self.settings.set(s); }
pub fn unset(&mut self, s: ArgSettings) { self.settings.unset(s); }
@ -29,7 +34,5 @@ impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Base<'n, 'e> {
}
impl<'n, 'e> PartialEq for Base<'n, 'e> {
fn eq(&self, other: &Base<'n, 'e>) -> bool {
self.name == other.name
}
}
fn eq(&self, other: &Base<'n, 'e>) -> bool { self.name == other.name }
}

View file

@ -1,4 +1,3 @@
use Arg;
#[derive(Debug)]

View file

@ -21,16 +21,19 @@ impl<'a> Default for ArgMatcher<'a> {
impl<'a> ArgMatcher<'a> {
pub fn new() -> Self { ArgMatcher::default() }
pub fn propagate_globals(&mut self, global_arg_vec : &[&'a str]) {
debugln!("ArgMatcher::get_global_values: global_arg_vec={:?}", global_arg_vec);
pub fn propagate_globals(&mut self, global_arg_vec: &[&'a str]) {
debugln!(
"ArgMatcher::get_global_values: global_arg_vec={:?}",
global_arg_vec
);
let mut vals_map = HashMap::new();
self.fill_in_global_values(global_arg_vec, &mut vals_map);
}
fn fill_in_global_values(
&mut self,
global_arg_vec: &[&'a str],
vals_map: &mut HashMap<&'a str, MatchedArg>
&mut self,
global_arg_vec: &[&'a str],
vals_map: &mut HashMap<&'a str, MatchedArg>,
) {
for global_arg in global_arg_vec {
if let Some(ma) = self.get(global_arg) {
@ -120,7 +123,8 @@ impl<'a> ArgMatcher<'a> {
}
pub fn needs_more_vals<'b, A>(&self, o: &A) -> bool
where A: AnyArg<'a, 'b>
where
A: AnyArg<'a, 'b>,
{
debugln!("ArgMatcher::needs_more_vals: o={}", o.name());
if let Some(ma) = self.get(o.name()) {

View file

@ -59,12 +59,9 @@ use args::SubCommand;
/// [`App::get_matches`]: ./struct.App.html#method.get_matches
#[derive(Debug, Clone)]
pub struct ArgMatches<'a> {
#[doc(hidden)]
pub args: HashMap<&'a str, MatchedArg>,
#[doc(hidden)]
pub subcommand: Option<Box<SubCommand<'a>>>,
#[doc(hidden)]
pub usage: Option<String>,
#[doc(hidden)] pub args: HashMap<&'a str, MatchedArg>,
#[doc(hidden)] pub subcommand: Option<Box<SubCommand<'a>>>,
#[doc(hidden)] pub usage: Option<String>,
}
impl<'a> Default for ArgMatches<'a> {
@ -79,7 +76,11 @@ impl<'a> Default for ArgMatches<'a> {
impl<'a> ArgMatches<'a> {
#[doc(hidden)]
pub fn new() -> Self { ArgMatches { ..Default::default() } }
pub fn new() -> Self {
ArgMatches {
..Default::default()
}
}
/// Gets the value of a specific [option] or [positional] argument (i.e. an argument that takes
/// an additional value at runtime). If the option wasn't present at runtime
@ -126,8 +127,8 @@ impl<'a> ArgMatches<'a> {
///
/// # Examples
///
#[cfg_attr(not(unix), doc=" ```ignore")]
#[cfg_attr( unix , doc=" ```")]
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, Arg};
/// use std::ffi::OsString;
/// use std::os::unix::ffi::{OsStrExt,OsStringExt};
@ -161,8 +162,8 @@ impl<'a> ArgMatches<'a> {
///
/// # Examples
///
#[cfg_attr(not(unix), doc=" ```ignore")]
#[cfg_attr( unix , doc=" ```")]
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, Arg};
/// use std::ffi::OsString;
/// use std::os::unix::ffi::{OsStrExt,OsStringExt};
@ -211,7 +212,9 @@ impl<'a> ArgMatches<'a> {
if let Some(arg) = self.args.get(name.as_ref()) {
fn to_str_slice(o: &OsString) -> &str { o.to_str().expect(INVALID_UTF8) }
let to_str_slice: fn(&OsString) -> &str = to_str_slice; // coerce to fn pointer
return Some(Values { iter: arg.vals.iter().map(to_str_slice) });
return Some(Values {
iter: arg.vals.iter().map(to_str_slice),
});
}
None
}
@ -222,8 +225,8 @@ impl<'a> ArgMatches<'a> {
///
/// # Examples
///
#[cfg_attr(not(unix), doc=" ```ignore")]
#[cfg_attr( unix , doc=" ```")]
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, Arg};
/// use std::ffi::OsString;
/// use std::os::unix::ffi::OsStringExt;
@ -242,10 +245,12 @@ impl<'a> ArgMatches<'a> {
/// ```
pub fn values_of_lossy<S: AsRef<str>>(&'a self, name: S) -> Option<Vec<String>> {
if let Some(arg) = self.args.get(name.as_ref()) {
return Some(arg.vals
.iter()
.map(|v| v.to_string_lossy().into_owned())
.collect());
return Some(
arg.vals
.iter()
.map(|v| v.to_string_lossy().into_owned())
.collect(),
);
}
None
}
@ -258,8 +263,8 @@ impl<'a> ArgMatches<'a> {
///
/// # Examples
///
#[cfg_attr(not(unix), doc=" ```ignore")]
#[cfg_attr( unix , doc=" ```")]
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, Arg};
/// use std::ffi::{OsStr,OsString};
/// use std::os::unix::ffi::{OsStrExt,OsStringExt};
@ -285,7 +290,9 @@ impl<'a> ArgMatches<'a> {
fn to_str_slice(o: &OsString) -> &OsStr { &*o }
let to_str_slice: fn(&'a OsString) -> &'a OsStr = to_str_slice; // coerce to fn pointer
if let Some(arg) = self.args.get(name.as_ref()) {
return Some(OsValues { iter: arg.vals.iter().map(to_str_slice) });
return Some(OsValues {
iter: arg.vals.iter().map(to_str_slice),
});
}
None
}
@ -507,7 +514,9 @@ impl<'a> ArgMatches<'a> {
/// [`ArgMatches::subcommand_matches`]: ./struct.ArgMatches.html#method.subcommand_matches
/// [`ArgMatches::subcommand_name`]: ./struct.ArgMatches.html#method.subcommand_name
pub fn subcommand(&self) -> (&str, Option<&ArgMatches<'a>>) {
self.subcommand.as_ref().map_or(("", None), |sc| (&sc.name[..], Some(&sc.matches)))
self.subcommand
.as_ref()
.map_or(("", None), |sc| (&sc.name[..], Some(&sc.matches)))
}
/// Returns a string slice of the usage statement for the [`App`] or [`SubCommand`]
@ -573,7 +582,9 @@ impl<'a> Default for Values<'a> {
static EMPTY: [OsString; 0] = [];
// This is never called because the iterator is empty:
fn to_str_slice(_: &OsString) -> &str { unreachable!() };
Values { iter: EMPTY[..].iter().map(to_str_slice) }
Values {
iter: EMPTY[..].iter().map(to_str_slice),
}
}
}
@ -596,8 +607,8 @@ fn test_default_values_with_shorter_lifetime() {
///
/// # Examples
///
#[cfg_attr(not(unix), doc=" ```ignore")]
#[cfg_attr( unix , doc=" ```")]
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, Arg};
/// use std::ffi::OsString;
/// use std::os::unix::ffi::{OsStrExt,OsStringExt};
@ -634,7 +645,9 @@ impl<'a> Default for OsValues<'a> {
static EMPTY: [OsString; 0] = [];
// This is never called because the iterator is empty:
fn to_str_slice(_: &OsString) -> &OsStr { unreachable!() };
OsValues { iter: EMPTY[..].iter().map(to_str_slice) }
OsValues {
iter: EMPTY[..].iter().map(to_str_slice),
}
}
}

View file

@ -79,18 +79,12 @@ use yaml_rust::Yaml;
/// [requirement]: ./struct.Arg.html#method.requires
#[derive(Default)]
pub struct ArgGroup<'a> {
#[doc(hidden)]
pub name: &'a str,
#[doc(hidden)]
pub args: Vec<&'a str>,
#[doc(hidden)]
pub required: bool,
#[doc(hidden)]
pub requires: Option<Vec<&'a str>>,
#[doc(hidden)]
pub conflicts: Option<Vec<&'a str>>,
#[doc(hidden)]
pub multiple: bool,
#[doc(hidden)] pub name: &'a str,
#[doc(hidden)] pub args: Vec<&'a str>,
#[doc(hidden)] pub required: bool,
#[doc(hidden)] pub requires: Option<Vec<&'a str>>,
#[doc(hidden)] pub conflicts: Option<Vec<&'a str>>,
#[doc(hidden)] pub multiple: bool,
}
impl<'a> ArgGroup<'a> {
@ -154,9 +148,11 @@ impl<'a> ArgGroup<'a> {
/// [argument]: ./struct.Arg.html
#[cfg_attr(feature = "lints", allow(should_assert_eq))]
pub fn arg(mut self, n: &'a str) -> Self {
assert!(self.name != n,
"ArgGroup '{}' can not have same name as arg inside it",
&*self.name);
assert!(
self.name != n,
"ArgGroup '{}' can not have same name as arg inside it",
&*self.name
);
self.args.push(n);
self
}
@ -426,19 +422,21 @@ impl<'a> ArgGroup<'a> {
impl<'a> Debug for ArgGroup<'a> {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f,
"{{\n\
\tname: {:?},\n\
\targs: {:?},\n\
\trequired: {:?},\n\
\trequires: {:?},\n\
\tconflicts: {:?},\n\
}}",
self.name,
self.args,
self.required,
self.requires,
self.conflicts)
write!(
f,
"{{\n\
\tname: {:?},\n\
\targs: {:?},\n\
\trequired: {:?},\n\
\trequires: {:?},\n\
\tconflicts: {:?},\n\
}}",
self.name,
self.args,
self.required,
self.requires,
self.conflicts
)
}
}
@ -462,7 +460,9 @@ impl<'a> From<&'a BTreeMap<Yaml, Yaml>> for ArgGroup<'a> {
let mut a = ArgGroup::default();
let group_settings = if b.len() == 1 {
let name_yml = b.keys().nth(0).expect("failed to get name");
let name_str = name_yml.as_str().expect("failed to convert arg YAML name to str");
let name_str = name_yml
.as_str()
.expect("failed to convert arg YAML name to str");
a.name = name_str;
b.get(name_yml)
.expect("failed to get name_str")
@ -491,12 +491,12 @@ impl<'a> From<&'a BTreeMap<Yaml, Yaml>> for ArgGroup<'a> {
}
a
}
s => {
panic!("Unknown ArgGroup setting '{}' in YAML file for \
ArgGroup '{}'",
s,
a.name)
}
s => panic!(
"Unknown ArgGroup setting '{}' in YAML file for \
ArgGroup '{}'",
s,
a.name
),
}
}
@ -551,17 +551,19 @@ mod test {
let reqs = vec!["r1", "r2", "r3", "r4"];
let confs = vec!["c1", "c2", "c3", "c4"];
let debug_str = format!("{{\n\
\tname: \"test\",\n\
\targs: {:?},\n\
\trequired: {:?},\n\
\trequires: {:?},\n\
\tconflicts: {:?},\n\
}}",
args,
true,
Some(reqs),
Some(confs));
let debug_str = format!(
"{{\n\
\tname: \"test\",\n\
\targs: {:?},\n\
\trequired: {:?},\n\
\trequires: {:?},\n\
\tconflicts: {:?},\n\
}}",
args,
true,
Some(reqs),
Some(confs)
);
assert_eq!(&*format!("{:?}", g), &*debug_str);
}
@ -589,10 +591,9 @@ mod test {
assert_eq!(g2.conflicts, Some(confs));
}
#[cfg(feature="yaml")]
#[cfg(feature = "yaml")]
#[cfg_attr(feature = "yaml", test)]
fn test_yaml() {
let g_yaml = "name: test
args:
- a1

View file

@ -4,10 +4,8 @@ use std::ffi::OsString;
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct MatchedArg {
#[doc(hidden)]
pub occurs: u64,
#[doc(hidden)]
pub vals: Vec<OsString>,
#[doc(hidden)] pub occurs: u64,
#[doc(hidden)] pub vals: Vec<OsString>,
}
impl Default for MatchedArg {

View file

@ -1,8 +1,8 @@
pub use self::any_arg::{AnyArg, DispOrder};
pub use self::arg::Arg;
pub use self::arg_builder::{Base, Switched, Valued, FlagBuilder, OptBuilder, PosBuilder};
pub use self::arg_builder::{Base, FlagBuilder, OptBuilder, PosBuilder, Switched, Valued};
pub use self::arg_matcher::ArgMatcher;
pub use self::arg_matches::{Values, OsValues, ArgMatches};
pub use self::arg_matches::{ArgMatches, OsValues, Values};
pub use self::group::ArgGroup;
pub use self::matched_arg::MatchedArg;
pub use self::settings::{ArgFlags, ArgSettings};

View file

@ -1,10 +1,10 @@
// Std
#[allow(unused_imports)]
#[allow(unused_imports)]
use std::ascii::AsciiExt;
use std::str::FromStr;
bitflags! {
struct Flags: u16 {
struct Flags: u32 {
const REQUIRED = 1;
const MULTIPLE = 1 << 1;
const EMPTY_VALS = 1 << 2;
@ -21,6 +21,7 @@ bitflags! {
const REQUIRE_EQUALS = 1 << 13;
const LAST = 1 << 14;
const HIDE_DEFAULT_VAL = 1 << 15;
const CASE_INSENSITIVE = 1 << 16;
}
}
@ -47,6 +48,7 @@ impl ArgFlags {
AllowLeadingHyphen => Flags::ALLOW_TAC_VALS,
RequireEquals => Flags::REQUIRE_EQUALS,
Last => Flags::LAST,
CaseInsensitive => Flags::CASE_INSENSITIVE,
HideDefaultValue => Flags::HIDE_DEFAULT_VAL
}
}
@ -92,10 +94,10 @@ pub enum ArgSettings {
Last,
/// Hides the default value from the help string
HideDefaultValue,
#[doc(hidden)]
RequiredUnlessAll,
#[doc(hidden)]
ValueDelimiterNotSet,
/// Makes `Arg::possible_values` case insensitive
CaseInsensitive,
#[doc(hidden)] RequiredUnlessAll,
#[doc(hidden)] ValueDelimiterNotSet,
}
impl FromStr for ArgSettings {
@ -118,6 +120,7 @@ impl FromStr for ArgSettings {
"requireequals" => Ok(ArgSettings::RequireEquals),
"last" => Ok(ArgSettings::Last),
"hidedefaultvalue" => Ok(ArgSettings::HideDefaultValue),
"caseinsensitive" => Ok(ArgSettings::CaseInsensitive),
_ => Err("unknown ArgSetting, cannot convert from str".to_owned()),
}
}
@ -129,38 +132,71 @@ mod test {
#[test]
fn arg_settings_fromstr() {
assert_eq!("allowleadinghyphen".parse::<ArgSettings>().unwrap(),
ArgSettings::AllowLeadingHyphen);
assert_eq!("emptyvalues".parse::<ArgSettings>().unwrap(),
ArgSettings::EmptyValues);
assert_eq!("global".parse::<ArgSettings>().unwrap(),
ArgSettings::Global);
assert_eq!("hidepossiblevalues".parse::<ArgSettings>().unwrap(),
ArgSettings::HidePossibleValues);
assert_eq!("hidden".parse::<ArgSettings>().unwrap(),
ArgSettings::Hidden);
assert_eq!("multiple".parse::<ArgSettings>().unwrap(),
ArgSettings::Multiple);
assert_eq!("nextlinehelp".parse::<ArgSettings>().unwrap(),
ArgSettings::NextLineHelp);
assert_eq!("requiredunlessall".parse::<ArgSettings>().unwrap(),
ArgSettings::RequiredUnlessAll);
assert_eq!("requiredelimiter".parse::<ArgSettings>().unwrap(),
ArgSettings::RequireDelimiter);
assert_eq!("required".parse::<ArgSettings>().unwrap(),
ArgSettings::Required);
assert_eq!("takesvalue".parse::<ArgSettings>().unwrap(),
ArgSettings::TakesValue);
assert_eq!("usevaluedelimiter".parse::<ArgSettings>().unwrap(),
ArgSettings::UseValueDelimiter);
assert_eq!("valuedelimiternotset".parse::<ArgSettings>().unwrap(),
ArgSettings::ValueDelimiterNotSet);
assert_eq!("requireequals".parse::<ArgSettings>().unwrap(),
ArgSettings::RequireEquals);
assert_eq!("last".parse::<ArgSettings>().unwrap(),
ArgSettings::Last);
assert_eq!("hidedefaultvalue".parse::<ArgSettings>().unwrap(),
ArgSettings::HideDefaultValue);
assert_eq!(
"allowleadinghyphen".parse::<ArgSettings>().unwrap(),
ArgSettings::AllowLeadingHyphen
);
assert_eq!(
"emptyvalues".parse::<ArgSettings>().unwrap(),
ArgSettings::EmptyValues
);
assert_eq!(
"global".parse::<ArgSettings>().unwrap(),
ArgSettings::Global
);
assert_eq!(
"hidepossiblevalues".parse::<ArgSettings>().unwrap(),
ArgSettings::HidePossibleValues
);
assert_eq!(
"hidden".parse::<ArgSettings>().unwrap(),
ArgSettings::Hidden
);
assert_eq!(
"multiple".parse::<ArgSettings>().unwrap(),
ArgSettings::Multiple
);
assert_eq!(
"nextlinehelp".parse::<ArgSettings>().unwrap(),
ArgSettings::NextLineHelp
);
assert_eq!(
"requiredunlessall".parse::<ArgSettings>().unwrap(),
ArgSettings::RequiredUnlessAll
);
assert_eq!(
"requiredelimiter".parse::<ArgSettings>().unwrap(),
ArgSettings::RequireDelimiter
);
assert_eq!(
"required".parse::<ArgSettings>().unwrap(),
ArgSettings::Required
);
assert_eq!(
"takesvalue".parse::<ArgSettings>().unwrap(),
ArgSettings::TakesValue
);
assert_eq!(
"usevaluedelimiter".parse::<ArgSettings>().unwrap(),
ArgSettings::UseValueDelimiter
);
assert_eq!(
"valuedelimiternotset".parse::<ArgSettings>().unwrap(),
ArgSettings::ValueDelimiterNotSet
);
assert_eq!(
"requireequals".parse::<ArgSettings>().unwrap(),
ArgSettings::RequireEquals
);
assert_eq!("last".parse::<ArgSettings>().unwrap(), ArgSettings::Last);
assert_eq!(
"hidedefaultvalue".parse::<ArgSettings>().unwrap(),
ArgSettings::HideDefaultValue
);
assert_eq!(
"caseinsensitive".parse::<ArgSettings>().unwrap(),
ArgSettings::CaseInsensitive
);
assert!("hahahaha".parse::<ArgSettings>().is_err());
}
}

View file

@ -29,10 +29,8 @@ use ArgMatches;
/// [arguments]: ./struct.Arg.html
#[derive(Debug, Clone)]
pub struct SubCommand<'a> {
#[doc(hidden)]
pub name: String,
#[doc(hidden)]
pub matches: ArgMatches<'a>,
#[doc(hidden)] pub name: String,
#[doc(hidden)] pub matches: ArgMatches<'a>,
}
impl<'a> SubCommand<'a> {

View file

@ -7,7 +7,8 @@ use args::{ArgSettings, OptBuilder};
use completions;
pub struct BashGen<'a, 'b>
where 'a: 'b
where
'a: 'b,
{
p: &'b Parser<'a, 'b>,
}
@ -16,9 +17,10 @@ impl<'a, 'b> BashGen<'a, 'b> {
pub fn new(p: &'b Parser<'a, 'b>) -> Self { BashGen { p: p } }
pub fn generate_to<W: Write>(&self, buf: &mut W) {
w!(buf,
format!("_{name}() {{
w!(
buf,
format!(
"_{name}() {{
local i cur prev opts cmds
COMPREPLY=()
cur=\"${{COMP_WORDS[COMP_CWORD]}}\"
@ -60,13 +62,14 @@ impl<'a, 'b> BashGen<'a, 'b> {
complete -F _{name} -o bashdefault -o default {name}
",
name = self.p.meta.bin_name.as_ref().unwrap(),
name_opts = self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()),
name_opts_details =
self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
subcmds = self.all_subcommands(),
subcmd_details = self.subcommand_details())
.as_bytes());
name = self.p.meta.bin_name.as_ref().unwrap(),
name_opts = self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()),
name_opts_details =
self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
subcmds = self.all_subcommands(),
subcmd_details = self.subcommand_details()
).as_bytes()
);
}
fn all_subcommands(&self) -> String {
@ -75,12 +78,14 @@ complete -F _{name} -o bashdefault -o default {name}
let scs = completions::all_subcommand_names(self.p);
for sc in &scs {
subcmds = format!("{}
subcmds = format!(
"{}
{name})
cmd+=\"__{name}\"
;;",
subcmds,
name = sc.replace("-", "__"));
subcmds,
name = sc.replace("-", "__")
);
}
subcmds
@ -94,7 +99,8 @@ complete -F _{name} -o bashdefault -o default {name}
scs.dedup();
for sc in &scs {
subcmd_dets = format!("{}
subcmd_dets = format!(
"{}
{subcmd})
opts=\"{sc_opts}\"
if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then
@ -110,11 +116,12 @@ complete -F _{name} -o bashdefault -o default {name}
COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
return 0
;;",
subcmd_dets,
subcmd = sc.replace("-", "__"),
sc_opts = self.all_options_for_path(&*sc),
level = sc.split("__").map(|_| 1).fold(0, |acc, n| acc + n),
opts_details = self.option_details_for_path(&*sc));
subcmd_dets,
subcmd = sc.replace("-", "__"),
sc_opts = self.all_options_for_path(&*sc),
level = sc.split("__").map(|_| 1).fold(0, |acc, n| acc + n),
opts_details = self.option_details_for_path(&*sc)
);
}
subcmd_dets
@ -130,24 +137,28 @@ complete -F _{name} -o bashdefault -o default {name}
let mut opts = String::new();
for o in p.opts() {
if let Some(l) = o.s.long {
opts = format!("{}
opts = format!(
"{}
--{})
COMPREPLY=({})
return 0
;;",
opts,
l,
self.vals_for(o));
opts,
l,
self.vals_for(o)
);
}
if let Some(s) = o.s.short {
opts = format!("{}
opts = format!(
"{}
-{})
COMPREPLY=({})
return 0
;;",
opts,
s,
self.vals_for(o));
opts,
s,
self.vals_for(o)
);
}
}
opts
@ -164,10 +175,12 @@ complete -F _{name} -o bashdefault -o default {name}
} else if let Some(vec) = o.val_names() {
let mut it = vec.iter().peekable();
while let Some((_, val)) = it.next() {
ret = format!("{}<{}>{}",
ret,
val,
if it.peek().is_some() { " " } else { "" });
ret = format!(
"{}<{}>{}",
ret,
val,
if it.peek().is_some() { " " } else { "" }
);
}
let num = vec.len();
if o.is_set(ArgSettings::Multiple) && num == 1 {
@ -176,10 +189,12 @@ complete -F _{name} -o bashdefault -o default {name}
} else if let Some(num) = o.num_vals() {
let mut it = (0..num).peekable();
while let Some(_) = it.next() {
ret = format!("{}<{}>{}",
ret,
o.name(),
if it.peek().is_some() { " " } else { "" });
ret = format!(
"{}<{}>{}",
ret,
o.name(),
if it.peek().is_some() { " " } else { "" }
);
}
if o.is_set(ArgSettings::Multiple) && num == 1 {
ret = format!("{}...", ret);
@ -203,26 +218,35 @@ complete -F _{name} -o bashdefault -o default {name}
p = &find_subcmd!(p, sc).unwrap().p;
}
let mut opts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s));
opts = format!("{} {}",
opts,
longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l)));
opts = format!("{} {}",
opts,
p.positionals
.values()
.fold(String::new(), |acc, p| format!("{} {}", acc, p)));
opts = format!("{} {}",
opts,
p.subcommands
.iter()
.fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name)));
opts = format!(
"{} {}",
opts,
longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l))
);
opts = format!(
"{} {}",
opts,
p.positionals
.values()
.fold(String::new(), |acc, p| format!("{} {}", acc, p))
);
opts = format!(
"{} {}",
opts,
p.subcommands
.iter()
.fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name))
);
for sc in &p.subcommands {
if let Some(ref aliases) = sc.p.meta.aliases {
opts = format!("{} {}",
opts,
aliases.iter()
.map(|&(n, _)| n)
.fold(String::new(), |acc, a| format!("{} {}", acc, a)));
opts = format!(
"{} {}",
opts,
aliases
.iter()
.map(|&(n, _)| n)
.fold(String::new(), |acc, a| format!("{} {}", acc, a))
);
}
}
opts

View file

@ -1,4 +1,3 @@
// Std
use std::io::Write;
@ -6,7 +5,8 @@ use std::io::Write;
use app::parser::Parser;
pub struct FishGen<'a, 'b>
where 'a: 'b
where
'a: 'b,
{
p: &'b Parser<'a, 'b>,
}
@ -31,8 +31,7 @@ impl<'a, 'b> FishGen<'a, 'b> {
return 1
end
"#
.to_string();
"#.to_string();
let mut buffer = detect_subcommand_function;
gen_fish_inner(command, self, &command.to_string(), &mut buffer);
@ -41,9 +40,7 @@ end
}
// Escape string inside single quotes
fn escape_string(string: &str) -> String {
string.replace("\\", "\\\\").replace("'", "\\'")
}
fn escape_string(string: &str) -> String { string.replace("\\", "\\\\").replace("'", "\\'") }
fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, parent_cmds: &str, buffer: &mut String) {
debugln!("FishGen::gen_fish_inner;");
@ -59,9 +56,11 @@ fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, parent_cmds: &str, buf
// -f # don't use file completion
// -n "__fish_using_command myprog subcmd1" # complete for command "myprog subcmd1"
let basic_template = format!("complete -c {} -n \"__fish_using_command {}\"",
root_command,
parent_cmds);
let basic_template = format!(
"complete -c {} -n \"__fish_using_command {}\"",
root_command,
parent_cmds
);
for option in comp_gen.p.opts() {
let mut template = basic_template.clone();

View file

@ -1,4 +1,3 @@
macro_rules! w {
($buf:expr, $to_w:expr) => {
match $buf.write_all($to_w) {
@ -20,7 +19,7 @@ macro_rules! get_zsh_arg_conflicts {
if let Some(l) = arg.long() {
v.push(format!("--{}", l));
}
}
}
v.join(" ")
} else {
String::new()

View file

@ -18,7 +18,8 @@ use self::powershell::PowerShellGen;
pub use self::shell::Shell;
pub struct ComplGen<'a, 'b>
where 'a: 'b
where
'a: 'b,
{
p: &'b Parser<'a, 'b>,
}
@ -44,7 +45,10 @@ impl<'a, 'b> ComplGen<'a, 'b> {
// aliasing.
pub fn all_subcommand_names(p: &Parser) -> Vec<String> {
debugln!("all_subcommand_names;");
let mut subcmds: Vec<_> = subcommands_of(p).iter().map(|&(ref n, _)| n.clone()).collect();
let mut subcmds: Vec<_> = subcommands_of(p)
.iter()
.map(|&(ref n, _)| n.clone())
.collect();
for sc_v in p.subcommands.iter().map(|s| all_subcommand_names(&s.p)) {
subcmds.extend(sc_v);
}
@ -75,14 +79,24 @@ pub fn all_subcommands(p: &Parser) -> Vec<(String, String)> {
// Also note, aliases are treated as their own subcommands but duplicates of whatever they're
// aliasing.
pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> {
debugln!("subcommands_of: name={}, bin_name={}",
p.meta.name,
p.meta.bin_name.as_ref().unwrap());
debugln!(
"subcommands_of: name={}, bin_name={}",
p.meta.name,
p.meta.bin_name.as_ref().unwrap()
);
let mut subcmds = vec![];
debugln!("subcommands_of: Has subcommands...{:?}", p.has_subcommands());
debugln!(
"subcommands_of: Has subcommands...{:?}",
p.has_subcommands()
);
if !p.has_subcommands() {
let mut ret = vec![(p.meta.name.clone(), p.meta.bin_name.as_ref().unwrap().clone())];
let mut ret = vec![
(
p.meta.name.clone(),
p.meta.bin_name.as_ref().unwrap().clone(),
),
];
debugln!("subcommands_of: Looking for aliases...");
if let Some(ref aliases) = p.meta.aliases {
for &(n, _) in aliases {
@ -98,9 +112,11 @@ pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> {
return ret;
}
for sc in &p.subcommands {
debugln!("subcommands_of:iter: name={}, bin_name={}",
sc.p.meta.name,
sc.p.meta.bin_name.as_ref().unwrap());
debugln!(
"subcommands_of:iter: name={}, bin_name={}",
sc.p.meta.name,
sc.p.meta.bin_name.as_ref().unwrap()
);
debugln!("subcommands_of:iter: Looking for aliases...");
if let Some(ref aliases) = sc.p.meta.aliases {
@ -114,7 +130,10 @@ pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> {
subcmds.push((n.to_owned(), als_bin_name.join(" ")));
}
}
subcmds.push((sc.p.meta.name.clone(), sc.p.meta.bin_name.as_ref().unwrap().clone()));
subcmds.push((
sc.p.meta.name.clone(),
sc.p.meta.bin_name.as_ref().unwrap().clone(),
));
}
subcmds
}
@ -138,7 +157,13 @@ pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
}
for sc in &p.subcommands {
let name = &*sc.p.meta.name;
let path = sc.p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "__");
let path = sc.p
.meta
.bin_name
.as_ref()
.unwrap()
.clone()
.replace(" ", "__");
subcmds.push(path.clone());
if let Some(ref aliases) = sc.p.meta.aliases {
for &(n, _) in aliases {
@ -146,7 +171,10 @@ pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
}
}
}
for sc_v in p.subcommands.iter().map(|s| get_all_subcommand_paths(&s.p, false)) {
for sc_v in p.subcommands
.iter()
.map(|s| get_all_subcommand_paths(&s.p, false))
{
subcmds.extend(sc_v);
}
subcmds

View file

@ -1,4 +1,3 @@
// Std
use std::io::Write;
@ -7,7 +6,8 @@ use app::parser::Parser;
use INTERNAL_ERROR_MSG;
pub struct PowerShellGen<'a, 'b>
where 'a: 'b
where
'a: 'b,
{
p: &'b Parser<'a, 'b>,
}
@ -19,7 +19,8 @@ impl<'a, 'b> PowerShellGen<'a, 'b> {
let bin_name = self.p.meta.bin_name.as_ref().unwrap();
let mut names = vec![];
let (subcommands_detection_cases, subcommands_cases) = generate_inner(self.p, "", &mut names);
let (subcommands_detection_cases, subcommands_cases) =
generate_inner(self.p, "", &mut names);
let mut bin_names = vec![bin_name.to_string(), format!("./{0}", bin_name)];
if cfg!(windows) {
@ -74,23 +75,33 @@ impl<'a, 'b> PowerShellGen<'a, 'b> {
}
}
fn generate_inner<'a, 'b, 'p>(p: &'p Parser<'a, 'b>, previous_command_name: &str, names: &mut Vec<&'p str>) -> (String, String) {
fn generate_inner<'a, 'b, 'p>(
p: &'p Parser<'a, 'b>,
previous_command_name: &str,
names: &mut Vec<&'p str>,
) -> (String, String) {
debugln!("PowerShellGen::generate_inner;");
let command_name = if previous_command_name.is_empty() {
format!("{}_{}", previous_command_name, &p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG))
format!(
"{}_{}",
previous_command_name,
&p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG)
)
} else {
format!("{}_{}", previous_command_name, &p.meta.name)
};
let mut subcommands_detection_cases = if !names.contains(&&*p.meta.name) {
names.push(&*p.meta.name);
format!(r"
format!(
r"
'{0}' {{
$command += '_{0}'
break
}}
",
&p.meta.name)
&p.meta.name
)
} else {
String::new()
};
@ -106,13 +117,15 @@ fn generate_inner<'a, 'b, 'p>(p: &'p Parser<'a, 'b>, previous_command_name: &str
completions.push_str(&format!("'--{}', ", long));
}
let mut subcommands_cases = format!(r"
let mut subcommands_cases = format!(
r"
'{}' {{
$completions = @({})
}}
",
&command_name,
completions.trim_right_matches(", "));
&command_name,
completions.trim_right_matches(", ")
);
for subcommand in &p.subcommands {
let (subcommand_subcommands_detection_cases, subcommand_subcommands_cases) =

View file

@ -1,4 +1,4 @@
#[allow(unused_imports)]
#[allow(unused_imports)]
use std::ascii::AsciiExt;
use std::str::FromStr;
use std::fmt;
@ -27,7 +27,6 @@ impl FromStr for Shell {
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"ZSH" | _ if s.eq_ignore_ascii_case("zsh") => Ok(Shell::Zsh),
"FISH" | _ if s.eq_ignore_ascii_case("fish") => Ok(Shell::Fish),
"BASH" | _ if s.eq_ignore_ascii_case("bash") => Ok(Shell::Bash),

View file

@ -1,18 +1,18 @@
// Std
use std::io::Write;
#[allow(unused_imports)]
#[allow(unused_imports)]
use std::ascii::AsciiExt;
// Internal
use app::App;
use app::parser::Parser;
use args::{ArgSettings, AnyArg};
use args::{AnyArg, ArgSettings};
use completions;
use INTERNAL_ERROR_MSG;
pub struct ZshGen<'a, 'b>
where 'a: 'b
where
'a: 'b,
{
p: &'b Parser<'a, 'b>,
}
@ -25,8 +25,10 @@ impl<'a, 'b> ZshGen<'a, 'b> {
pub fn generate_to<W: Write>(&self, buf: &mut W) {
debugln!("ZshGen::generate_to;");
w!(buf,
format!("\
w!(
buf,
format!(
"\
#compdef {name}
_{name}() {{
@ -41,11 +43,12 @@ _{name}() {{
{subcommand_details}
_{name} \"$@\"",
name = self.p.meta.bin_name.as_ref().unwrap(),
initial_args = get_args_of(self.p),
subcommands = get_subcommands_of(self.p),
subcommand_details = subcommand_details(self.p)).as_bytes());
name = self.p.meta.bin_name.as_ref().unwrap(),
initial_args = get_args_of(self.p),
subcommands = get_subcommands_of(self.p),
subcommand_details = subcommand_details(self.p)
).as_bytes()
);
}
}
@ -79,7 +82,9 @@ _{name} \"$@\"",
fn subcommand_details(p: &Parser) -> String {
debugln!("ZshGen::subcommand_details;");
// First we do ourself
let mut ret = vec![format!("\
let mut ret = vec![
format!(
"\
(( $+functions[_{bin_name_underscore}_commands] )) ||
_{bin_name_underscore}_commands() {{
local commands; commands=(
@ -89,7 +94,9 @@ _{bin_name_underscore}_commands() {{
}}",
bin_name_underscore = p.meta.bin_name.as_ref().unwrap().replace(" ", "__"),
bin_name = p.meta.bin_name.as_ref().unwrap(),
subcommands_and_args = subcommands_and_args_of(p))];
subcommands_and_args = subcommands_and_args_of(p)
),
];
// Next we start looping through all the children, grandchildren, etc.
let mut all_subcommands = completions::all_subcommands(p);
@ -97,7 +104,8 @@ _{bin_name_underscore}_commands() {{
all_subcommands.dedup();
for &(_, ref bin_name) in &all_subcommands {
debugln!("ZshGen::subcommand_details:iter: bin_name={}", bin_name);
ret.push(format!("\
ret.push(format!(
"\
(( $+functions[_{bin_name_underscore}_commands] )) ||
_{bin_name_underscore}_commands() {{
local commands; commands=(
@ -107,7 +115,8 @@ _{bin_name_underscore}_commands() {{
}}",
bin_name_underscore = bin_name.replace(" ", "__"),
bin_name = bin_name,
subcommands_and_args = subcommands_and_args_of(parser_of(p, bin_name))));
subcommands_and_args = subcommands_and_args_of(parser_of(p, bin_name))
));
}
ret.join("\n")
@ -129,9 +138,16 @@ fn subcommands_and_args_of(p: &Parser) -> String {
let mut ret = vec![];
fn add_sc(sc: &App, n: &str, ret: &mut Vec<String>) {
debugln!("ZshGen::add_sc;");
let s = format!("\"{name}:{help}\" \\",
name = n,
help = sc.p.meta.about.unwrap_or("").replace("[", "\\[").replace("]", "\\]"));
let s = format!(
"\"{name}:{help}\" \\",
name = n,
help = sc.p
.meta
.about
.unwrap_or("")
.replace("[", "\\[")
.replace("]", "\\]")
);
if !s.is_empty() {
ret.push(s);
}
@ -139,7 +155,10 @@ fn subcommands_and_args_of(p: &Parser) -> String {
// First the subcommands
for sc in p.subcommands() {
debugln!("ZshGen::subcommands_and_args_of:iter: subcommand={}", sc.p.meta.name);
debugln!(
"ZshGen::subcommands_and_args_of:iter: subcommand={}",
sc.p.meta.name
);
add_sc(sc, &sc.p.meta.name, &mut ret);
if let Some(ref v) = sc.p.meta.aliases {
for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) {
@ -151,9 +170,15 @@ fn subcommands_and_args_of(p: &Parser) -> String {
// Then the positional args
for arg in p.positionals() {
debugln!("ZshGen::subcommands_and_args_of:iter: arg={}", arg.b.name);
let a = format!("\"{name}:{help}\" \\",
name = arg.b.name.to_ascii_uppercase(),
help = arg.b.help.unwrap_or("").replace("[", "\\[").replace("]", "\\]"));
let a = format!(
"\"{name}:{help}\" \\",
name = arg.b.name.to_ascii_uppercase(),
help = arg.b
.help
.unwrap_or("")
.replace("[", "\\[")
.replace("]", "\\]")
);
if !a.is_empty() {
ret.push(a);
@ -195,7 +220,10 @@ fn subcommands_and_args_of(p: &Parser) -> String {
fn get_subcommands_of(p: &Parser) -> String {
debugln!("get_subcommands_of;");
debugln!("get_subcommands_of: Has subcommands...{:?}", p.has_subcommands());
debugln!(
"get_subcommands_of: Has subcommands...{:?}",
p.has_subcommands()
);
if !p.has_subcommands() {
return String::new();
}
@ -218,17 +246,18 @@ fn get_subcommands_of(p: &Parser) -> String {
}
format!(
"case $state in
"case $state in
({name})
curcontext=\"${{curcontext%:*:*}}:{name_hyphen}-command-$words[1]:\"
case $line[1] in
{subcommands}
esac
;;
esac",
esac",
name = p.meta.name,
name_hyphen = p.meta.bin_name.as_ref().unwrap().replace(" ", "-"),
subcommands = subcmds.join("\n"))
subcommands = subcmds.join("\n")
)
}
fn parser_of<'a, 'b>(p: &'b Parser<'a, 'b>, sc: &str) -> &'b Parser<'a, 'b> {
@ -265,8 +294,10 @@ fn get_args_of(p: &Parser) -> String {
let opts = write_opts_of(p);
let flags = write_flags_of(p);
let sc_or_a = if p.has_subcommands() || p.has_positionals() {
format!("\"1:: :_{name}_commands\" \\",
name = p.meta.bin_name.as_ref().unwrap().replace(" ", "__"))
format!(
"\"1:: :_{name}_commands\" \\",
name = p.meta.bin_name.as_ref().unwrap().replace(" ", "__")
)
} else {
String::new()
};
@ -295,7 +326,8 @@ fn get_args_of(p: &Parser) -> String {
// Escape string inside single quotes and brackets
fn escape_string(string: &str) -> String {
string.replace("\\", "\\\\")
string
.replace("\\", "\\\\")
.replace("'", "'\\''")
.replace("[", "\\[")
.replace("]", "\\]")
@ -325,23 +357,27 @@ fn write_opts_of(p: &Parser) -> String {
String::new()
};
if let Some(short) = o.short() {
let s = format!("'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\",
let s = format!(
"'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\",
conflicts = conflicts,
multiple = multiple,
arg = short,
possible_values = pv,
help = help);
help = help
);
debugln!("write_opts_of:iter: Wrote...{}", &*s);
ret.push(s);
}
if let Some(long) = o.long() {
let l = format!("'{conflicts}{multiple}--{arg}+[{help}]{possible_values}' \\",
let l = format!(
"'{conflicts}{multiple}--{arg}+[{help}]{possible_values}' \\",
conflicts = conflicts,
multiple = multiple,
arg = long,
possible_values = pv,
help = help);
help = help
);
debugln!("write_opts_of:iter: Wrote...{}", &*l);
ret.push(l);
@ -370,22 +406,26 @@ fn write_flags_of(p: &Parser) -> String {
""
};
if let Some(short) = f.short() {
let s = format!("'{conflicts}{multiple}-{arg}[{help}]' \\",
let s = format!(
"'{conflicts}{multiple}-{arg}[{help}]' \\",
multiple = multiple,
conflicts = conflicts,
arg = short,
help = help);
help = help
);
debugln!("write_flags_of:iter: Wrote...{}", &*s);
ret.push(s);
}
if let Some(long) = f.long() {
let l = format!("'{conflicts}{multiple}--{arg}[{help}]' \\",
let l = format!(
"'{conflicts}{multiple}--{arg}[{help}]' \\",
conflicts = conflicts,
multiple = multiple,
arg = long,
help = help);
help = help
);
debugln!("write_flags_of:iter: Wrote...{}", &*l);
ret.push(l);

View file

@ -8,8 +8,8 @@ use std::process;
use std::result::Result as StdResult;
// Internal
use args::{FlagBuilder, AnyArg};
use fmt::{Colorizer, ColorizerOption, ColorWhen};
use args::{AnyArg, FlagBuilder};
use fmt::{ColorWhen, Colorizer, ColorizerOption};
use suggestions;
/// Short hand for [`Result`] type
@ -58,8 +58,8 @@ pub enum ErrorKind {
///
/// # Examples
///
#[cfg_attr(not(feature="suggestions"), doc=" ```no_run")]
#[cfg_attr( feature="suggestions" , doc=" ```")]
#[cfg_attr(not(feature = "suggestions"), doc = " ```no_run")]
#[cfg_attr(feature = "suggestions", doc = " ```")]
/// # use clap::{App, Arg, ErrorKind, SubCommand};
/// let result = App::new("prog")
/// .subcommand(SubCommand::with_name("config")
@ -300,8 +300,8 @@ pub enum ErrorKind {
///
/// # Examples
///
#[cfg_attr(not(unix), doc=" ```ignore")]
#[cfg_attr( unix , doc=" ```")]
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, Arg, ErrorKind, AppSettings};
/// # use std::os::unix::ffi::OsStringExt;
/// # use std::ffi::OsString;
@ -384,8 +384,7 @@ impl Error {
/// Should the message be written to `stdout` or not
pub fn use_stderr(&self) -> bool {
match self.kind {
ErrorKind::HelpDisplayed |
ErrorKind::VersionDisplayed => false,
ErrorKind::HelpDisplayed | ErrorKind::VersionDisplayed => false,
_ => true,
}
}
@ -405,14 +404,16 @@ impl Error {
pub fn write_to<W: Write>(&self, w: &mut W) -> io::Result<()> { write!(w, "{}", self.message) }
#[doc(hidden)]
pub fn argument_conflict<'a, 'b, A, O, U>(arg: &A,
other: Option<O>,
usage: U,
color: ColorWhen)
-> Self
where A: AnyArg<'a, 'b> + Display,
O: Into<String>,
U: Display
pub fn argument_conflict<'a, 'b, A, O, U>(
arg: &A,
other: Option<O>,
usage: U,
color: ColorWhen,
) -> Self
where
A: AnyArg<'a, 'b> + Display,
O: Into<String>,
U: Display,
{
let mut v = vec![arg.name().to_owned()];
let c = Colorizer::new(ColorizerOption {
@ -420,24 +421,23 @@ impl Error {
when: color,
});
Error {
message: format!("{} The argument '{}' cannot be used with {}\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(&*arg.to_string()),
match other {
Some(name) => {
let n = name.into();
v.push(n.clone());
c.warning(format!("'{}'", n))
}
None => {
c.none("one or more of the other specified arguments"
.to_owned())
}
},
usage,
c.good("--help")),
message: format!(
"{} The argument '{}' cannot be used with {}\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(&*arg.to_string()),
match other {
Some(name) => {
let n = name.into();
v.push(n.clone());
c.warning(format!("'{}'", n))
}
None => c.none("one or more of the other specified arguments".to_owned()),
},
usage,
c.good("--help")
),
kind: ErrorKind::ArgumentConflict,
info: Some(v),
}
@ -445,47 +445,49 @@ impl Error {
#[doc(hidden)]
pub fn empty_value<'a, 'b, A, U>(arg: &A, usage: U, color: ColorWhen) -> Self
where A: AnyArg<'a, 'b> + Display,
U: Display
where
A: AnyArg<'a, 'b> + Display,
U: Display,
{
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
when: color,
});
Error {
message: format!("{} The argument '{}' requires a value but none was supplied\
\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(arg.to_string()),
usage,
c.good("--help")),
message: format!(
"{} The argument '{}' requires a value but none was supplied\
\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(arg.to_string()),
usage,
c.good("--help")
),
kind: ErrorKind::EmptyValue,
info: Some(vec![arg.name().to_owned()]),
}
}
#[doc(hidden)]
pub fn invalid_value<'a, 'b, B, G, A, U>(bad_val: B,
good_vals: &[G],
arg: &A,
usage: U,
color: ColorWhen)
-> Self
where B: AsRef<str>,
G: AsRef<str> + Display,
A: AnyArg<'a, 'b> + Display,
U: Display
pub fn invalid_value<'a, 'b, B, G, A, U>(
bad_val: B,
good_vals: &[G],
arg: &A,
usage: U,
color: ColorWhen,
) -> Self
where
B: AsRef<str>,
G: AsRef<str> + Display,
A: AnyArg<'a, 'b> + Display,
U: Display,
{
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
when: color,
});
let suffix =
suggestions::did_you_mean_value_suffix(
bad_val.as_ref(),
good_vals.iter());
let suffix = suggestions::did_you_mean_value_suffix(bad_val.as_ref(), good_vals.iter());
let mut sorted = vec![];
for v in good_vals {
@ -495,34 +497,38 @@ impl Error {
sorted.sort();
let valid_values = sorted.join(", ");
Error {
message: format!("{} '{}' isn't a valid value for '{}'\n\t\
[values: {}]\n\
{}\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(bad_val.as_ref()),
c.warning(arg.to_string()),
valid_values,
suffix.0,
usage,
c.good("--help")),
message: format!(
"{} '{}' isn't a valid value for '{}'\n\t\
[values: {}]\n\
{}\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(bad_val.as_ref()),
c.warning(arg.to_string()),
valid_values,
suffix.0,
usage,
c.good("--help")
),
kind: ErrorKind::InvalidValue,
info: Some(vec![arg.name().to_owned(), bad_val.as_ref().to_owned()]),
}
}
#[doc(hidden)]
pub fn invalid_subcommand<S, D, N, U>(subcmd: S,
did_you_mean: D,
name: N,
usage: U,
color: ColorWhen)
-> Self
where S: Into<String>,
D: AsRef<str> + Display,
N: Display,
U: Display
pub fn invalid_subcommand<S, D, N, U>(
subcmd: S,
did_you_mean: D,
name: N,
usage: U,
color: ColorWhen,
) -> Self
where
S: Into<String>,
D: AsRef<str> + Display,
N: Display,
U: Display,
{
let s = subcmd.into();
let c = Colorizer::new(ColorizerOption {
@ -530,20 +536,22 @@ impl Error {
when: color,
});
Error {
message: format!("{} The subcommand '{}' wasn't recognized\n\t\
Did you mean '{}'?\n\n\
If you believe you received this message in error, try \
re-running with '{} {} {}'\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(&*s),
c.good(did_you_mean.as_ref()),
name,
c.good("--"),
&*s,
usage,
c.good("--help")),
message: format!(
"{} The subcommand '{}' wasn't recognized\n\t\
Did you mean '{}'?\n\n\
If you believe you received this message in error, try \
re-running with '{} {} {}'\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(&*s),
c.good(did_you_mean.as_ref()),
name,
c.good("--"),
&*s,
usage,
c.good("--help")
),
kind: ErrorKind::InvalidSubcommand,
info: Some(vec![s]),
}
@ -551,8 +559,9 @@ impl Error {
#[doc(hidden)]
pub fn unrecognized_subcommand<S, N>(subcmd: S, name: N, color: ColorWhen) -> Self
where S: Into<String>,
N: Display
where
S: Into<String>,
N: Display,
{
let s = subcmd.into();
let c = Colorizer::new(ColorizerOption {
@ -560,15 +569,17 @@ impl Error {
when: color,
});
Error {
message: format!("{} The subcommand '{}' wasn't recognized\n\n\
{}\n\t\
{} help <subcommands>...\n\n\
For more information try {}",
c.error("error:"),
c.warning(&*s),
c.warning("USAGE:"),
name,
c.good("--help")),
message: format!(
"{} The subcommand '{}' wasn't recognized\n\n\
{}\n\t\
{} help <subcommands>...\n\n\
For more information try {}",
c.error("error:"),
c.warning(&*s),
c.warning("USAGE:"),
name,
c.good("--help")
),
kind: ErrorKind::UnrecognizedSubcommand,
info: Some(vec![s]),
}
@ -576,21 +587,24 @@ impl Error {
#[doc(hidden)]
pub fn missing_required_argument<R, U>(required: R, usage: U, color: ColorWhen) -> Self
where R: Display,
U: Display
where
R: Display,
U: Display,
{
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
when: color,
});
Error {
message: format!("{} The following required arguments were not provided:{}\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
required,
usage,
c.good("--help")),
message: format!(
"{} The following required arguments were not provided:{}\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
required,
usage,
c.good("--help")
),
kind: ErrorKind::MissingRequiredArgument,
info: None,
}
@ -598,21 +612,24 @@ impl Error {
#[doc(hidden)]
pub fn missing_subcommand<N, U>(name: N, usage: U, color: ColorWhen) -> Self
where N: AsRef<str> + Display,
U: Display
where
N: AsRef<str> + Display,
U: Display,
{
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
when: color,
});
Error {
message: format!("{} '{}' requires a subcommand, but one was not provided\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(name),
usage,
c.good("--help")),
message: format!(
"{} '{}' requires a subcommand, but one was not provided\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(name),
usage,
c.good("--help")
),
kind: ErrorKind::MissingSubcommand,
info: None,
}
@ -621,33 +638,33 @@ impl Error {
#[doc(hidden)]
pub fn invalid_utf8<U>(usage: U, color: ColorWhen) -> Self
where U: Display
where
U: Display,
{
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
when: color,
});
Error {
message: format!("{} Invalid UTF-8 was detected in one or more arguments\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
usage,
c.good("--help")),
message: format!(
"{} Invalid UTF-8 was detected in one or more arguments\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
usage,
c.good("--help")
),
kind: ErrorKind::InvalidUtf8,
info: None,
}
}
#[doc(hidden)]
pub fn too_many_values<'a, 'b, V, A, U>(val: V,
arg: &A,
usage: U,
color: ColorWhen)
-> Self
where V: AsRef<str> + Display + ToOwned,
A: AnyArg<'a, 'b> + Display,
U: Display
pub fn too_many_values<'a, 'b, V, A, U>(val: V, arg: &A, usage: U, color: ColorWhen) -> Self
where
V: AsRef<str> + Display + ToOwned,
A: AnyArg<'a, 'b> + Display,
U: Display,
{
let v = val.as_ref();
let c = Colorizer::new(ColorizerOption {
@ -655,46 +672,52 @@ impl Error {
when: color,
});
Error {
message: format!("{} The value '{}' was provided to '{}', but it wasn't expecting \
any more values\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(v),
c.warning(arg.to_string()),
usage,
c.good("--help")),
message: format!(
"{} The value '{}' was provided to '{}', but it wasn't expecting \
any more values\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(v),
c.warning(arg.to_string()),
usage,
c.good("--help")
),
kind: ErrorKind::TooManyValues,
info: Some(vec![arg.name().to_owned(), v.to_owned()]),
}
}
#[doc(hidden)]
pub fn too_few_values<'a, 'b, A, U>(arg: &A,
min_vals: u64,
curr_vals: usize,
usage: U,
color: ColorWhen)
-> Self
where A: AnyArg<'a, 'b> + Display,
U: Display
pub fn too_few_values<'a, 'b, A, U>(
arg: &A,
min_vals: u64,
curr_vals: usize,
usage: U,
color: ColorWhen,
) -> Self
where
A: AnyArg<'a, 'b> + Display,
U: Display,
{
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
when: color,
});
Error {
message: format!("{} The argument '{}' requires at least {} values, but only {} w{} \
provided\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(arg.to_string()),
c.warning(min_vals.to_string()),
c.warning(curr_vals.to_string()),
if curr_vals > 1 { "ere" } else { "as" },
usage,
c.good("--help")),
message: format!(
"{} The argument '{}' requires at least {} values, but only {} w{} \
provided\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(arg.to_string()),
c.warning(min_vals.to_string()),
c.warning(curr_vals.to_string()),
if curr_vals > 1 { "ere" } else { "as" },
usage,
c.good("--help")
),
kind: ErrorKind::TooFewValues,
info: Some(vec![arg.name().to_owned()]),
}
@ -702,21 +725,24 @@ impl Error {
#[doc(hidden)]
pub fn value_validation<'a, 'b, A>(arg: Option<&A>, err: String, color: ColorWhen) -> Self
where A: AnyArg<'a, 'b> + Display
where
A: AnyArg<'a, 'b> + Display,
{
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
when: color,
});
Error {
message: format!("{} Invalid value{}: {}",
c.error("error:"),
if let Some(a) = arg {
format!(" for '{}'", c.warning(a.to_string()))
} else {
"".to_string()
},
err),
message: format!(
"{} Invalid value{}: {}",
c.error("error:"),
if let Some(a) = arg {
format!(" for '{}'", c.warning(a.to_string()))
} else {
"".to_string()
},
err
),
kind: ErrorKind::ValueValidation,
info: None,
}
@ -724,38 +750,42 @@ impl Error {
#[doc(hidden)]
pub fn value_validation_auto(err: String) -> Self {
let n: Option<&FlagBuilder> = None;
let n: Option<&FlagBuilder> = None;
Error::value_validation(n, err, ColorWhen::Auto)
}
#[doc(hidden)]
pub fn wrong_number_of_values<'a, 'b, A, S, U>(arg: &A,
num_vals: u64,
curr_vals: usize,
suffix: S,
usage: U,
color: ColorWhen)
-> Self
where A: AnyArg<'a, 'b> + Display,
S: Display,
U: Display
pub fn wrong_number_of_values<'a, 'b, A, S, U>(
arg: &A,
num_vals: u64,
curr_vals: usize,
suffix: S,
usage: U,
color: ColorWhen,
) -> Self
where
A: AnyArg<'a, 'b> + Display,
S: Display,
U: Display,
{
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
when: color,
});
Error {
message: format!("{} The argument '{}' requires {} values, but {} w{} \
provided\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(arg.to_string()),
c.warning(num_vals.to_string()),
c.warning(curr_vals.to_string()),
suffix,
usage,
c.good("--help")),
message: format!(
"{} The argument '{}' requires {} values, but {} w{} \
provided\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(arg.to_string()),
c.warning(num_vals.to_string()),
c.warning(curr_vals.to_string()),
suffix,
usage,
c.good("--help")
),
kind: ErrorKind::WrongNumberOfValues,
info: Some(vec![arg.name().to_owned()]),
}
@ -763,35 +793,35 @@ impl Error {
#[doc(hidden)]
pub fn unexpected_multiple_usage<'a, 'b, A, U>(arg: &A, usage: U, color: ColorWhen) -> Self
where A: AnyArg<'a, 'b> + Display,
U: Display
where
A: AnyArg<'a, 'b> + Display,
U: Display,
{
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
when: color,
});
Error {
message: format!("{} The argument '{}' was provided more than once, but cannot \
be used multiple times\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(arg.to_string()),
usage,
c.good("--help")),
message: format!(
"{} The argument '{}' was provided more than once, but cannot \
be used multiple times\n\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(arg.to_string()),
usage,
c.good("--help")
),
kind: ErrorKind::UnexpectedMultipleUsage,
info: Some(vec![arg.name().to_owned()]),
}
}
#[doc(hidden)]
pub fn unknown_argument<A, U>(arg: A,
did_you_mean: &str,
usage: U,
color: ColorWhen)
-> Self
where A: Into<String>,
U: Display
pub fn unknown_argument<A, U>(arg: A, did_you_mean: &str, usage: U, color: ColorWhen) -> Self
where
A: Into<String>,
U: Display,
{
let a = arg.into();
let c = Colorizer::new(ColorizerOption {
@ -799,19 +829,21 @@ impl Error {
when: color,
});
Error {
message: format!("{} Found argument '{}' which wasn't expected, or isn't valid in \
this context{}\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(&*a),
if did_you_mean.is_empty() {
"\n".to_owned()
} else {
format!("{}\n", did_you_mean)
},
usage,
c.good("--help")),
message: format!(
"{} Found argument '{}' which wasn't expected, or isn't valid in \
this context{}\n\
{}\n\n\
For more information try {}",
c.error("error:"),
c.warning(&*a),
if did_you_mean.is_empty() {
"\n".to_owned()
} else {
format!("{}\n", did_you_mean)
},
usage,
c.good("--help")
),
kind: ErrorKind::UnknownArgument,
info: Some(vec![a]),
}
@ -832,7 +864,8 @@ impl Error {
#[doc(hidden)]
pub fn argument_not_found_auto<A>(arg: A) -> Self
where A: Into<String>
where
A: Into<String>,
{
let a = arg.into();
let c = Colorizer::new(ColorizerOption {
@ -840,9 +873,11 @@ impl Error {
when: ColorWhen::Auto,
});
Error {
message: format!("{} The argument '{}' wasn't found",
c.error("error:"),
a.clone()),
message: format!(
"{} The argument '{}' wasn't found",
c.error("error:"),
a.clone()
),
kind: ErrorKind::ArgumentNotFound,
info: Some(vec![a]),
}

View file

@ -71,28 +71,32 @@ impl Colorizer {
}
pub fn good<T>(&self, msg: T) -> Format<T>
where T: fmt::Display + AsRef<str>
where
T: fmt::Display + AsRef<str>,
{
debugln!("Colorizer::good;");
color!(self, Good, msg)
}
pub fn warning<T>(&self, msg: T) -> Format<T>
where T: fmt::Display + AsRef<str>
where
T: fmt::Display + AsRef<str>,
{
debugln!("Colorizer::warning;");
color!(self, Warning, msg)
}
pub fn error<T>(&self, msg: T) -> Format<T>
where T: fmt::Display + AsRef<str>
where
T: fmt::Display + AsRef<str>,
{
debugln!("Colorizer::error;");
color!(self, Error, msg)
}
pub fn none<T>(&self, msg: T) -> Format<T>
where T: fmt::Display + AsRef<str>
where
T: fmt::Display + AsRef<str>,
{
debugln!("Colorizer::none;");
Format::None(msg)
@ -136,7 +140,7 @@ impl<T: AsRef<str>> Format<T> {
}
#[cfg(any(not(feature = "color"), target_os = "windows"))]
#[cfg_attr(feature="lints", allow(match_same_arms))]
#[cfg_attr(feature = "lints", allow(match_same_arms))]
impl<T: fmt::Display> Format<T> {
fn format(&self) -> &T {
match *self {
@ -168,14 +172,18 @@ mod test {
#[test]
fn colored_output() {
let err = Format::Error("error");
assert_eq!(&*format!("{}", err),
&*format!("{}", Red.bold().paint("error")));
assert_eq!(
&*format!("{}", err),
&*format!("{}", Red.bold().paint("error"))
);
let good = Format::Good("good");
assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good")));
let warn = Format::Warning("warn");
assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn")));
let none = Format::None("none");
assert_eq!(&*format!("{}", none),
&*format!("{}", ANSIString::from("none")));
assert_eq!(
&*format!("{}", none),
&*format!("{}", ANSIString::from("none"))
);
}
}

View file

@ -512,15 +512,10 @@
//! `clap` is licensed under the MIT license. Please read the [LICENSE-MIT](LICENSE-MIT) file in
//! this repository for more information.
#![crate_type= "lib"]
#![crate_type = "lib"]
#![doc(html_root_url = "https://docs.rs/clap/2.28.0")]
#![deny(
missing_docs,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
unused_import_braces,
unused_allocation)]
#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
unused_import_braces, unused_allocation)]
// Lints we'd like to deny but are currently failing for upstream crates
// unused_qualifications (bitflags, clippy)
// trivial_numeric_casts (bitflags)
@ -533,26 +528,26 @@
#![cfg_attr(feature = "lints", allow(doc_markdown))]
#![cfg_attr(feature = "lints", allow(explicit_iter_loop))]
#[cfg(feature = "suggestions")]
extern crate strsim;
#[cfg(feature = "color")]
extern crate ansi_term;
#[cfg(feature = "yaml")]
extern crate yaml_rust;
extern crate unicode_width;
#[cfg(feature = "color")]
extern crate atty;
#[macro_use]
extern crate bitflags;
#[cfg(feature = "vec_map")]
extern crate vec_map;
#[cfg(feature = "suggestions")]
extern crate strsim;
#[cfg(feature = "wrap_help")]
extern crate term_size;
extern crate textwrap;
#[cfg(feature = "color")]
extern crate atty;
extern crate unicode_width;
#[cfg(feature = "vec_map")]
extern crate vec_map;
#[cfg(feature = "yaml")]
extern crate yaml_rust;
#[cfg(feature = "yaml")]
pub use yaml_rust::YamlLoader;
pub use args::{Arg, ArgGroup, ArgMatches, ArgSettings, SubCommand, Values, OsValues};
pub use args::{Arg, ArgGroup, ArgMatches, ArgSettings, OsValues, SubCommand, Values};
pub use app::{App, AppSettings};
pub use fmt::Format;
pub use errors::{Error, ErrorKind, Result};
@ -576,22 +571,20 @@ const INTERNAL_ERROR_MSG: &'static str = "Fatal internal error. Please consider
const INVALID_UTF8: &'static str = "unexpected invalid UTF-8 code point";
#[cfg(unstable)]
pub use derive::{ArgEnum, ClapApp, IntoApp, FromArgMatches};
pub use derive::{ArgEnum, ClapApp, FromArgMatches, IntoApp};
#[cfg(unstable)]
mod derive {
/// @TODO @release @docs
pub trait ClapApp: IntoApp + FromArgMatches + Sized {
/// @TODO @release @docs
fn parse() -> Self {
Self::from_argmatches(Self::into_app().get_matches())
}
fn parse() -> Self { Self::from_argmatches(Self::into_app().get_matches()) }
/// @TODO @release @docs
fn parse_from<I, T>(argv: I) -> Self
where I: IntoIterator<Item = T>,
T: Into<OsString> + Clone
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
Self::from_argmatches(Self::into_app().get_matches_from(argv))
}
@ -604,8 +597,9 @@ mod derive {
/// @TODO @release @docs
fn try_parse_from<I, T>(argv: I) -> Result<Self, clap::Error>
where I: IntoIterator<Item = T>,
T: Into<OsString> + Clone
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
Self::try_from_argmatches(Self::into_app().get_matches_from_safe(argv)?)
}
@ -627,5 +621,5 @@ mod derive {
}
/// @TODO @release @docs
pub trait ArgEnum { }
pub trait ArgEnum {}
}

View file

@ -262,7 +262,8 @@ macro_rules! _clap_count_exprs {
/// retrieve a `Vec<&'static str>` of the variant names, as well as implementing [`FromStr`] and
/// [`Display`] automatically.
///
/// **NOTE:** Case insensitivity is supported for ASCII characters only
/// **NOTE:** Case insensitivity is supported for ASCII characters only. It's highly recommended to
/// use [`Arg::case_insensitive(true)`] for args that will be used with these enums
///
/// **NOTE:** This macro automatically implements [`std::str::FromStr`] and [`std::fmt::Display`]
///
@ -270,12 +271,12 @@ macro_rules! _clap_count_exprs {
///
/// # Examples
///
/// ```no_run
/// ```rust
/// # #[macro_use]
/// # extern crate clap;
/// # use clap::{App, Arg};
/// arg_enum!{
/// #[derive(Debug)]
/// #[derive(PartialEq, Debug)]
/// pub enum Foo {
/// Bar,
/// Baz,
@ -286,17 +287,22 @@ macro_rules! _clap_count_exprs {
/// // and implements std::str::FromStr to use with the value_t! macros
/// fn main() {
/// let m = App::new("app")
/// .arg_from_usage("<foo> 'the foo'")
/// .get_matches();
/// .arg(Arg::from_usage("<foo> 'the foo'")
/// .possible_values(&Foo::variants())
/// .case_insensitive(true))
/// .get_matches_from(vec![
/// "app", "baz"
/// ]);
/// let f = value_t!(m, "foo", Foo).unwrap_or_else(|e| e.exit());
///
/// // Use f like any other Foo variant...
/// assert_eq!(f, Foo::Baz);
/// }
/// ```
/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
/// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
/// [`std::fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
/// [`Arg::case_insensitive(true)`]: ./struct.Arg.html#method.case_insensitive
#[macro_export]
macro_rules! arg_enum {
(@as_item $($i:item)*) => ($($i)*);
@ -386,7 +392,7 @@ macro_rules! arg_enum {
/// .get_matches();
/// # }
/// ```
#[cfg(not(feature="no_cargo"))]
#[cfg(not(feature = "no_cargo"))]
#[macro_export]
macro_rules! crate_version {
() => {
@ -415,7 +421,7 @@ macro_rules! crate_version {
/// .get_matches();
/// # }
/// ```
#[cfg(not(feature="no_cargo"))]
#[cfg(not(feature = "no_cargo"))]
#[macro_export]
macro_rules! crate_authors {
($sep:expr) => {{
@ -466,7 +472,7 @@ macro_rules! crate_authors {
/// .get_matches();
/// # }
/// ```
#[cfg(not(feature="no_cargo"))]
#[cfg(not(feature = "no_cargo"))]
#[macro_export]
macro_rules! crate_description {
() => {
@ -487,7 +493,7 @@ macro_rules! crate_description {
/// .get_matches();
/// # }
/// ```
#[cfg(not(feature="no_cargo"))]
#[cfg(not(feature = "no_cargo"))]
#[macro_export]
macro_rules! crate_name {
() => {
@ -518,7 +524,7 @@ macro_rules! crate_name {
/// let m = app_from_crate!().get_matches();
/// # }
/// ```
#[cfg(not(feature="no_cargo"))]
#[cfg(not(feature = "no_cargo"))]
#[macro_export]
macro_rules! app_from_crate {
() => {

View file

@ -1,8 +1,8 @@
#[cfg(feature = "vec_map")]
pub use vec_map::{VecMap, Values};
pub use vec_map::{Values, VecMap};
#[cfg(not(feature = "vec_map"))]
pub use self::vec_map::{VecMap, Values};
pub use self::vec_map::{Values, VecMap};
#[cfg(not(feature = "vec_map"))]
mod vec_map {
@ -17,40 +17,32 @@ mod vec_map {
impl<V> VecMap<V> {
pub fn new() -> Self {
VecMap { inner: Default::default() }
VecMap {
inner: Default::default(),
}
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn len(&self) -> usize { self.inner.len() }
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn is_empty(&self) -> bool { self.inner.is_empty() }
pub fn insert(&mut self, key: usize, value: V) -> Option<V> {
self.inner.insert(key, value)
}
pub fn values(&self) -> Values<V> {
self.inner.values()
}
pub fn values(&self) -> Values<V> { self.inner.values() }
pub fn iter(&self) -> Iter<V> {
Iter { inner: self.inner.iter() }
Iter {
inner: self.inner.iter(),
}
}
pub fn contains_key(&self, key: usize) -> bool {
self.inner.contains_key(&key)
}
pub fn contains_key(&self, key: usize) -> bool { self.inner.contains_key(&key) }
pub fn entry(&mut self, key: usize) -> Entry<V> {
self.inner.entry(key)
}
pub fn entry(&mut self, key: usize) -> Entry<V> { self.inner.entry(key) }
pub fn get(&self, key: usize) -> Option<&V> {
self.inner.get(&key)
}
pub fn get(&self, key: usize) -> Option<&V> { self.inner.get(&key) }
}
pub type Values<'a, V> = btree_map::Values<'a, usize, V>;
@ -71,9 +63,7 @@ mod vec_map {
impl<'a, V: 'a> Iterator for Iter<'a, V> {
type Item = (usize, &'a V);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(k, v)| (*k, v))
}
fn next(&mut self) -> Option<Self::Item> { self.inner.next().map(|(k, v)| (*k, v)) }
}
impl<'a, V: 'a> DoubleEndedIterator for Iter<'a, V> {

View file

@ -48,11 +48,16 @@ impl OsStrExt2 for OsStr {
fn split_at_byte(&self, byte: u8) -> (&OsStr, &OsStr) {
for (i, b) in self.as_bytes().iter().enumerate() {
if b == &byte {
return (OsStr::from_bytes(&self.as_bytes()[..i]),
OsStr::from_bytes(&self.as_bytes()[i + 1..]));
return (
OsStr::from_bytes(&self.as_bytes()[..i]),
OsStr::from_bytes(&self.as_bytes()[i + 1..]),
);
}
}
(&*self, OsStr::from_bytes(&self.as_bytes()[self.len_()..self.len_()]))
(
&*self,
OsStr::from_bytes(&self.as_bytes()[self.len_()..self.len_()]),
)
}
fn trim_left_matches(&self, byte: u8) -> &OsStr {
@ -71,7 +76,10 @@ impl OsStrExt2 for OsStr {
}
fn split_at(&self, i: usize) -> (&OsStr, &OsStr) {
(OsStr::from_bytes(&self.as_bytes()[..i]), OsStr::from_bytes(&self.as_bytes()[i..]))
(
OsStr::from_bytes(&self.as_bytes()[..i]),
OsStr::from_bytes(&self.as_bytes()[i..]),
)
}
fn len_(&self) -> usize { self.as_bytes().len() }

View file

@ -13,15 +13,15 @@ use fmt::Format;
#[cfg(feature = "suggestions")]
#[cfg_attr(feature = "lints", allow(needless_lifetimes))]
pub fn did_you_mean<'a, T: ?Sized, I>(v: &str, possible_values: I) -> Option<&'a str>
where T: AsRef<str> + 'a,
I: IntoIterator<Item = &'a T>
where
T: AsRef<str> + 'a,
I: IntoIterator<Item = &'a T>,
{
let mut candidate: Option<(f64, &str)> = None;
for pv in possible_values {
let confidence = strsim::jaro_winkler(v, pv.as_ref());
if confidence > 0.8 &&
(candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence)) {
if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence))
{
candidate = Some((confidence, pv.as_ref()));
}
}
@ -33,47 +33,60 @@ pub fn did_you_mean<'a, T: ?Sized, I>(v: &str, possible_values: I) -> Option<&'a
#[cfg(not(feature = "suggestions"))]
pub fn did_you_mean<'a, T: ?Sized, I>(_: &str, _: I) -> Option<&'a str>
where T: AsRef<str> + 'a,
I: IntoIterator<Item = &'a T>
where
T: AsRef<str> + 'a,
I: IntoIterator<Item = &'a T>,
{
None
}
/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
#[cfg_attr(feature = "lints", allow(needless_lifetimes))]
pub fn did_you_mean_flag_suffix<'z, T, I>(arg: &str, longs: I, subcommands: &'z [App])
-> (String, Option<&'z str>)
where T: AsRef<str> + 'z,
I: IntoIterator<Item = &'z T>
pub fn did_you_mean_flag_suffix<'z, T, I>(
arg: &str,
longs: I,
subcommands: &'z [App],
) -> (String, Option<&'z str>)
where
T: AsRef<str> + 'z,
I: IntoIterator<Item = &'z T>,
{
match did_you_mean(arg, longs) {
Some(candidate) => {
let suffix = format!("\n\tDid you mean {}{}?", Format::Good("--"), Format::Good(candidate));
return (suffix, Some(candidate))
let suffix = format!(
"\n\tDid you mean {}{}?",
Format::Good("--"),
Format::Good(candidate)
);
return (suffix, Some(candidate));
}
None => {
for subcommand in subcommands {
let opts = subcommand.p.flags.iter().filter_map(|f| f.s.long).chain(
subcommand.p.opts.iter().filter_map(|o| o.s.long));
None => for subcommand in subcommands {
let opts = subcommand
.p
.flags
.iter()
.filter_map(|f| f.s.long)
.chain(subcommand.p.opts.iter().filter_map(|o| o.s.long));
if let Some(candidate) = did_you_mean(arg, opts) {
let suffix = format!(
"\n\tDid you mean to put '{}{}' after the subcommand '{}'?",
Format::Good("--"),
Format::Good(candidate),
Format::Good(subcommand.get_name()));
return (suffix, Some(candidate));
}
if let Some(candidate) = did_you_mean(arg, opts) {
let suffix = format!(
"\n\tDid you mean to put '{}{}' after the subcommand '{}'?",
Format::Good("--"),
Format::Good(candidate),
Format::Good(subcommand.get_name())
);
return (suffix, Some(candidate));
}
}
},
}
(String::new(), None)
}
/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
pub fn did_you_mean_value_suffix<'z, T, I>(arg: &str, values: I) -> (String, Option<&'z str>)
where T: AsRef<str> + 'z,
I: IntoIterator<Item = &'z T>
where
T: AsRef<str> + 'z,
I: IntoIterator<Item = &'z T>,
{
match did_you_mean(arg, values) {
Some(candidate) => {
@ -104,13 +117,19 @@ mod test {
fn suffix_long() {
let p_vals = ["test", "possible", "values"];
let suffix = "\n\tDid you mean \'--test\'?";
assert_eq!(did_you_mean_flag_suffix("tst", p_vals.iter(), []), (suffix, Some("test")));
assert_eq!(
did_you_mean_flag_suffix("tst", p_vals.iter(), []),
(suffix, Some("test"))
);
}
#[test]
fn suffix_enum() {
let p_vals = ["test", "possible", "values"];
let suffix = "\n\tDid you mean \'test\'?";
assert_eq!(did_you_mean_value_suffix("tst", p_vals.iter()), (suffix, Some("test")));
assert_eq!(
did_you_mean_value_suffix("tst", p_vals.iter()),
(suffix, Some("test"))
);
}
}

View file

@ -1,4 +1,3 @@
// Internal
use INTERNAL_ERROR_MSG;
use args::Arg;
@ -60,9 +59,13 @@ impl<'a> UsageParser<'a> {
break;
}
}
debug_assert!(!arg.b.name.is_empty(),
format!("No name found for Arg when parsing usage string: {}",
self.usage));
debug_assert!(
!arg.b.name.is_empty(),
format!(
"No name found for Arg when parsing usage string: {}",
self.usage
)
);
arg.v.num_vals = match arg.v.val_names {
Some(ref v) if v.len() >= 2 => Some(v.len() as u64),
_ => None,
@ -73,8 +76,11 @@ impl<'a> UsageParser<'a> {
fn name(&mut self, arg: &mut Arg<'a, 'a>) {
debugln!("UsageParser::name;");
if *self.usage.as_bytes().get(self.pos).expect(INTERNAL_ERROR_MSG) == b'<' &&
!self.explicit_name_set {
if *self.usage
.as_bytes()
.get(self.pos)
.expect(INTERNAL_ERROR_MSG) == b'<' && !self.explicit_name_set
{
arg.setb(ArgSettings::Required);
}
self.pos += 1;
@ -104,17 +110,25 @@ impl<'a> UsageParser<'a> {
}
fn stop_at<F>(&mut self, f: F)
where F: Fn(u8) -> bool
where
F: Fn(u8) -> bool,
{
debugln!("UsageParser::stop_at;");
self.start = self.pos;
self.pos += self.usage[self.start..].bytes().take_while(|&b| f(b)).count();
self.pos += self.usage[self.start..]
.bytes()
.take_while(|&b| f(b))
.count();
}
fn short_or_long(&mut self, arg: &mut Arg<'a, 'a>) {
debugln!("UsageParser::short_or_long;");
self.pos += 1;
if *self.usage.as_bytes().get(self.pos).expect(INTERNAL_ERROR_MSG) == b'-' {
if *self.usage
.as_bytes()
.get(self.pos)
.expect(INTERNAL_ERROR_MSG) == b'-'
{
self.pos += 1;
self.long(arg);
return;
@ -181,9 +195,12 @@ impl<'a> UsageParser<'a> {
self.stop_at(help_start);
self.start = self.pos + 1;
self.pos = self.usage.len() - 1;
debugln!("UsageParser::help: setting help...{}", &self.usage[self.start..self.pos]);
debugln!(
"UsageParser::help: setting help...{}",
&self.usage[self.start..self.pos]
);
arg.b.help = Some(&self.usage[self.start..self.pos]);
self.pos += 1; // Move to next byte to keep from thinking ending ' is a start
self.pos += 1; // Move to next byte to keep from thinking ending ' is a start
self.prev = UsageToken::Help;
}
}
@ -332,7 +349,10 @@ mod test {
assert!(!a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(a.v.num_vals.is_none());
}
@ -346,7 +366,10 @@ mod test {
assert!(!b.is_set(ArgSettings::Multiple));
assert!(b.is_set(ArgSettings::TakesValue));
assert!(!b.is_set(ArgSettings::Required));
assert_eq!(b.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(b.v.num_vals.is_none());
}
@ -360,7 +383,10 @@ mod test {
assert!(!c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -374,7 +400,10 @@ mod test {
assert!(!d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(d.v.num_vals.is_none());
}
@ -388,7 +417,10 @@ mod test {
assert!(a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(a.v.num_vals.is_none());
}
@ -402,7 +434,10 @@ mod test {
assert!(a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(a.v.num_vals.is_none());
}
@ -416,7 +451,10 @@ mod test {
assert!(b.is_set(ArgSettings::Multiple));
assert!(b.is_set(ArgSettings::TakesValue));
assert!(!b.is_set(ArgSettings::Required));
assert_eq!(b.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(b.v.num_vals.is_none());
}
@ -430,7 +468,10 @@ mod test {
assert!(c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -444,7 +485,10 @@ mod test {
assert!(c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -458,7 +502,10 @@ mod test {
assert!(d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(d.v.num_vals.is_none());
}
@ -472,7 +519,10 @@ mod test {
assert!(!a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(a.v.num_vals.is_none());
}
@ -486,8 +536,10 @@ mod test {
assert!(!b.is_set(ArgSettings::Multiple));
assert!(b.is_set(ArgSettings::TakesValue));
assert!(!b.is_set(ArgSettings::Required));
assert_eq!(b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(b.v.num_vals.is_none());
}
@ -501,7 +553,10 @@ mod test {
assert!(!c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -515,8 +570,10 @@ mod test {
assert!(!d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(d.v.num_vals.is_none());
}
@ -530,7 +587,10 @@ mod test {
assert!(a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(a.v.num_vals.is_none());
}
@ -544,7 +604,10 @@ mod test {
assert!(a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(a.v.num_vals.is_none());
}
@ -558,8 +621,10 @@ mod test {
assert!(b.is_set(ArgSettings::Multiple));
assert!(b.is_set(ArgSettings::TakesValue));
assert!(!b.is_set(ArgSettings::Required));
assert_eq!(b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(b.v.num_vals.is_none());
}
@ -573,7 +638,10 @@ mod test {
assert!(c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -587,7 +655,10 @@ mod test {
assert!(c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -601,8 +672,10 @@ mod test {
assert!(d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(d.v.num_vals.is_none());
}
@ -616,7 +689,10 @@ mod test {
assert!(!a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(a.v.num_vals.is_none());
}
@ -630,8 +706,10 @@ mod test {
assert!(!b.is_set(ArgSettings::Multiple));
assert!(b.is_set(ArgSettings::TakesValue));
assert!(!b.is_set(ArgSettings::Required));
assert_eq!(b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(b.v.num_vals.is_none());
}
@ -645,7 +723,10 @@ mod test {
assert!(!c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -659,8 +740,10 @@ mod test {
assert!(!d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(d.v.num_vals.is_none());
}
@ -674,7 +757,10 @@ mod test {
assert!(a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(a.v.num_vals.is_none());
}
@ -688,7 +774,10 @@ mod test {
assert!(a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(a.v.num_vals.is_none());
}
@ -702,8 +791,10 @@ mod test {
assert!(b.is_set(ArgSettings::Multiple));
assert!(b.is_set(ArgSettings::TakesValue));
assert!(!b.is_set(ArgSettings::Required));
assert_eq!(b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(b.v.num_vals.is_none());
}
@ -717,7 +808,10 @@ mod test {
assert!(c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -731,7 +825,10 @@ mod test {
assert!(c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -745,8 +842,10 @@ mod test {
assert!(d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(d.v.num_vals.is_none());
}
@ -760,8 +859,10 @@ mod test {
assert!(!a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(a.v.num_vals.is_none());
}
@ -775,8 +876,10 @@ mod test {
assert!(!b.is_set(ArgSettings::Multiple));
assert!(b.is_set(ArgSettings::TakesValue));
assert!(!b.is_set(ArgSettings::Required));
assert_eq!(b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(b.v.num_vals.is_none());
}
@ -790,7 +893,10 @@ mod test {
assert!(!c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -804,8 +910,10 @@ mod test {
assert!(!d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(d.v.num_vals.is_none());
}
@ -819,8 +927,10 @@ mod test {
assert!(a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(a.v.num_vals.is_none());
}
@ -834,8 +944,10 @@ mod test {
assert!(b.is_set(ArgSettings::Multiple));
assert!(b.is_set(ArgSettings::TakesValue));
assert!(!b.is_set(ArgSettings::Required));
assert_eq!(b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(b.v.num_vals.is_none());
}
@ -849,7 +961,10 @@ mod test {
assert!(c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -863,8 +978,10 @@ mod test {
assert!(d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(d.v.num_vals.is_none());
}
@ -878,8 +995,10 @@ mod test {
assert!(!a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(a.v.num_vals.is_none());
}
@ -893,8 +1012,10 @@ mod test {
assert!(!b.is_set(ArgSettings::Multiple));
assert!(b.is_set(ArgSettings::TakesValue));
assert!(!b.is_set(ArgSettings::Required));
assert_eq!(b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(b.v.num_vals.is_none());
}
@ -908,7 +1029,10 @@ mod test {
assert!(!c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -922,8 +1046,10 @@ mod test {
assert!(!d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(d.v.num_vals.is_none());
}
@ -937,8 +1063,10 @@ mod test {
assert!(a.is_set(ArgSettings::Multiple));
assert!(a.is_set(ArgSettings::TakesValue));
assert!(!a.is_set(ArgSettings::Required));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(a.v.num_vals.is_none());
}
@ -952,8 +1080,10 @@ mod test {
assert!(b.is_set(ArgSettings::Multiple));
assert!(b.is_set(ArgSettings::TakesValue));
assert!(!b.is_set(ArgSettings::Required));
assert_eq!(b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
b.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(b.v.num_vals.is_none());
}
@ -967,7 +1097,10 @@ mod test {
assert!(c.is_set(ArgSettings::Multiple));
assert!(c.is_set(ArgSettings::TakesValue));
assert!(c.is_set(ArgSettings::Required));
assert_eq!(c.v.val_names.unwrap().values().collect::<Vec<_>>(), [&"opt"]);
assert_eq!(
c.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"opt"]
);
assert!(c.v.num_vals.is_none());
}
@ -981,8 +1114,10 @@ mod test {
assert!(d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"option"]
);
assert!(d.v.num_vals.is_none());
}
@ -996,8 +1131,10 @@ mod test {
assert!(!d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"file", &"mode"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"file", &"mode"]
);
assert_eq!(d.v.num_vals.unwrap(), 2);
}
@ -1011,8 +1148,10 @@ mod test {
assert!(d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"file", &"mode"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"file", &"mode"]
);
assert_eq!(d.v.num_vals.unwrap(), 2);
}
@ -1026,8 +1165,10 @@ mod test {
assert!(d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"file", &"mode"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"file", &"mode"]
);
assert_eq!(d.v.num_vals.unwrap(), 2);
}
@ -1041,8 +1182,10 @@ mod test {
assert!(!d.is_set(ArgSettings::Multiple));
assert!(d.is_set(ArgSettings::TakesValue));
assert!(!d.is_set(ArgSettings::Required));
assert_eq!(d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"file", &"mode"]);
assert_eq!(
d.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"file", &"mode"]
);
assert_eq!(d.v.num_vals.unwrap(), 2);
}
@ -1116,8 +1259,10 @@ mod test {
#[test]
fn pos_help_newline() {
let c = Arg::from_usage("[pos]... 'some help{n}\
info'");
let c = Arg::from_usage(
"[pos]... 'some help{n}\
info'",
);
assert_eq!(c.b.name, "pos");
assert_eq!(c.b.help.unwrap(), "some help{n}info");
assert!(c.is_set(ArgSettings::Multiple));
@ -1128,8 +1273,10 @@ mod test {
#[test]
fn pos_help_newline_lit_sq() {
let c = Arg::from_usage("[pos]... 'some help\' stuff{n}\
info'");
let c = Arg::from_usage(
"[pos]... 'some help\' stuff{n}\
info'",
);
assert_eq!(c.b.name, "pos");
assert_eq!(c.b.help.unwrap(), "some help' stuff{n}info");
assert!(c.is_set(ArgSettings::Multiple));
@ -1191,8 +1338,10 @@ mod test {
let a = Arg::from_usage("[ñämê] --ôpt=[üñíčöĐ€] 'hælp'");
assert_eq!(a.b.name, "ñämê");
assert_eq!(a.s.long, Some("ôpt"));
assert_eq!(a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"üñíčöĐ€"]);
assert_eq!(
a.v.val_names.unwrap().values().collect::<Vec<_>>(),
[&"üñíčöĐ€"]
);
assert_eq!(a.b.help, Some("hælp"));
}
}

View file

@ -3,9 +3,12 @@ extern crate regex;
include!("../clap-test.rs");
#[allow(unsused_imports)]
use std::ascii::AsciiExt;
use clap::{App, Arg, ErrorKind};
#[cfg(feature="suggestions")]
#[cfg(feature = "suggestions")]
static PV_ERROR: &'static str = "error: 'slo' isn't a valid value for '--Option <option3>'
\t[values: fast, slow]
@ -16,7 +19,7 @@ USAGE:
For more information try --help";
#[cfg(not(feature="suggestions"))]
#[cfg(not(feature = "suggestions"))]
static PV_ERROR: &'static str = "error: 'slo' isn't a valid value for '--Option <option3>'
\t[values: fast, slow]
@ -29,9 +32,11 @@ For more information try --help";
#[test]
fn possible_values_of_positional() {
let m = App::new("possible_values")
.arg(Arg::with_name("positional")
.index(1)
.possible_value("test123"))
.arg(
Arg::with_name("positional")
.index(1)
.possible_value("test123"),
)
.get_matches_from_safe(vec!["myprog", "test123"]);
assert!(m.is_ok());
@ -44,9 +49,11 @@ fn possible_values_of_positional() {
#[test]
fn possible_values_of_positional_fail() {
let m = App::new("possible_values")
.arg(Arg::with_name("positional")
.index(1)
.possible_value("test123"))
.arg(
Arg::with_name("positional")
.index(1)
.possible_value("test123"),
)
.get_matches_from_safe(vec!["myprog", "notest"]);
assert!(m.is_err());
@ -56,28 +63,35 @@ fn possible_values_of_positional_fail() {
#[test]
fn possible_values_of_positional_multiple() {
let m = App::new("possible_values")
.arg(Arg::with_name("positional")
.index(1)
.possible_value("test123")
.possible_value("test321")
.multiple(true))
.arg(
Arg::with_name("positional")
.index(1)
.possible_value("test123")
.possible_value("test321")
.multiple(true),
)
.get_matches_from_safe(vec!["myprog", "test123", "test321"]);
assert!(m.is_ok());
let m = m.unwrap();
assert!(m.is_present("positional"));
assert_eq!(m.values_of("positional").unwrap().collect::<Vec<_>>(), vec!["test123", "test321"]);
assert_eq!(
m.values_of("positional").unwrap().collect::<Vec<_>>(),
vec!["test123", "test321"]
);
}
#[test]
fn possible_values_of_positional_multiple_fail() {
let m = App::new("possible_values")
.arg(Arg::with_name("positional")
.index(1)
.possible_value("test123")
.possible_value("test321")
.multiple(true))
.arg(
Arg::with_name("positional")
.index(1)
.possible_value("test123")
.possible_value("test321")
.multiple(true),
)
.get_matches_from_safe(vec!["myprog", "test123", "notest"]);
assert!(m.is_err());
@ -87,11 +101,13 @@ fn possible_values_of_positional_multiple_fail() {
#[test]
fn possible_values_of_option() {
let m = App::new("possible_values")
.arg(Arg::with_name("option")
.short("-o")
.long("--option")
.takes_value(true)
.possible_value("test123"))
.arg(
Arg::with_name("option")
.short("-o")
.long("--option")
.takes_value(true)
.possible_value("test123"),
)
.get_matches_from_safe(vec!["myprog", "--option", "test123"]);
assert!(m.is_ok());
@ -104,11 +120,13 @@ fn possible_values_of_option() {
#[test]
fn possible_values_of_option_fail() {
let m = App::new("possible_values")
.arg(Arg::with_name("option")
.short("-o")
.long("--option")
.takes_value(true)
.possible_value("test123"))
.arg(
Arg::with_name("option")
.short("-o")
.long("--option")
.takes_value(true)
.possible_value("test123"),
)
.get_matches_from_safe(vec!["myprog", "--option", "notest"]);
assert!(m.is_err());
@ -118,41 +136,40 @@ fn possible_values_of_option_fail() {
#[test]
fn possible_values_of_option_multiple() {
let m = App::new("possible_values")
.arg(Arg::with_name("option")
.short("-o")
.long("--option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.multiple(true))
.get_matches_from_safe(vec![
"",
"--option", "test123",
"--option", "test321",
]);
.arg(
Arg::with_name("option")
.short("-o")
.long("--option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.multiple(true),
)
.get_matches_from_safe(vec!["", "--option", "test123", "--option", "test321"]);
assert!(m.is_ok());
let m = m.unwrap();
assert!(m.is_present("option"));
assert_eq!(m.values_of("option").unwrap().collect::<Vec<_>>(), vec!["test123", "test321"]);
assert_eq!(
m.values_of("option").unwrap().collect::<Vec<_>>(),
vec!["test123", "test321"]
);
}
#[test]
fn possible_values_of_option_multiple_fail() {
let m = App::new("possible_values")
.arg(Arg::with_name("option")
.short("-o")
.long("--option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.multiple(true))
.get_matches_from_safe(vec![
"",
"--option", "test123",
"--option", "notest",
]);
.arg(
Arg::with_name("option")
.short("-o")
.long("--option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.multiple(true),
)
.get_matches_from_safe(vec!["", "--option", "test123", "--option", "notest"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue);
@ -160,5 +177,90 @@ fn possible_values_of_option_multiple_fail() {
#[test]
fn possible_values_output() {
assert!(test::compare_output(test::complex_app(), "clap-test -O slo", PV_ERROR, true));
assert!(test::compare_output(
test::complex_app(),
"clap-test -O slo",
PV_ERROR,
true
));
}
#[test]
fn case_insensitive() {
let m = App::new("pv")
.arg(
Arg::with_name("option")
.short("-o")
.long("--option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.case_insensitive(true),
)
.get_matches_from_safe(vec!["pv", "--option", "TeSt123"]);
assert!(m.is_ok());
assert!(
m.unwrap()
.value_of("option")
.unwrap()
.eq_ignore_ascii_case("test123")
);
}
#[test]
fn case_insensitive_faili() {
let m = App::new("pv")
.arg(
Arg::with_name("option")
.short("-o")
.long("--option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321"),
)
.get_matches_from_safe(vec!["pv", "--option", "TeSt123"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue);
}
#[test]
fn case_insensitive_multiple() {
let m = App::new("pv")
.arg(
Arg::with_name("option")
.short("-o")
.long("--option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.multiple(true)
.case_insensitive(true),
)
.get_matches_from_safe(vec!["pv", "--option", "TeSt123", "teST123", "tESt321"]);
assert!(m.is_ok());
assert_eq!(
m.unwrap().values_of("option").unwrap().collect::<Vec<_>>(),
&["TeSt123", "teST123", "tESt321"]
);
}
#[test]
fn case_insensitive_multiple_fail() {
let m = App::new("pv")
.arg(
Arg::with_name("option")
.short("-o")
.long("--option")
.takes_value(true)
.possible_value("test123")
.possible_value("test321")
.multiple(true),
)
.get_matches_from_safe(vec!["pv", "--option", "test123", "teST123", "test321"]);
assert!(m.is_err());
assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue);
}