clap 4.1.4升级至4.1.13

Signed-off-by: 徐未来 <xuweilai2@huawei.com>
This commit is contained in:
徐未来 2024-04-02 20:06:53 +08:00
parent 4871ecbd72
commit a85e791e75
117 changed files with 1897 additions and 1078 deletions

View File

@ -1,26 +1,49 @@
name: Security audit
permissions:
contents: read
on:
pull_request:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
push:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
schedule:
- cron: '3 3 3 * *'
permissions:
contents: read
branches:
- main
env:
RUST_BACKTRACE: 1
CARGO_TERM_COLOR: always
CLICOLOR: 1
jobs:
security_audit:
permissions:
issues: write # to create issues (actions-rs/audit-check)
checks: write # to create check (actions-rs/audit-check)
runs-on: ubuntu-latest
# Prevent sudden announcement of a new advisory from failing ci:
continue-on-error: true
steps:
- name: Checkout repository
uses: actions/checkout@v3
- uses: actions-rs/audit-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
cargo_deny:
permissions:
issues: write # to create issues (actions-rs/audit-check)
checks: write # to create check (actions-rs/audit-check)
runs-on: ubuntu-latest
strategy:
matrix:
checks:
- bans licenses sources
steps:
- uses: actions/checkout@v3
- uses: EmbarkStudios/cargo-deny-action@v1
with:
command: check ${{ matrix.checks }}
rust-version: stable

View File

@ -13,7 +13,7 @@ jobs:
permissions:
contents: none
name: CI
needs: [test, check, docs, rustfmt, clippy]
needs: [test, check, docs, rustfmt, clippy, cffconvert]
runs-on: ubuntu-latest
steps:
- name: Done
@ -187,3 +187,15 @@ jobs:
run: make clippy-full
- name: Lint (release)
run: make clippy-release
cffconvert:
name: cffconvert
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
persist-credentials: false
- name: CFF validation
uses: citation-file-format/cffconvert-github-action@2.0.0
with:
args: --validate

View File

@ -20,7 +20,7 @@ ohos_cargo_crate("lib") {
sources = [ "src/lib.rs" ]
edition = "2021"
cargo_pkg_version = "4.1.4"
cargo_pkg_version = "4.1.13"
cargo_pkg_name = "clap"
cargo_pkg_description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
deps = [
@ -49,7 +49,7 @@ ohos_cargo_crate("stdio_fixture") {
sources = [ "src/bin/stdio-fixture.rs" ]
edition = "2021"
cargo_pkg_version = "4.1.4"
cargo_pkg_version = "4.1.13"
cargo_pkg_name = "clap"
cargo_pkg_description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
deps = [

View File

@ -18,6 +18,65 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
<!-- next-header -->
## [Unreleased] - ReleaseDate
## [4.1.13] - 2023-03-18
### Performance
- Reduce repeated alloc calls when building a `Command`
- Reduce duplicate dependencies for faster builds
## [4.1.12] - 2023-03-18
### Internal
- *(derive)* Update to `syn` v2
### Performance
- *(derive)* Faster build times by dropping `proc-macro-error` dependency
## [4.1.11] - 2023-03-17
### Internal
- Update `bitflags`
## [4.1.10] - 2023-03-17
### Fixes
- *(help)* On Windows, avoid underlined text artifacts
## [4.1.9] - 2023-03-16
### Fixes
- *(assert)* Improve the assert when using the wrong action with `get_count` / `get_flag`
## [4.1.8] - 2023-02-27
### Fixes
- *(derive)* Don't `deny` lints on the users behalf
## [4.1.7] - 2023-02-27
### Fixes
- *(derive)* Hide some nightly clippy warnings
## [4.1.6] - 2023-02-15
### Fixes
- *(help)* Don't show long help for `--help` just because hidden possible values include a description
## [4.1.5] - 2023-02-15
### Fixes
- *(help)* Don't show long help for `--help` just because a hidden arg has a possible value with a description
## [4.1.4] - 2023-01-24
### Fixes
@ -4119,7 +4178,16 @@ Minimum version of Rust is now v1.13.0 (Stable)
* **arg** allow lifetimes other than 'static in arguments ([9e8c1fb9](https://github.com/clap-rs/clap/commit/9e8c1fb9406f8448873ca58bab07fe905f1551e5))
<!-- next-url -->
[Unreleased]: https://github.com/clap-rs/clap/compare/v4.1.4...HEAD
[Unreleased]: https://github.com/clap-rs/clap/compare/v4.1.13...HEAD
[4.1.13]: https://github.com/clap-rs/clap/compare/v4.1.12...v4.1.13
[4.1.12]: https://github.com/clap-rs/clap/compare/v4.1.11...v4.1.12
[4.1.11]: https://github.com/clap-rs/clap/compare/v4.1.10...v4.1.11
[4.1.10]: https://github.com/clap-rs/clap/compare/v4.1.9...v4.1.10
[4.1.9]: https://github.com/clap-rs/clap/compare/v4.1.8...v4.1.9
[4.1.8]: https://github.com/clap-rs/clap/compare/v4.1.7...v4.1.8
[4.1.7]: https://github.com/clap-rs/clap/compare/v4.1.6...v4.1.7
[4.1.6]: https://github.com/clap-rs/clap/compare/v4.1.5...v4.1.6
[4.1.5]: https://github.com/clap-rs/clap/compare/v4.1.4...v4.1.5
[4.1.4]: https://github.com/clap-rs/clap/compare/v4.1.3...v4.1.4
[4.1.3]: https://github.com/clap-rs/clap/compare/v4.1.2...v4.1.3
[4.1.2]: https://github.com/clap-rs/clap/compare/v4.1.1...v4.1.2

35
CITATION.cff Normal file
View File

@ -0,0 +1,35 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Parser settings.
cff-version: 1.2.0
message: Please cite this crate using these information.
# Version information.
date-released: 2023-03-18
version: 4.1.13
# Project information.
abstract: A full featured, fast Command Line Argument Parser for Rust
authors:
- alias: kbknapp
family-names: Knapp
given-names: Kevin B.
- name: The Clap Community
license:
- Apache-2.0
- MIT
repository-artifact: https://crates.io/crates/clap
repository-code: https://github.com/clap-rs/clap
title: clap
url: https://docs.rs/clap

341
Cargo.lock generated
View File

@ -4,9 +4,9 @@ version = 3
[[package]]
name = "addr2line"
version = "0.17.0"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
dependencies = [
"gimli",
]
@ -23,6 +23,46 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstream"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd0982309face56a044e935a18bbffcddeb1ce72e69a3ecc3bafb56d4e959f37"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-wincon",
"concolor-override",
"concolor-query",
"is-terminal",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453bc2a7b261f8c4d1ce5b2c6c222d648d00988d30315e4911fbddc4ddf8983c"
[[package]]
name = "anstyle-parse"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-wincon"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa"
dependencies = [
"anstyle",
"windows-sys 0.45.0",
]
[[package]]
name = "atty"
version = "0.2.14"
@ -42,9 +82,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
version = "0.3.66"
version = "0.3.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
dependencies = [
"addr2line",
"cc",
@ -55,6 +95,15 @@ dependencies = [
"rustc-demangle",
]
[[package]]
name = "basic-toml"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e819b667739967cd44d308b8c7b71305d8bb0729ac44a248aa08f33d01950b4"
dependencies = [
"serde",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -126,12 +175,12 @@ dependencies = [
[[package]]
name = "clap"
version = "4.1.4"
version = "4.1.13"
dependencies = [
"backtrace",
"bitflags",
"clap_derive",
"clap_lex 0.3.1",
"clap_lex 0.3.3",
"humantime",
"is-terminal",
"once_cell",
@ -153,17 +202,17 @@ dependencies = [
name = "clap_bench"
version = "0.0.0"
dependencies = [
"clap 4.1.4",
"clap 4.1.13",
"criterion",
"lazy_static",
]
[[package]]
name = "clap_complete"
version = "4.1.1"
version = "4.1.5"
dependencies = [
"clap 4.1.4",
"clap_lex 0.3.1",
"clap 4.1.13",
"clap_lex 0.3.3",
"is_executable",
"os_str_bytes",
"pathdiff",
@ -175,22 +224,21 @@ dependencies = [
[[package]]
name = "clap_complete_fig"
version = "4.1.0"
version = "4.1.2"
dependencies = [
"clap 4.1.4",
"clap 4.1.13",
"clap_complete",
"snapbox",
]
[[package]]
name = "clap_derive"
version = "4.1.0"
version = "4.1.12"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
"syn 2.0.8",
]
[[package]]
@ -204,36 +252,34 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.3.1"
version = "0.3.3"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "clap_mangen"
version = "0.2.7"
version = "0.2.10"
dependencies = [
"clap 4.1.4",
"clap 4.1.13",
"roff",
"snapbox",
]
[[package]]
name = "concolor"
version = "0.0.11"
name = "concolor-override"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "318d6c16e73b3a900eb212ad6a82fc7d298c5ab8184c7a9998646455bc474a16"
dependencies = [
"bitflags",
"concolor-query",
"is-terminal",
]
checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f"
[[package]]
name = "concolor-query"
version = "0.1.0"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82a90734b3d5dcf656e7624cca6bce9c3a90ee11f900e80141a7427ccfb3d317"
checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf"
dependencies = [
"windows-sys 0.45.0",
]
[[package]]
name = "criterion"
@ -355,9 +401,9 @@ dependencies = [
[[package]]
name = "gimli"
version = "0.26.2"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
[[package]]
name = "glob"
@ -394,12 +440,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.2.6"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "humantime"
@ -434,19 +477,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
dependencies = [
"libc",
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
name = "is-terminal"
version = "0.4.1"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857"
dependencies = [
"hermit-abi 0.2.6",
"hermit-abi 0.3.1",
"io-lifetimes",
"rustix",
"windows-sys",
"windows-sys 0.45.0",
]
[[package]]
@ -526,22 +569,13 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.5.3"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
dependencies = [
"adler",
]
[[package]]
name = "nom8"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
dependencies = [
"memchr",
]
[[package]]
name = "normalize-line-endings"
version = "0.3.0"
@ -569,9 +603,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.29.0"
version = "0.30.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
dependencies = [
"memchr",
]
@ -638,44 +672,20 @@ dependencies = [
"plotters-backend",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.47"
version = "1.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [
"proc-macro2",
]
@ -742,14 +752,14 @@ dependencies = [
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
name = "rustversion"
version = "1.0.9"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
[[package]]
name = "ryu"
@ -774,22 +784,22 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.147"
version = "1.0.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.147"
version = "1.0.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.8",
]
[[package]]
@ -803,6 +813,15 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
dependencies = [
"serde",
]
[[package]]
name = "shlex"
version = "1.1.0"
@ -817,26 +836,30 @@ checksum = "62ac7f900db32bf3fd12e0117dd3dc4da74bc52ebaac97f39668446d89694803"
[[package]]
name = "snapbox"
version = "0.4.4"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34eced5a65e76d5a00047986a83c65f80dc666faa27b5138f331659e2ca6bcf5"
checksum = "9615402f9cff539301119bdf2c2f328739cf2b45c2116666618fb6ac399f75bb"
dependencies = [
"concolor",
"anstream",
"anstyle",
"escargot",
"libc",
"normalize-line-endings",
"os_pipe",
"similar",
"snapbox-macros",
"wait-timeout",
"windows-sys",
"yansi",
"windows-sys 0.45.0",
]
[[package]]
name = "snapbox-macros"
version = "0.3.1"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "485e65c1203eb37244465e857d15a26d3a85a5410648ccb53b18bd44cb3a7336"
checksum = "f8e40c667388ed1cb5060f545d0013bf0a23efdfa6c5c3e9ef592de391cd860f"
dependencies = [
"anstream",
]
[[package]]
name = "static_assertions"
@ -852,9 +875,20 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.103"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcc02725fd69ab9f26eab07fad303e2497fad6fb9eba4f96c4d1687bdf704ad9"
dependencies = [
"proc-macro2",
"quote",
@ -877,7 +911,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
dependencies = [
"rustix",
"windows-sys",
"windows-sys 0.42.0",
]
[[package]]
@ -896,59 +930,49 @@ dependencies = [
"serde_json",
]
[[package]]
name = "toml"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
dependencies = [
"serde",
]
[[package]]
name = "toml_datetime"
version = "0.5.0"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808b51e57d0ef8f71115d8f3a01e7d3750d01c79cac4b3eda910f4389fdf92fd"
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.17.1"
version = "0.19.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a34cc558345efd7e88b9eda9626df2138b80bb46a7606f695e751c892bc7dac6"
checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825"
dependencies = [
"indexmap",
"itertools",
"nom8",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "trybuild"
version = "1.0.73"
version = "1.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed01de3de062db82c0920b5cabe804f88d599a3f217932292597c678c903754d"
checksum = "a44da5a6f2164c8e14d3bbc0657d69c5966af9f5f6930d4f600b1f5c4a673413"
dependencies = [
"basic-toml",
"glob",
"once_cell",
"serde",
"serde_derive",
"serde_json",
"termcolor",
"toml",
]
[[package]]
name = "trycmd"
version = "0.14.9"
version = "0.14.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a050cd97463d2f8df73e65b122dadb7f04ea31f0bd53a1306ea915cbb156849"
checksum = "32564b3f936a9ebedf5cc07dcf1e7e661204766d35f92c03bf347b099d84e783"
dependencies = [
"escargot",
"glob",
"humantime",
"humantime-serde",
@ -1011,9 +1035,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.5"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "unicode-width"
@ -1027,6 +1051,12 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "version_check"
version = "0.9.4"
@ -1074,7 +1104,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn",
"syn 1.0.109",
"wasm-bindgen-shared",
]
@ -1096,7 +1126,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.109",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -1164,49 +1194,76 @@ dependencies = [
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.0"
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "yansi"
version = "0.5.1"
name = "winnow"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
checksum = "faf09497b8f8b5ac5d3bb4d05c0a99be20f26fd3d5f2db7b0716e946d5103658"
dependencies = [
"memchr",
]

View File

@ -24,7 +24,7 @@ include = [
[package]
name = "clap"
version = "4.1.4"
version = "4.1.13"
description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
repository = "https://github.com/clap-rs/clap"
categories = ["command-line-interface"]
@ -57,6 +57,8 @@ pre-release-replacements = [
{file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1},
{file="CHANGELOG.md", search="<!-- next-header -->", replace="<!-- next-header -->\n## [Unreleased] - ReleaseDate\n", exactly=1},
{file="CHANGELOG.md", search="<!-- next-url -->", replace="<!-- next-url -->\n[Unreleased]: https://github.com/clap-rs/clap/compare/{{tag_name}}...HEAD", exactly=1},
{file="CITATION.cff", search="^date-released: ....-..-..", replace="date-released: {{date}}"},
{file="CITATION.cff", search="^version: .+\\..+\\..+", replace="version: {{version}}"},
]
[features]
@ -97,25 +99,25 @@ unstable-v5 = ["clap_derive?/unstable-v5", "deprecated"]
bench = false
[dependencies]
clap_derive = { path = "./clap_derive", version = "=4.1.0", optional = true }
clap_derive = { path = "./clap_derive", version = "=4.1.12", optional = true }
clap_lex = { path = "./clap_lex", version = "0.3.0" }
bitflags = "1.2"
unicase = { version = "2.6", optional = true }
strsim = { version = "0.10", optional = true }
bitflags = "1.2.0"
unicase = { version = "2.6.0", optional = true }
strsim = { version = "0.10.0", optional = true }
is-terminal = { version = "0.4.1", optional = true }
termcolor = { version = "1.1.1", optional = true }
terminal_size = { version = "0.2.1", optional = true }
backtrace = { version = "0.3", optional = true }
backtrace = { version = "0.3.67", optional = true }
unicode-width = { version = "0.1.9", optional = true }
once_cell = { version = "1.12.0", optional = true }
[dev-dependencies]
trybuild = "1.0.73"
rustversion = "1"
trybuild = "1.0.77"
rustversion = "1.0.12"
# Cutting out `filesystem` feature
trycmd = { version = "0.14.9", default-features = false, features = ["color-auto", "diff", "examples"] }
humantime = "2"
snapbox = "0.4"
trycmd = { version = "0.14.15", default-features = false, features = ["color-auto", "diff", "examples"] }
humantime = "2.1.0"
snapbox = "0.4.10"
shlex = "1.1.0"
static_assertions = "1.1.0"
unic-emoji-char = "0.9.0"

View File

@ -3,7 +3,7 @@
"Name": "clap",
"License": "Apache license 2.0, MIT",
"License File": "LICENSE-MIT, LICENSE-APACHE",
"Version Number": "v4.1.4",
"Version Number": "v4.1.13",
"Owner": "fangting12@huawei.com",
"Upstream URL": "https://github.com/clap-rs/clap",
"Description": "A command-line argument parsing library for Rust that supports subcommands and complex argument parsing."

View File

@ -14,7 +14,7 @@ release = false
[dev-dependencies]
clap = { path = "../", version = "4.0.0", default-features = false, features = ["std", "help"] }
criterion = "0.4.0"
lazy_static = "1"
lazy_static = "1.4.0"
[[bench]]
harness = false

View File

@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
<!-- next-header -->
## [Unreleased] - ReleaseDate
## [4.1.5] - 2023-03-16
## [4.1.4] - 2023-02-27
### Features
- *(zsh)* Allow sourcing completion
## [4.1.3] - 2023-02-23
### Fixes
- *(zsh)* Improve handling of multi-valued arguments
## [4.1.2] - 2023-02-15
## [4.1.1] - 2023-01-23
### Fixes
@ -109,7 +125,11 @@ MSRV changed to 1.64.0
## [3.0.1] - 2022-01-03
<!-- next-url -->
[Unreleased]: https://github.com/clap-rs/clap/compare/clap_complete-v4.1.1...HEAD
[Unreleased]: https://github.com/clap-rs/clap/compare/clap_complete-v4.1.5...HEAD
[4.1.5]: https://github.com/clap-rs/clap/compare/clap_complete-v4.1.4...clap_complete-v4.1.5
[4.1.4]: https://github.com/clap-rs/clap/compare/clap_complete-v4.1.3...clap_complete-v4.1.4
[4.1.3]: https://github.com/clap-rs/clap/compare/clap_complete-v4.1.2...clap_complete-v4.1.3
[4.1.2]: https://github.com/clap-rs/clap/compare/clap_complete-v4.1.1...clap_complete-v4.1.2
[4.1.1]: https://github.com/clap-rs/clap/compare/clap_complete-v4.1.0...clap_complete-v4.1.1
[4.1.0]: https://github.com/clap-rs/clap/compare/clap_complete-v4.0.7...clap_complete-v4.1.0
[4.0.7]: https://github.com/clap-rs/clap/compare/clap_complete-v4.0.6...clap_complete-v4.0.7

View File

@ -1,6 +1,6 @@
[package]
name = "clap_complete"
version = "4.1.1"
version = "4.1.5"
description = "Generate shell completion scripts for your clap::Command"
repository = "https://github.com/clap-rs/clap/tree/master/clap_complete"
categories = ["command-line-interface"]
@ -35,15 +35,15 @@ bench = false
clap = { path = "../", version = "4.1.0", default-features = false, features = ["std"] }
clap_lex = { path = "../clap_lex", version = "0.3.0", optional = true }
is_executable = { version = "1.0.1", optional = true }
os_str_bytes = { version = "6.0", default-features = false, features = ["raw_os_str"], optional = true }
os_str_bytes = { version = "6.0.0", default-features = false, features = ["raw_os_str"], optional = true }
pathdiff = { version = "0.2.1", optional = true }
shlex = { version = "1.1.0", optional = true }
unicode-xid = { version = "0.2.2", optional = true }
[dev-dependencies]
snapbox = { version = "0.4", features = ["diff"] }
snapbox = { version = "0.4.10", features = ["diff"] }
# Cutting out `filesystem` feature
trycmd = { version = "0.14.6", default-features = false, features = ["color-auto", "diff", "examples"] }
trycmd = { version = "0.14.15", default-features = false, features = ["color-auto", "diff", "examples"] }
clap = { path = "../", version = "4.0.0", default-features = false, features = ["std", "derive", "help"] }
[[example]]

View File

@ -5,16 +5,16 @@
[![Crates.io](https://img.shields.io/crates/v/clap_complete?style=flat-square)](https://crates.io/crates/clap_complete)
[![Crates.io](https://img.shields.io/crates/d/clap_complete?style=flat-square)](https://crates.io/crates/clap_complete)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_complete-v4.1.1/LICENSE-APACHE)
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_complete-v4.1.1/LICENSE-MIT)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_complete-v4.1.5/LICENSE-APACHE)
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_complete-v4.1.5/LICENSE-MIT)
Dual-licensed under [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT).
1. [About](#about)
2. [API Reference](https://docs.rs/clap_complete)
3. [Questions & Discussions](https://github.com/clap-rs/clap/discussions)
4. [CONTRIBUTING](https://github.com/clap-rs/clap/blob/clap_complete-v4.1.1/clap_complete/CONTRIBUTING.md)
5. [Sponsors](https://github.com/clap-rs/clap/blob/clap_complete-v4.1.1/README.md#sponsors)
4. [CONTRIBUTING](https://github.com/clap-rs/clap/blob/clap_complete-v4.1.5/clap_complete/CONTRIBUTING.md)
5. [Sponsors](https://github.com/clap-rs/clap/blob/clap_complete-v4.1.5/README.md#sponsors)
## About

View File

@ -24,7 +24,7 @@ struct Opt {
// If provided, outputs the completion file for given shell
#[arg(long = "generate", value_enum)]
generator: Option<Shell>,
#[clap(subcommand)]
#[command(subcommand)]
command: Option<Commands>,
}
@ -75,9 +75,9 @@ fn main() {
if let Some(generator) = opt.generator {
let mut cmd = Opt::command();
eprintln!("Generating completion file for {:?}...", generator);
eprintln!("Generating completion file for {generator:?}...");
print_completions(generator, &mut cmd);
} else {
println!("{:#?}", opt);
println!("{opt:#?}");
}
}

View File

@ -103,7 +103,7 @@ fn main() {
if let Some(generator) = matches.get_one::<Shell>("generator") {
let mut cmd = build_cli();
eprintln!("Generating completion file for {}...", generator);
eprintln!("Generating completion file for {generator}...");
print_completions(*generator, &mut cmd);
}
}

View File

@ -10,7 +10,7 @@ pub struct Bash;
impl Generator for Bash {
fn file_name(&self, name: &str) -> String {
format!("{}.bash", name)
format!("{name}.bash")
}
fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
@ -114,9 +114,6 @@ fn all_subcommands(cmd: &Command) -> String {
"{parent_fn_name},{name})
cmd=\"{fn_name}\"
;;",
parent_fn_name = parent_fn_name,
name = name,
fn_name = fn_name,
));
}
@ -221,10 +218,10 @@ fn all_options_for_path(cmd: &Command, path: &str) -> String {
let mut opts = String::new();
for short in utils::shorts_and_visible_aliases(p) {
write!(&mut opts, "-{} ", short).unwrap();
write!(&mut opts, "-{short} ").unwrap();
}
for long in utils::longs_and_visible_aliases(p) {
write!(&mut opts, "--{} ", long).unwrap();
write!(&mut opts, "--{long} ").unwrap();
}
for pos in p.get_positionals() {
if let Some(vals) = utils::possible_values(pos) {
@ -232,11 +229,11 @@ fn all_options_for_path(cmd: &Command, path: &str) -> String {
write!(&mut opts, "{} ", value.get_name()).unwrap();
}
} else {
write!(&mut opts, "{} ", pos).unwrap();
write!(&mut opts, "{pos} ").unwrap();
}
}
for (sc, _) in utils::subcommands(p) {
write!(&mut opts, "{} ", sc).unwrap();
write!(&mut opts, "{sc} ").unwrap();
}
opts.pop();

View File

@ -12,7 +12,7 @@ pub struct Elvish;
impl Generator for Elvish {
fn file_name(&self, name: &str) -> String {
format!("{}.elv", name)
format!("{name}.elv")
}
fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
@ -46,8 +46,6 @@ set edit:completion:arg-completer[{bin_name}] = {{|@words|
$completions[$command]
}}
"#,
bin_name = bin_name,
subcommands_cases = subcommands_cases
);
w!(buf, result.as_bytes());
@ -83,7 +81,7 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String {
let tooltip = get_tooltip(option.get_help(), shorts[0]);
for short in shorts {
completions.push_str(&preamble);
completions.push_str(format!("-{} '{}'", short, tooltip).as_str());
completions.push_str(format!("-{short} '{tooltip}'").as_str());
}
}
@ -91,7 +89,7 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String {
let tooltip = get_tooltip(option.get_help(), longs[0]);
for long in longs {
completions.push_str(&preamble);
completions.push_str(format!("--{} '{}'", long, tooltip).as_str());
completions.push_str(format!("--{long} '{tooltip}'").as_str());
}
}
}
@ -101,7 +99,7 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String {
let tooltip = get_tooltip(flag.get_help(), shorts[0]);
for short in shorts {
completions.push_str(&preamble);
completions.push_str(format!("-{} '{}'", short, tooltip).as_str());
completions.push_str(format!("-{short} '{tooltip}'").as_str());
}
}
@ -109,7 +107,7 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String {
let tooltip = get_tooltip(flag.get_help(), longs[0]);
for long in longs {
completions.push_str(&preamble);
completions.push_str(format!("--{} '{}'", long, tooltip).as_str());
completions.push_str(format!("--{long} '{tooltip}'").as_str());
}
}
}
@ -119,7 +117,7 @@ fn generate_inner(p: &Command, previous_command_name: &str) -> String {
let tooltip = get_tooltip(subcommand.get_about(), data);
completions.push_str(&preamble);
completions.push_str(format!("{} '{}'", data, tooltip).as_str());
completions.push_str(format!("{data} '{tooltip}'").as_str());
}
let mut subcommands_cases = format!(

View File

@ -12,7 +12,7 @@ pub struct Fish;
impl Generator for Fish {
fn file_name(&self, name: &str) -> String {
format!("{}.fish", name)
format!("{name}.fish")
}
fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
@ -56,7 +56,7 @@ fn gen_fish_inner(
// -n "__fish_use_subcommand" # complete for command "myprog"
// -n "__fish_seen_subcommand_from subcmd1" # complete for command "myprog subcmd1"
let mut basic_template = format!("complete -c {}", root_command);
let mut basic_template = format!("complete -c {root_command}");
if parent_commands.is_empty() {
if cmd.has_subcommands() {
@ -68,10 +68,10 @@ fn gen_fish_inner(
" -n \"{}\"",
parent_commands
.iter()
.map(|command| format!("__fish_seen_subcommand_from {}", command))
.map(|command| format!("__fish_seen_subcommand_from {command}"))
.chain(
cmd.get_subcommands()
.map(|command| format!("not __fish_seen_subcommand_from {}", command))
.map(|command| format!("not __fish_seen_subcommand_from {command}"))
)
.collect::<Vec<_>>()
.join("; and ")
@ -87,7 +87,7 @@ fn gen_fish_inner(
if let Some(shorts) = option.get_short_and_visible_aliases() {
for short in shorts {
template.push_str(format!(" -s {}", short).as_str());
template.push_str(format!(" -s {short}").as_str());
}
}
@ -113,7 +113,7 @@ fn gen_fish_inner(
if let Some(shorts) = flag.get_short_and_visible_aliases() {
for short in shorts {
template.push_str(format!(" -s {}", short).as_str());
template.push_str(format!(" -s {short}").as_str());
}
}

View File

@ -12,7 +12,7 @@ pub struct PowerShell;
impl Generator for PowerShell {
fn file_name(&self, name: &str) -> String {
format!("_{}.ps1", name)
format!("_{name}.ps1")
}
fn generate(&self, cmd: &Command, buf: &mut dyn Write) {

View File

@ -42,7 +42,7 @@ impl FromStr for Shell {
return Ok(*variant);
}
}
Err(format!("invalid variant: {}", s))
Err(format!("invalid variant: {s}"))
}
}

View File

@ -11,7 +11,7 @@ pub struct Zsh;
impl Generator for Zsh {
fn file_name(&self, name: &str) -> String {
format!("_{}", name)
format!("_{name}")
}
fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
@ -43,7 +43,11 @@ _{name}() {{
{subcommand_details}
_{name} \"$@\"
if [ \"$funcstack[1]\" = \"_{name}\" ]; then
_{name} \"$@\"
else
compdef _{name} {name}
fi
",
name = bin_name,
initial_args = get_args_of(cmd, None),
@ -111,8 +115,8 @@ _{bin_name_underscore}_commands() {{
all_subcommands.sort();
all_subcommands.dedup();
for &(_, ref bin_name) in &all_subcommands {
debug!("subcommand_details:iter: bin_name={}", bin_name);
for (_, ref bin_name) in &all_subcommands {
debug!("subcommand_details:iter: bin_name={bin_name}");
ret.push(format!(
"\
@ -223,14 +227,12 @@ fn get_subcommands_of(parent: &Command) -> String {
let subcommand_names = utils::subcommands(parent);
let mut all_subcommands = vec![];
for &(ref name, ref bin_name) in &subcommand_names {
for (ref name, ref bin_name) in &subcommand_names {
debug!(
"get_subcommands_of:iter: parent={}, name={}, bin_name={}",
"get_subcommands_of:iter: parent={}, name={name}, bin_name={bin_name}",
parent.get_name(),
name,
bin_name,
);
let mut segments = vec![format!("({})", name)];
let mut segments = vec![format!("({name})")];
let subcommand_args = get_args_of(
parser_of(parent, bin_name).expect(INTERNAL_ERROR_MSG),
Some(parent),
@ -458,8 +460,8 @@ fn write_opts_of(p: &Command, p_global: Option<&Command>) -> String {
Some(val) => val[0].to_string(),
};
let vc = match value_completion(o) {
Some(val) => format!(":{}:{}", vn, val),
None => format!(":{}: ", vn),
Some(val) => format!(":{vn}:{val}"),
None => format!(":{vn}: "),
};
let vc = vc.repeat(o.get_num_args().expect("built").min_values());
@ -502,11 +504,11 @@ fn arg_conflicts(cmd: &Command, arg: &Arg, app_global: Option<&Command>) -> Stri
fn push_conflicts(conflicts: &[&Arg], res: &mut Vec<String>) {
for conflict in conflicts {
if let Some(s) = conflict.get_short() {
res.push(format!("-{}", s));
res.push(format!("-{s}"));
}
if let Some(l) = conflict.get_long() {
res.push(format!("--{}", l));
res.push(format!("--{l}"));
}
}
}
@ -568,13 +570,7 @@ fn write_flags_of(p: &Command, p_global: Option<&Command>) -> String {
if let Some(short_aliases) = f.get_visible_short_aliases() {
for alias in short_aliases {
let s = format!(
"'{conflicts}{multiple}-{arg}[{help}]' \\",
multiple = multiple,
conflicts = conflicts,
arg = alias,
help = help
);
let s = format!("'{conflicts}{multiple}-{alias}[{help}]' \\",);
debug!("write_flags_of:iter: Wrote...{}", &*s);
@ -622,18 +618,46 @@ fn write_positionals_of(p: &Command) -> String {
let mut ret = vec![];
// Completions for commands that end with two Vec arguments require special care.
// - You can have two Vec args separated with a custom value terminator.
// - You can have two Vec args with the second one set to last (raw sets last)
// which will require a '--' separator to be used before the second argument
// on the command-line.
//
// We use the '-S' _arguments option to disable completion after '--'. Thus, the
// completion for the second argument in scenario (B) does not need to be emitted
// because it is implicitly handled by the '-S' option.
// We only need to emit the first catch-all.
//
// Have we already emitted a catch-all multi-valued positional argument
// without a custom value terminator?
let mut catch_all_emitted = false;
for arg in p.get_positionals() {
debug!("write_positionals_of:iter: arg={}", arg.get_id());
let num_args = arg.get_num_args().expect("built");
let is_multi_valued = num_args.max_values() > 1;
if catch_all_emitted && (arg.is_last_set() || is_multi_valued) {
// This is the final argument and it also takes multiple arguments.
// We've already emitted a catch-all positional argument so we don't need
// to emit anything for this argument because it is implicitly handled by
// the use of the '-S' _arguments option.
continue;
}
let cardinality_value;
let cardinality = if num_args.max_values() > 1 {
let cardinality = if is_multi_valued {
match arg.get_value_terminator() {
Some(terminator) => {
cardinality_value = format!("*{}:", escape_value(terminator));
cardinality_value.as_str()
}
None => "*:",
None => {
catch_all_emitted = true;
"*:"
}
}
} else if !arg.is_required_set() {
":"

View File

@ -111,3 +111,15 @@ fn register_minimal() {
.action_env("SNAPSHOTS")
.matches_path("tests/snapshots/register_minimal.bash", buf);
}
#[test]
fn two_multi_valued_arguments() {
let name = "my-app";
let cmd = common::two_multi_valued_arguments_command(name);
common::assert_matches_path(
"tests/snapshots/two_multi_valued_arguments.bash",
clap_complete::shells::Bash,
cmd,
name,
);
}

View File

@ -261,6 +261,20 @@ pub fn value_terminator_command(name: &'static str) -> clap::Command {
)
}
pub fn two_multi_valued_arguments_command(name: &'static str) -> clap::Command {
clap::Command::new(name)
.arg(
clap::Arg::new("first")
.help("first multi-valued argument")
.num_args(1..),
)
.arg(
clap::Arg::new("second")
.help("second multi-valued argument")
.raw(true),
)
}
pub fn assert_matches_path(
expected_path: impl AsRef<std::path::Path>,
gen: impl clap_complete::Generator,

View File

@ -95,3 +95,15 @@ fn value_terminator() {
name,
);
}
#[test]
fn two_multi_valued_arguments() {
let name = "my-app";
let cmd = common::two_multi_valued_arguments_command(name);
common::assert_matches_path(
"tests/snapshots/two_multi_valued_arguments.elvish",
clap_complete::shells::Elvish,
cmd,
name,
);
}

View File

@ -95,3 +95,15 @@ fn value_terminator() {
name,
);
}
#[test]
fn two_multi_valued_arguments() {
let name = "my-app";
let cmd = common::two_multi_valued_arguments_command(name);
common::assert_matches_path(
"tests/snapshots/two_multi_valued_arguments.fish",
clap_complete::shells::Fish,
cmd,
name,
);
}

View File

@ -95,3 +95,15 @@ fn value_terminator() {
name,
);
}
#[test]
fn two_multi_valued_arguments() {
let name = "my-app";
let cmd = common::two_multi_valued_arguments_command(name);
common::assert_matches_path(
"tests/snapshots/two_multi_valued_arguments.ps1",
clap_complete::shells::PowerShell,
cmd,
name,
);
}

View File

@ -37,4 +37,8 @@ _my-app_commands() {
_describe -t commands 'my-app commands' commands "$@"
}
_my-app "$@"
if [ "$funcstack[1]" = "_my-app" ]; then
_my-app "$@"
else
compdef _my-app my-app
fi

View File

@ -97,4 +97,8 @@ _my-app__test_commands() {
_describe -t commands 'my-app test commands' commands "$@"
}
_my-app "$@"
if [ "$funcstack[1]" = "_my-app" ]; then
_my-app "$@"
else
compdef _my-app my-app
fi

View File

@ -104,4 +104,8 @@ _my-app__test_commands() {
_describe -t commands 'my-app test commands' commands "$@"
}
_my-app "$@"
if [ "$funcstack[1]" = "_my-app" ]; then
_my-app "$@"
else
compdef _my-app my-app
fi

View File

@ -211,4 +211,8 @@ _my-app__help__help_commands() {
_describe -t commands 'my-app help help commands' commands "$@"
}
_my-app "$@"
if [ "$funcstack[1]" = "_my-app" ]; then
_my-app "$@"
else
compdef _my-app my-app
fi

View File

@ -178,4 +178,8 @@ _my-app__test_commands() {
_describe -t commands 'my-app test commands' commands "$@"
}
_my-app "$@"
if [ "$funcstack[1]" = "_my-app" ]; then
_my-app "$@"
else
compdef _my-app my-app
fi

View File

@ -224,4 +224,8 @@ _my-app__test_commands() {
_describe -t commands 'my-app test commands' commands "$@"
}
_my-app "$@"
if [ "$funcstack[1]" = "_my-app" ]; then
_my-app "$@"
else
compdef _my-app my-app
fi

View File

@ -0,0 +1,38 @@
_my-app() {
local i cur prev opts cmd
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
cmd=""
opts=""
for i in ${COMP_WORDS[@]}
do
case "${cmd},${i}" in
",$1")
cmd="my__app"
;;
*)
;;
esac
done
case "${cmd}" in
my__app)
opts="-h --help [first]... [second]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
esac
}
complete -F _my-app -o bashdefault -o default my-app

View File

@ -0,0 +1,26 @@
use builtin;
use str;
set edit:completion:arg-completer[my-app] = {|@words|
fn spaces {|n|
builtin:repeat $n ' ' | str:join ''
}
fn cand {|text desc|
edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc
}
var command = 'my-app'
for word $words[1..-1] {
if (str:has-prefix $word '-') {
break
}
set command = $command';'$word
}
var completions = [
&'my-app'= {
cand -h 'Print help'
cand --help 'Print help'
}
]
$completions[$command]
}

View File

@ -0,0 +1 @@
complete -c my-app -s h -l help -d 'Print help'

View File

@ -0,0 +1,32 @@
using namespace System.Management.Automation
using namespace System.Management.Automation.Language
Register-ArgumentCompleter -Native -CommandName 'my-app' -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
$commandElements = $commandAst.CommandElements
$command = @(
'my-app'
for ($i = 1; $i -lt $commandElements.Count; $i++) {
$element = $commandElements[$i]
if ($element -isnot [StringConstantExpressionAst] -or
$element.StringConstantType -ne [StringConstantType]::BareWord -or
$element.Value.StartsWith('-') -or
$element.Value -eq $wordToComplete) {
break
}
$element.Value
}) -join ';'
$completions = @(switch ($command) {
'my-app' {
[CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help')
break
}
})
$completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
Sort-Object -Property ListItemText
}

View File

@ -0,0 +1,34 @@
#compdef my-app
autoload -U is-at-least
_my-app() {
typeset -A opt_args
typeset -a _arguments_options
local ret=1
if is-at-least 5.2; then
_arguments_options=(-s -S -C)
else
_arguments_options=(-s -C)
fi
local context curcontext="$curcontext" state line
_arguments "${_arguments_options[@]}" \
'-h[Print help]' \
'--help[Print help]' \
'*::first -- first multi-valued argument:' \
&& ret=0
}
(( $+functions[_my-app_commands] )) ||
_my-app_commands() {
local commands; commands=()
_describe -t commands 'my-app commands' commands "$@"
}
if [ "$funcstack[1]" = "_my-app" ]; then
_my-app "$@"
else
compdef _my-app my-app
fi

View File

@ -47,4 +47,8 @@ _my-app_commands() {
_describe -t commands 'my-app commands' commands "$@"
}
_my-app "$@"
if [ "$funcstack[1]" = "_my-app" ]; then
_my-app "$@"
else
compdef _my-app my-app
fi

View File

@ -27,4 +27,8 @@ _my-app_commands() {
_describe -t commands 'my-app commands' commands "$@"
}
_my-app "$@"
if [ "$funcstack[1]" = "_my-app" ]; then
_my-app "$@"
else
compdef _my-app my-app
fi

View File

@ -95,3 +95,15 @@ fn value_terminator() {
name,
);
}
#[test]
fn two_multi_valued_arguments() {
let name = "my-app";
let cmd = common::two_multi_valued_arguments_command(name);
common::assert_matches_path(
"tests/snapshots/two_multi_valued_arguments.zsh",
clap_complete::shells::Zsh,
cmd,
name,
);
}

View File

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
<!-- next-header -->
## [Unreleased] - ReleaseDate
## [4.1.2] - 2023-03-16
## [4.1.1] - 2023-02-15
## [4.1.0] - 2023-01-13
### Compatibility
@ -63,7 +67,9 @@ MSRV changed to 1.64.0
## [3.0.1] - 2022-01-03
<!-- next-url -->
[Unreleased]: https://github.com/clap-rs/clap/compare/clap_complete_fig-v4.1.0...HEAD
[Unreleased]: https://github.com/clap-rs/clap/compare/clap_complete_fig-v4.1.2...HEAD
[4.1.2]: https://github.com/clap-rs/clap/compare/clap_complete_fig-v4.1.1...clap_complete_fig-v4.1.2
[4.1.1]: https://github.com/clap-rs/clap/compare/clap_complete_fig-v4.1.0...clap_complete_fig-v4.1.1
[4.1.0]: https://github.com/clap-rs/clap/compare/clap_complete_fig-v4.0.2...clap_complete_fig-v4.1.0
[4.0.2]: https://github.com/clap-rs/clap/compare/clap_complete_fig-v4.0.1...clap_complete_fig-v4.0.2
[4.0.1]: https://github.com/clap-rs/clap/compare/clap_complete_fig-v4.0.0...clap_complete_fig-v4.0.1

View File

@ -1,6 +1,6 @@
[package]
name = "clap_complete_fig"
version = "4.1.0"
version = "4.1.2"
description = "A generator library used with clap for Fig completion scripts"
repository = "https://github.com/clap-rs/clap/tree/master/clap_complete_fig"
categories = ["command-line-interface"]
@ -35,5 +35,5 @@ clap = { path = "../", version = "4.0.0", default-features = false, features = [
clap_complete = { path = "../clap_complete", version = "4.0.0" }
[dev-dependencies]
snapbox = { version = "0.4", features = ["diff"] }
snapbox = { version = "0.4.10", features = ["diff"] }
clap = { path = "../", version = "4.0.0", default-features = false, features = ["std", "help"] }

View File

@ -11,7 +11,7 @@ pub struct Fig;
impl Generator for Fig {
fn file_name(&self, name: &str) -> String {
format!("{}.ts", name)
format!("{name}.ts")
}
fn generate(&self, cmd: &Command, buf: &mut dyn std::io::Write) {
@ -267,11 +267,11 @@ fn gen_options(cmd: &Command, indent: usize) -> String {
let mut flags = vec![];
if let Some(shorts) = flag.get_short_and_visible_aliases() {
flags.extend(shorts.iter().map(|s| format!("-{}", s)));
flags.extend(shorts.iter().map(|s| format!("-{s}")));
}
if let Some(longs) = flag.get_long_and_visible_aliases() {
flags.extend(longs.iter().map(|s| format!("--{}", s)));
flags.extend(longs.iter().map(|s| format!("--{s}")));
}
if flags.len() > 1 {

View File

@ -14,20 +14,20 @@
import("//build/ohos.gni")
ohos_cargo_crate("lib") {
crate_name = "clap_derive"
crate_type = "proc-macro"
crate_root = "src/lib.rs"
crate_name = "clap_derive"
crate_type = "proc-macro"
crate_root = "src/lib.rs"
sources = ["src/lib.rs"]
edition = "2021"
cargo_pkg_version = "4.1.0"
cargo_pkg_name = "clap_derive"
cargo_pkg_description = "Parse command line argument by defining a struct, derive crate."
deps = [
"//third_party/rust/crates/heck:lib",
"//third_party/rust/crates/proc-macro2:lib",
"//third_party/rust/crates/proc-macro-error:lib",
"//third_party/rust/crates/quote:lib",
"//third_party/rust/crates/syn:lib",
]
sources = [ "src/lib.rs" ]
edition = "2021"
cargo_pkg_version = "4.1.12"
cargo_pkg_name = "clap_derive"
cargo_pkg_description =
"Parse command line argument by defining a struct, derive crate."
deps = [
"//third_party/rust/crates/heck:lib",
"//third_party/rust/crates/proc-macro2:lib",
"//third_party/rust/crates/quote:lib",
"//third_party/rust/crates/syn:lib",
]
}

View File

@ -1,6 +1,6 @@
[package]
name = "clap_derive"
version = "4.1.0"
version = "4.1.12"
description = "Parse command line argument by defining a struct, derive crate."
repository = "https://github.com/clap-rs/clap/tree/master/clap_derive"
categories = ["command-line-interface", "development-tools::procedural-macro-helpers"]
@ -29,11 +29,10 @@ proc-macro = true
bench = false
[dependencies]
syn = { version = "1.0.74", features = ["full"] }
syn = { version = "2.0.8", features = ["full"] }
quote = "1.0.9"
proc-macro2 = "1.0.42"
heck = "0.4.0"
proc-macro-error = "1"
[features]
default = []

View File

@ -1,8 +1,6 @@
use std::iter::FromIterator;
use proc_macro2::TokenStream;
use proc_macro_error::abort;
use proc_macro_error::ResultExt;
use quote::quote;
use quote::ToTokens;
use syn::spanned::Spanned;
@ -24,49 +22,44 @@ pub struct ClapAttr {
}
impl ClapAttr {
pub fn parse_all(all_attrs: &[Attribute]) -> Vec<Self> {
all_attrs
.iter()
.filter_map(|attr| {
let kind = if attr.path.is_ident("clap") {
Some(Sp::new(AttrKind::Clap, attr.path.span()))
} else if attr.path.is_ident("structopt") {
Some(Sp::new(AttrKind::StructOpt, attr.path.span()))
} else if attr.path.is_ident("command") {
Some(Sp::new(AttrKind::Command, attr.path.span()))
} else if attr.path.is_ident("group") {
Some(Sp::new(AttrKind::Group, attr.path.span()))
} else if attr.path.is_ident("arg") {
Some(Sp::new(AttrKind::Arg, attr.path.span()))
} else if attr.path.is_ident("value") {
Some(Sp::new(AttrKind::Value, attr.path.span()))
} else {
None
};
kind.map(|k| (k, attr))
})
.flat_map(|(k, attr)| {
attr.parse_args_with(Punctuated::<ClapAttr, Token![,]>::parse_terminated)
.unwrap_or_abort()
.into_iter()
.map(move |mut a| {
a.kind = k;
a
})
})
.collect()
pub fn parse_all(all_attrs: &[Attribute]) -> Result<Vec<Self>, syn::Error> {
let mut parsed = Vec::new();
for attr in all_attrs {
let kind = if attr.path().is_ident("clap") {
Sp::new(AttrKind::Clap, attr.path().span())
} else if attr.path().is_ident("structopt") {
Sp::new(AttrKind::StructOpt, attr.path().span())
} else if attr.path().is_ident("command") {
Sp::new(AttrKind::Command, attr.path().span())
} else if attr.path().is_ident("group") {
Sp::new(AttrKind::Group, attr.path().span())
} else if attr.path().is_ident("arg") {
Sp::new(AttrKind::Arg, attr.path().span())
} else if attr.path().is_ident("value") {
Sp::new(AttrKind::Value, attr.path().span())
} else {
continue;
};
for mut attr in
attr.parse_args_with(Punctuated::<ClapAttr, Token![,]>::parse_terminated)?
{
attr.kind = kind;
parsed.push(attr);
}
}
Ok(parsed)
}
pub fn value_or_abort(&self) -> &AttrValue {
pub fn value_or_abort(&self) -> Result<&AttrValue, syn::Error> {
self.value
.as_ref()
.unwrap_or_else(|| abort!(self.name, "attribute `{}` requires a value", self.name))
.ok_or_else(|| format_err!(self.name, "attribute `{}` requires a value", self.name))
}
pub fn lit_str_or_abort(&self) -> &LitStr {
let value = self.value_or_abort();
pub fn lit_str_or_abort(&self) -> Result<&LitStr, syn::Error> {
let value = self.value_or_abort()?;
match value {
AttrValue::LitStr(tokens) => tokens,
AttrValue::LitStr(tokens) => Ok(tokens),
AttrValue::Expr(_) | AttrValue::Call(_) => {
abort!(
self.name,
@ -133,7 +126,7 @@ impl Parse for ClapAttr {
let nested;
parenthesized!(nested in input);
let method_args: Punctuated<_, Token![,]> = nested.parse_terminated(Expr::parse)?;
let method_args: Punctuated<_, _> = nested.parse_terminated(Expr::parse, Token![,])?;
Some(AttrValue::Call(Vec::from_iter(method_args)))
} else {
None

View File

@ -13,7 +13,6 @@
// MIT/Apache 2.0 license.
use proc_macro2::{Ident, Span, TokenStream};
use proc_macro_error::{abort, abort_call_site};
use quote::{format_ident, quote, quote_spanned};
use syn::ext::IdentExt;
use syn::{
@ -21,30 +20,27 @@ use syn::{
Fields, Generics,
};
use crate::dummies;
use crate::item::{Item, Kind, Name};
use crate::utils::{inner_type, sub_type, Sp, Ty};
pub fn derive_args(input: &DeriveInput) -> TokenStream {
pub fn derive_args(input: &DeriveInput) -> Result<TokenStream, syn::Error> {
let ident = &input.ident;
dummies::args(ident);
match input.data {
Data::Struct(DataStruct {
fields: Fields::Named(ref fields),
..
}) => {
let name = Name::Derived(ident.clone());
let item = Item::from_args_struct(input, name);
let item = Item::from_args_struct(input, name)?;
let fields = fields
.named
.iter()
.map(|field| {
let item = Item::from_args_field(field, item.casing(), item.env_casing());
(field, item)
let item = Item::from_args_field(field, item.casing(), item.env_casing())?;
Ok((field, item))
})
.collect::<Vec<_>>();
.collect::<Result<Vec<_>, syn::Error>>()?;
gen_for_struct(&item, ident, &input.generics, &fields)
}
Data::Struct(DataStruct {
@ -52,15 +48,15 @@ pub fn derive_args(input: &DeriveInput) -> TokenStream {
..
}) => {
let name = Name::Derived(ident.clone());
let item = Item::from_args_struct(input, name);
let item = Item::from_args_struct(input, name)?;
let fields = Punctuated::<Field, Comma>::new();
let fields = fields
.iter()
.map(|field| {
let item = Item::from_args_field(field, item.casing(), item.env_casing());
(field, item)
let item = Item::from_args_field(field, item.casing(), item.env_casing())?;
Ok((field, item))
})
.collect::<Vec<_>>();
.collect::<Result<Vec<_>, syn::Error>>()?;
gen_for_struct(&item, ident, &input.generics, &fields)
}
_ => abort_call_site!("`#[derive(Args)]` only supports non-tuple structs"),
@ -72,7 +68,7 @@ pub fn gen_for_struct(
item_name: &Ident,
generics: &Generics,
fields: &[(&Field, Item)],
) -> TokenStream {
) -> Result<TokenStream, syn::Error> {
if !matches!(&*item.kind(), Kind::Command(_)) {
abort! { item.kind().span(),
"`{}` cannot be used with `command`",
@ -82,13 +78,13 @@ pub fn gen_for_struct(
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let constructor = gen_constructor(fields);
let updater = gen_updater(fields, true);
let constructor = gen_constructor(fields)?;
let updater = gen_updater(fields, true)?;
let raw_deprecated = raw_deprecated();
let app_var = Ident::new("__clap_app", Span::call_site());
let augmentation = gen_augment(fields, &app_var, item, false);
let augmentation_update = gen_augment(fields, &app_var, item, true);
let augmentation = gen_augment(fields, &app_var, item, false)?;
let augmentation_update = gen_augment(fields, &app_var, item, true)?;
let group_id = if item.skip_group() {
quote!(None)
@ -97,7 +93,7 @@ pub fn gen_for_struct(
quote!(Some(clap::Id::from(#group_id)))
};
quote! {
Ok(quote! {
#[allow(dead_code, unreachable_code, unused_variables, unused_braces)]
#[allow(
clippy::style,
@ -109,8 +105,8 @@ pub fn gen_for_struct(
clippy::nursery,
clippy::cargo,
clippy::suspicious_else_formatting,
clippy::almost_swapped,
)]
#[deny(clippy::correctness)]
impl #impl_generics clap::FromArgMatches for #item_name #ty_generics #where_clause {
fn from_arg_matches(__clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
Self::from_arg_matches_mut(&mut __clap_arg_matches.clone())
@ -144,8 +140,8 @@ pub fn gen_for_struct(
clippy::nursery,
clippy::cargo,
clippy::suspicious_else_formatting,
clippy::almost_swapped,
)]
#[deny(clippy::correctness)]
impl #impl_generics clap::Args for #item_name #ty_generics #where_clause {
fn group_id() -> Option<clap::Id> {
#group_id
@ -157,7 +153,7 @@ pub fn gen_for_struct(
#augmentation_update
}
}
}
})
}
/// Generate a block of code to add arguments/subcommands corresponding to
@ -167,11 +163,12 @@ pub fn gen_augment(
app_var: &Ident,
parent_item: &Item,
override_required: bool,
) -> TokenStream {
) -> Result<TokenStream, syn::Error> {
let mut subcommand_specified = false;
let args = fields.iter().filter_map(|(field, item)| {
let mut args = Vec::new();
for (field, item) in fields {
let kind = item.kind();
match &*kind {
let genned = match &*kind {
Kind::Command(_)
| Kind::Value
| Kind::Skip(_, _)
@ -179,7 +176,10 @@ pub fn gen_augment(
| Kind::ExternalSubcommand => None,
Kind::Subcommand(ty) => {
if subcommand_specified {
abort!(field.span(), "`#[command(subcommand)]` can only be used once per container");
abort!(
field.span(),
"`#[command(subcommand)]` can only be used once per container"
);
}
subcommand_specified = true;
@ -354,8 +354,9 @@ pub fn gen_augment(
});
})
}
}
});
};
args.push(genned);
}
let deprecations = if !override_required {
parent_item.deprecations()
@ -408,7 +409,7 @@ pub fn gen_augment(
)
)
};
quote! {{
Ok(quote! {{
#deprecations
let #app_var = #app_var
#initial_app_methods
@ -416,15 +417,15 @@ pub fn gen_augment(
;
#( #args )*
#app_var #final_app_methods
}}
}})
}
pub fn gen_constructor(fields: &[(&Field, Item)]) -> TokenStream {
pub fn gen_constructor(fields: &[(&Field, Item)]) -> Result<TokenStream, syn::Error> {
let fields = fields.iter().map(|(field, item)| {
let field_name = field.ident.as_ref().unwrap();
let kind = item.kind();
let arg_matches = format_ident!("__clap_arg_matches");
match &*kind {
let genned = match &*kind {
Kind::Command(_)
| Kind::Value
| Kind::ExternalSubcommand => {
@ -519,18 +520,20 @@ pub fn gen_constructor(fields: &[(&Field, Item)]) -> TokenStream {
},
Kind::Arg(ty) | Kind::FromGlobal(ty) => {
gen_parsers(item, ty, field_name, field, None)
gen_parsers(item, ty, field_name, field, None)?
}
}
});
};
Ok(genned)
}).collect::<Result<Vec<_>, syn::Error>>()?;
quote! {{
Ok(quote! {{
#( #fields ),*
}}
}})
}
pub fn gen_updater(fields: &[(&Field, Item)], use_self: bool) -> TokenStream {
let fields = fields.iter().map(|(field, item)| {
pub fn gen_updater(fields: &[(&Field, Item)], use_self: bool) -> Result<TokenStream, syn::Error> {
let mut genned_fields = Vec::new();
for (field, item) in fields {
let field_name = field.ident.as_ref().unwrap();
let kind = item.kind();
@ -544,10 +547,8 @@ pub fn gen_updater(fields: &[(&Field, Item)], use_self: bool) -> TokenStream {
};
let arg_matches = format_ident!("__clap_arg_matches");
match &*kind {
Kind::Command(_)
| Kind::Value
| Kind::ExternalSubcommand => {
let genned = match &*kind {
Kind::Command(_) | Kind::Value | Kind::ExternalSubcommand => {
abort! { kind.span(),
"`{}` cannot be used with `arg`",
kind.name(),
@ -617,17 +618,20 @@ pub fn gen_updater(fields: &[(&Field, Item)], use_self: bool) -> TokenStream {
#updater
}
}
},
}
Kind::Skip(_, _) => quote!(),
Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(item, ty, field_name, field, Some(&access)),
}
});
quote! {
#( #fields )*
Kind::Arg(ty) | Kind::FromGlobal(ty) => {
gen_parsers(item, ty, field_name, field, Some(&access))?
}
};
genned_fields.push(genned);
}
Ok(quote! {
#( #genned_fields )*
})
}
fn gen_parsers(
@ -636,7 +640,7 @@ fn gen_parsers(
field_name: &Ident,
field: &Field,
update: Option<&TokenStream>,
) -> TokenStream {
) -> Result<TokenStream, syn::Error> {
let span = ty.span();
let convert_type = inner_type(&field.ty);
let id = item.id();
@ -709,7 +713,7 @@ fn gen_parsers(
}
};
if let Some(access) = update {
let genned = if let Some(access) = update {
quote_spanned! { field.span()=>
if #arg_matches.contains_id(#id) {
#access
@ -718,7 +722,8 @@ fn gen_parsers(
}
} else {
quote_spanned!(field.span()=> #field_name: #field_value )
}
};
Ok(genned)
}
#[cfg(feature = "raw-deprecated")]

View File

@ -18,7 +18,11 @@ use syn::{Generics, Ident};
use crate::item::Item;
pub fn gen_for_struct(item: &Item, item_name: &Ident, generics: &Generics) -> TokenStream {
pub fn gen_for_struct(
item: &Item,
item_name: &Ident,
generics: &Generics,
) -> Result<TokenStream, syn::Error> {
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let name = item.cased_name();
@ -36,8 +40,8 @@ pub fn gen_for_struct(item: &Item, item_name: &Ident, generics: &Generics) -> To
clippy::nursery,
clippy::cargo,
clippy::suspicious_else_formatting,
clippy::almost_swapped,
)]
#[deny(clippy::correctness)]
impl #impl_generics clap::CommandFactory for #item_name #ty_generics #where_clause {
fn command<'b>() -> clap::Command {
let #app_var = clap::Command::new(#name);
@ -51,16 +55,20 @@ pub fn gen_for_struct(item: &Item, item_name: &Ident, generics: &Generics) -> To
}
};
tokens
Ok(tokens)
}
pub fn gen_for_enum(item: &Item, item_name: &Ident, generics: &Generics) -> TokenStream {
pub fn gen_for_enum(
item: &Item,
item_name: &Ident,
generics: &Generics,
) -> Result<TokenStream, syn::Error> {
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let name = item.cased_name();
let app_var = Ident::new("__clap_app", Span::call_site());
quote! {
Ok(quote! {
#[allow(dead_code, unreachable_code, unused_variables, unused_braces)]
#[allow(
clippy::style,
@ -72,8 +80,8 @@ pub fn gen_for_enum(item: &Item, item_name: &Ident, generics: &Generics) -> Toke
clippy::nursery,
clippy::cargo,
clippy::suspicious_else_formatting,
clippy::almost_swapped,
)]
#[deny(clippy::correctness)]
impl #impl_generics clap::CommandFactory for #item_name #ty_generics #where_clause {
fn command<'b>() -> clap::Command {
let #app_var = clap::Command::new(#name)
@ -89,5 +97,5 @@ pub fn gen_for_enum(item: &Item, item_name: &Ident, generics: &Generics) -> Toke
.arg_required_else_help(false)
}
}
}
})
}

View File

@ -13,7 +13,6 @@
// MIT/Apache 2.0 license.
use proc_macro2::TokenStream;
use proc_macro_error::abort_call_site;
use quote::quote;
use syn::Ident;
use syn::Variant;
@ -23,11 +22,10 @@ use syn::{
};
use crate::derives::{args, into_app, subcommand};
use crate::dummies;
use crate::item::Item;
use crate::item::Name;
pub fn derive_parser(input: &DeriveInput) -> TokenStream {
pub fn derive_parser(input: &DeriveInput) -> Result<TokenStream, syn::Error> {
let ident = &input.ident;
let pkg_name = std::env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
@ -36,52 +34,46 @@ pub fn derive_parser(input: &DeriveInput) -> TokenStream {
fields: Fields::Named(ref fields),
..
}) => {
dummies::parser_struct(ident);
let name = Name::Assigned(quote!(#pkg_name));
let item = Item::from_args_struct(input, name);
let item = Item::from_args_struct(input, name)?;
let fields = fields
.named
.iter()
.map(|field| {
let item = Item::from_args_field(field, item.casing(), item.env_casing());
(field, item)
let item = Item::from_args_field(field, item.casing(), item.env_casing())?;
Ok((field, item))
})
.collect::<Vec<_>>();
.collect::<Result<Vec<_>, syn::Error>>()?;
gen_for_struct(&item, ident, &input.generics, &fields)
}
Data::Struct(DataStruct {
fields: Fields::Unit,
..
}) => {
dummies::parser_struct(ident);
let name = Name::Assigned(quote!(#pkg_name));
let item = Item::from_args_struct(input, name);
let item = Item::from_args_struct(input, name)?;
let fields = Punctuated::<Field, Comma>::new();
let fields = fields
.iter()
.map(|field| {
let item = Item::from_args_field(field, item.casing(), item.env_casing());
(field, item)
let item = Item::from_args_field(field, item.casing(), item.env_casing())?;
Ok((field, item))
})
.collect::<Vec<_>>();
.collect::<Result<Vec<_>, syn::Error>>()?;
gen_for_struct(&item, ident, &input.generics, &fields)
}
Data::Enum(ref e) => {
dummies::parser_enum(ident);
let name = Name::Assigned(quote!(#pkg_name));
let item = Item::from_subcommand_enum(input, name);
let item = Item::from_subcommand_enum(input, name)?;
let variants = e
.variants
.iter()
.map(|variant| {
let item =
Item::from_subcommand_variant(variant, item.casing(), item.env_casing());
(variant, item)
Item::from_subcommand_variant(variant, item.casing(), item.env_casing())?;
Ok((variant, item))
})
.collect::<Vec<_>>();
.collect::<Result<Vec<_>, syn::Error>>()?;
gen_for_enum(&item, ident, &input.generics, &variants)
}
_ => abort_call_site!("`#[derive(Parser)]` only supports non-tuple structs and enums"),
@ -93,18 +85,18 @@ fn gen_for_struct(
item_name: &Ident,
generics: &Generics,
fields: &[(&Field, Item)],
) -> TokenStream {
) -> Result<TokenStream, syn::Error> {
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let into_app = into_app::gen_for_struct(item, item_name, generics);
let args = args::gen_for_struct(item, item_name, generics, fields);
let into_app = into_app::gen_for_struct(item, item_name, generics)?;
let args = args::gen_for_struct(item, item_name, generics, fields)?;
quote! {
Ok(quote! {
impl #impl_generics clap::Parser for #item_name #ty_generics #where_clause {}
#into_app
#args
}
})
}
fn gen_for_enum(
@ -112,16 +104,16 @@ fn gen_for_enum(
item_name: &Ident,
generics: &Generics,
variants: &[(&Variant, Item)],
) -> TokenStream {
) -> Result<TokenStream, syn::Error> {
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let into_app = into_app::gen_for_enum(item, item_name, generics);
let subcommand = subcommand::gen_for_enum(item, item_name, generics, variants);
let into_app = into_app::gen_for_enum(item, item_name, generics)?;
let subcommand = subcommand::gen_for_enum(item, item_name, generics, variants)?;
quote! {
Ok(quote! {
impl #impl_generics clap::Parser for #item_name #ty_generics #where_clause {}
#into_app
#subcommand
}
})
}

View File

@ -13,33 +13,29 @@
// MIT/Apache 2.0 license.
use proc_macro2::{Ident, Span, TokenStream};
use proc_macro_error::{abort, abort_call_site};
use quote::{format_ident, quote, quote_spanned};
use syn::{spanned::Spanned, Data, DeriveInput, FieldsUnnamed, Generics, Variant};
use crate::derives::args;
use crate::dummies;
use crate::item::{Item, Kind, Name};
use crate::utils::{is_simple_ty, subty_if_name};
pub fn derive_subcommand(input: &DeriveInput) -> TokenStream {
pub fn derive_subcommand(input: &DeriveInput) -> Result<TokenStream, syn::Error> {
let ident = &input.ident;
dummies::subcommand(ident);
match input.data {
Data::Enum(ref e) => {
let name = Name::Derived(ident.clone());
let item = Item::from_subcommand_enum(input, name);
let item = Item::from_subcommand_enum(input, name)?;
let variants = e
.variants
.iter()
.map(|variant| {
let item =
Item::from_subcommand_variant(variant, item.casing(), item.env_casing());
(variant, item)
Item::from_subcommand_variant(variant, item.casing(), item.env_casing())?;
Ok((variant, item))
})
.collect::<Vec<_>>();
.collect::<Result<Vec<_>, syn::Error>>()?;
gen_for_enum(&item, ident, &input.generics, &variants)
}
_ => abort_call_site!("`#[derive(Subcommand)]` only supports enums"),
@ -51,7 +47,7 @@ pub fn gen_for_enum(
item_name: &Ident,
generics: &Generics,
variants: &[(&Variant, Item)],
) -> TokenStream {
) -> Result<TokenStream, syn::Error> {
if !matches!(&*item.kind(), Kind::Command(_)) {
abort! { item.kind().span(),
"`{}` cannot be used with `command`",
@ -61,14 +57,14 @@ pub fn gen_for_enum(
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let from_arg_matches = gen_from_arg_matches(variants);
let update_from_arg_matches = gen_update_from_arg_matches(variants);
let from_arg_matches = gen_from_arg_matches(variants)?;
let update_from_arg_matches = gen_update_from_arg_matches(variants)?;
let augmentation = gen_augment(variants, item, false);
let augmentation_update = gen_augment(variants, item, true);
let has_subcommand = gen_has_subcommand(variants);
let augmentation = gen_augment(variants, item, false)?;
let augmentation_update = gen_augment(variants, item, true)?;
let has_subcommand = gen_has_subcommand(variants)?;
quote! {
Ok(quote! {
#[allow(dead_code, unreachable_code, unused_variables, unused_braces)]
#[allow(
clippy::style,
@ -80,8 +76,8 @@ pub fn gen_for_enum(
clippy::nursery,
clippy::cargo,
clippy::suspicious_else_formatting,
clippy::almost_swapped,
)]
#[deny(clippy::correctness)]
impl #impl_generics clap::FromArgMatches for #item_name #ty_generics #where_clause {
fn from_arg_matches(__clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
Self::from_arg_matches_mut(&mut __clap_arg_matches.clone())
@ -106,8 +102,8 @@ pub fn gen_for_enum(
clippy::nursery,
clippy::cargo,
clippy::suspicious_else_formatting,
clippy::almost_swapped,
)]
#[deny(clippy::correctness)]
impl #impl_generics clap::Subcommand for #item_name #ty_generics #where_clause {
fn augment_subcommands <'b>(__clap_app: clap::Command) -> clap::Command {
#augmentation
@ -119,225 +115,222 @@ pub fn gen_for_enum(
#has_subcommand
}
}
}
})
}
fn gen_augment(
variants: &[(&Variant, Item)],
parent_item: &Item,
override_required: bool,
) -> TokenStream {
) -> Result<TokenStream, syn::Error> {
use syn::Fields::*;
let app_var = Ident::new("__clap_app", Span::call_site());
let subcommands: Vec<_> = variants
.iter()
.filter_map(|(variant, item)| {
let kind = item.kind();
let mut subcommands = Vec::new();
for (variant, item) in variants {
let kind = item.kind();
match &*kind {
Kind::Skip(_, _) |
Kind::Arg(_) |
Kind::FromGlobal(_) |
Kind::Value => None,
let genned = match &*kind {
Kind::Skip(_, _) | Kind::Arg(_) | Kind::FromGlobal(_) | Kind::Value => None,
Kind::ExternalSubcommand => {
let ty = match variant.fields {
Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty,
Kind::ExternalSubcommand => {
let ty = match variant.fields {
Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty,
_ => abort!(
variant,
"The enum variant marked with `external_subcommand` must be \
a single-typed tuple, and the type must be either `Vec<String>` \
or `Vec<OsString>`."
),
};
let deprecations = if !override_required {
item.deprecations()
} else {
quote!()
};
let subty = subty_if_name(ty, "Vec").unwrap_or_else(|| {
abort!(
ty.span(),
"The type must be `Vec<_>` \
to be used with `external_subcommand`."
)
});
let subcommand = quote_spanned! { kind.span()=>
#deprecations
let #app_var = #app_var
.external_subcommand_value_parser(clap::value_parser!(#subty));
};
Some(subcommand)
}
Kind::Flatten(_) => match variant.fields {
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
let ty = &unnamed[0];
let deprecations = if !override_required {
item.deprecations()
} else {
quote!()
};
let next_help_heading = item.next_help_heading();
let next_display_order = item.next_display_order();
let subcommand = if override_required {
quote! {
#deprecations
let #app_var = #app_var
#next_help_heading
#next_display_order;
let #app_var = <#ty as clap::Subcommand>::augment_subcommands_for_update(#app_var);
}
} else {
quote! {
#deprecations
let #app_var = #app_var
#next_help_heading
#next_display_order;
let #app_var = <#ty as clap::Subcommand>::augment_subcommands(#app_var);
}
};
Some(subcommand)
}
_ => abort!(
variant,
"`flatten` is usable only with single-typed tuple variants"
"The enum variant marked with `external_subcommand` must be \
a single-typed tuple, and the type must be either `Vec<String>` \
or `Vec<OsString>`."
),
},
};
let deprecations = if !override_required {
item.deprecations()
} else {
quote!()
};
let subty = subty_if_name(ty, "Vec").ok_or_else(|| {
format_err!(
ty.span(),
"The type must be `Vec<_>` \
to be used with `external_subcommand`."
)
})?;
let subcommand = quote_spanned! { kind.span()=>
#deprecations
let #app_var = #app_var
.external_subcommand_value_parser(clap::value_parser!(#subty));
};
Some(subcommand)
}
Kind::Subcommand(_) => {
let subcommand_var = Ident::new("__clap_subcommand", Span::call_site());
let arg_block = match variant.fields {
Named(_) => {
abort!(variant, "non single-typed tuple enums are not supported")
}
Unit => quote!( #subcommand_var ),
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
let ty = &unnamed[0];
if override_required {
quote_spanned! { ty.span()=>
{
<#ty as clap::Subcommand>::augment_subcommands_for_update(#subcommand_var)
}
}
} else {
quote_spanned! { ty.span()=>
{
<#ty as clap::Subcommand>::augment_subcommands(#subcommand_var)
}
}
}
}
Unnamed(..) => {
abort!(variant, "non single-typed tuple enums are not supported")
}
};
let name = item.cased_name();
Kind::Flatten(_) => match variant.fields {
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
let ty = &unnamed[0];
let deprecations = if !override_required {
item.deprecations()
} else {
quote!()
};
let initial_app_methods = item.initial_top_level_methods();
let final_from_attrs = item.final_top_level_methods();
let override_methods = if override_required {
quote_spanned! { kind.span()=>
.subcommand_required(false)
.arg_required_else_help(false)
let next_help_heading = item.next_help_heading();
let next_display_order = item.next_display_order();
let subcommand = if override_required {
quote! {
#deprecations
let #app_var = #app_var
#next_help_heading
#next_display_order;
let #app_var = <#ty as clap::Subcommand>::augment_subcommands_for_update(#app_var);
}
} else {
quote!()
quote! {
#deprecations
let #app_var = #app_var
#next_help_heading
#next_display_order;
let #app_var = <#ty as clap::Subcommand>::augment_subcommands(#app_var);
}
};
let subcommand = quote! {
let #app_var = #app_var.subcommand({
#deprecations;
let #subcommand_var = clap::Command::new(#name);
let #subcommand_var = #subcommand_var
.subcommand_required(true)
.arg_required_else_help(true);
Some(subcommand)
}
_ => abort!(
variant,
"`flatten` is usable only with single-typed tuple variants"
),
},
Kind::Subcommand(_) => {
let subcommand_var = Ident::new("__clap_subcommand", Span::call_site());
let arg_block = match variant.fields {
Named(_) => {
abort!(variant, "non single-typed tuple enums are not supported")
}
Unit => quote!( #subcommand_var ),
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
let ty = &unnamed[0];
if override_required {
quote_spanned! { ty.span()=>
{
<#ty as clap::Subcommand>::augment_subcommands_for_update(#subcommand_var)
}
}
} else {
quote_spanned! { ty.span()=>
{
<#ty as clap::Subcommand>::augment_subcommands(#subcommand_var)
}
}
}
}
Unnamed(..) => {
abort!(variant, "non single-typed tuple enums are not supported")
}
};
let name = item.cased_name();
let deprecations = if !override_required {
item.deprecations()
} else {
quote!()
};
let initial_app_methods = item.initial_top_level_methods();
let final_from_attrs = item.final_top_level_methods();
let override_methods = if override_required {
quote_spanned! { kind.span()=>
.subcommand_required(false)
.arg_required_else_help(false)
}
} else {
quote!()
};
let subcommand = quote! {
let #app_var = #app_var.subcommand({
#deprecations;
let #subcommand_var = clap::Command::new(#name);
let #subcommand_var = #subcommand_var
.subcommand_required(true)
.arg_required_else_help(true);
let #subcommand_var = #subcommand_var #initial_app_methods;
let #subcommand_var = #arg_block;
#subcommand_var #final_from_attrs #override_methods
});
};
Some(subcommand)
}
Kind::Command(_) => {
let subcommand_var = Ident::new("__clap_subcommand", Span::call_site());
let sub_augment = match variant.fields {
Named(ref fields) => {
// Defer to `gen_augment` for adding cmd methods
let fields = fields
.named
.iter()
.map(|field| {
let item =
Item::from_args_field(field, item.casing(), item.env_casing())?;
Ok((field, item))
})
.collect::<Result<Vec<_>, syn::Error>>()?;
args::gen_augment(&fields, &subcommand_var, item, override_required)?
}
Unit => {
let arg_block = quote!( #subcommand_var );
let initial_app_methods = item.initial_top_level_methods();
let final_from_attrs = item.final_top_level_methods();
quote! {
let #subcommand_var = #subcommand_var #initial_app_methods;
let #subcommand_var = #arg_block;
#subcommand_var #final_from_attrs #override_methods
});
};
Some(subcommand)
}
Kind::Command(_) => {
let subcommand_var = Ident::new("__clap_subcommand", Span::call_site());
let sub_augment = match variant.fields {
Named(ref fields) => {
// Defer to `gen_augment` for adding cmd methods
let fields = fields
.named
.iter()
.map(|field| {
let item = Item::from_args_field(field, item.casing(), item.env_casing());
(field, item)
})
.collect::<Vec<_>>();
args::gen_augment(&fields, &subcommand_var, item, override_required)
#subcommand_var #final_from_attrs
}
Unit => {
let arg_block = quote!( #subcommand_var );
let initial_app_methods = item.initial_top_level_methods();
let final_from_attrs = item.final_top_level_methods();
quote! {
let #subcommand_var = #subcommand_var #initial_app_methods;
let #subcommand_var = #arg_block;
#subcommand_var #final_from_attrs
}
},
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
let ty = &unnamed[0];
let arg_block = if override_required {
quote_spanned! { ty.span()=>
{
<#ty as clap::Args>::augment_args_for_update(#subcommand_var)
}
}
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
let ty = &unnamed[0];
let arg_block = if override_required {
quote_spanned! { ty.span()=>
{
<#ty as clap::Args>::augment_args_for_update(#subcommand_var)
}
} else {
quote_spanned! { ty.span()=>
{
<#ty as clap::Args>::augment_args(#subcommand_var)
}
}
};
let initial_app_methods = item.initial_top_level_methods();
let final_from_attrs = item.final_top_level_methods();
quote! {
let #subcommand_var = #subcommand_var #initial_app_methods;
let #subcommand_var = #arg_block;
#subcommand_var #final_from_attrs
}
} else {
quote_spanned! { ty.span()=>
{
<#ty as clap::Args>::augment_args(#subcommand_var)
}
}
};
let initial_app_methods = item.initial_top_level_methods();
let final_from_attrs = item.final_top_level_methods();
quote! {
let #subcommand_var = #subcommand_var #initial_app_methods;
let #subcommand_var = #arg_block;
#subcommand_var #final_from_attrs
}
Unnamed(..) => {
abort!(variant, "non single-typed tuple enums are not supported")
}
};
}
Unnamed(..) => {
abort!(variant, "non single-typed tuple enums are not supported")
}
};
let deprecations = if !override_required {
item.deprecations()
} else {
quote!()
};
let name = item.cased_name();
let subcommand = quote! {
let #app_var = #app_var.subcommand({
#deprecations
let #subcommand_var = clap::Command::new(#name);
#sub_augment
});
};
Some(subcommand)
}
let deprecations = if !override_required {
item.deprecations()
} else {
quote!()
};
let name = item.cased_name();
let subcommand = quote! {
let #app_var = #app_var.subcommand({
#deprecations
let #subcommand_var = clap::Command::new(#name);
#sub_augment
});
};
Some(subcommand)
}
})
.collect();
};
subcommands.push(genned);
}
let deprecations = if !override_required {
parent_item.deprecations()
@ -346,15 +339,15 @@ fn gen_augment(
};
let initial_app_methods = parent_item.initial_top_level_methods();
let final_app_methods = parent_item.final_top_level_methods();
quote! {
Ok(quote! {
#deprecations;
let #app_var = #app_var #initial_app_methods;
#( #subcommands )*;
#app_var #final_app_methods
}
})
}
fn gen_has_subcommand(variants: &[(&Variant, Item)]) -> TokenStream {
fn gen_has_subcommand(variants: &[(&Variant, Item)]) -> Result<TokenStream, syn::Error> {
use syn::Fields::*;
let mut ext_subcmd = false;
@ -391,19 +384,20 @@ fn gen_has_subcommand(variants: &[(&Variant, Item)]) -> TokenStream {
.map(|(variant, _attrs)| match variant.fields {
Unnamed(ref fields) if fields.unnamed.len() == 1 => {
let ty = &fields.unnamed[0];
quote! {
Ok(quote! {
if <#ty as clap::Subcommand>::has_subcommand(__clap_name) {
return true;
}
}
})
}
_ => abort!(
variant,
"`flatten` is usable only with single-typed tuple variants"
),
});
})
.collect::<Result<Vec<_>, syn::Error>>()?;
if ext_subcmd {
let genned = if ext_subcmd {
quote! { true }
} else {
quote! {
@ -413,77 +407,79 @@ fn gen_has_subcommand(variants: &[(&Variant, Item)]) -> TokenStream {
false
}
}
};
Ok(genned)
}
fn gen_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream {
fn gen_from_arg_matches(variants: &[(&Variant, Item)]) -> Result<TokenStream, syn::Error> {
use syn::Fields::*;
let mut ext_subcmd = None;
let subcommand_name_var = format_ident!("__clap_name");
let sub_arg_matches_var = format_ident!("__clap_arg_matches");
let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
.iter()
.filter_map(|(variant, item)| {
let kind = item.kind();
match &*kind {
Kind::Skip(_, _) | Kind::Arg(_) | Kind::FromGlobal(_) | Kind::Value => None,
Kind::ExternalSubcommand => {
if ext_subcmd.is_some() {
abort!(
item.kind().span(),
"Only one variant can be marked with `external_subcommand`, \
let mut ext_subcmd = None;
let mut flatten_variants = Vec::new();
let mut unflatten_variants = Vec::new();
for (variant, item) in variants {
let kind = item.kind();
match &*kind {
Kind::Skip(_, _) | Kind::Arg(_) | Kind::FromGlobal(_) | Kind::Value => {}
Kind::ExternalSubcommand => {
if ext_subcmd.is_some() {
abort!(
item.kind().span(),
"Only one variant can be marked with `external_subcommand`, \
this is the second"
);
}
);
}
let ty = match variant.fields {
Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty,
let ty = match variant.fields {
Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty,
_ => abort!(
variant,
"The enum variant marked with `external_subcommand` must be \
_ => abort!(
variant,
"The enum variant marked with `external_subcommand` must be \
a single-typed tuple, and the type must be either `Vec<String>` \
or `Vec<OsString>`."
),
};
),
};
let (span, str_ty) = match subty_if_name(ty, "Vec") {
Some(subty) => {
if is_simple_ty(subty, "String") {
(subty.span(), quote!(::std::string::String))
} else if is_simple_ty(subty, "OsString") {
(subty.span(), quote!(::std::ffi::OsString))
} else {
abort!(
ty.span(),
"The type must be either `Vec<String>` or `Vec<OsString>` \
let (span, str_ty) = match subty_if_name(ty, "Vec") {
Some(subty) => {
if is_simple_ty(subty, "String") {
(subty.span(), quote!(::std::string::String))
} else if is_simple_ty(subty, "OsString") {
(subty.span(), quote!(::std::ffi::OsString))
} else {
abort!(
ty.span(),
"The type must be either `Vec<String>` or `Vec<OsString>` \
to be used with `external_subcommand`."
);
}
);
}
}
None => abort!(
ty.span(),
"The type must be either `Vec<String>` or `Vec<OsString>` \
None => abort!(
ty.span(),
"The type must be either `Vec<String>` or `Vec<OsString>` \
to be used with `external_subcommand`."
),
};
),
};
ext_subcmd = Some((span, &variant.ident, str_ty));
None
}
Kind::Flatten(_) | Kind::Subcommand(_) | Kind::Command(_) => Some((variant, item)),
ext_subcmd = Some((span, &variant.ident, str_ty));
}
})
.partition(|(_, item)| {
let kind = item.kind();
matches!(&*kind, Kind::Flatten(_))
});
Kind::Flatten(_) | Kind::Subcommand(_) | Kind::Command(_) => {
if matches!(&*item.kind(), Kind::Flatten(_)) {
flatten_variants.push((variant, item));
} else {
unflatten_variants.push((variant, item));
}
}
}
}
let subcommands = variants.iter().map(|(variant, item)| {
let subcommands = unflatten_variants.iter().map(|(variant, item)| {
let sub_name = item.cased_name();
let variant_name = &variant.ident;
let constructor_block = match variant.fields {
@ -492,11 +488,11 @@ fn gen_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream {
.named
.iter()
.map(|field| {
let item = Item::from_args_field(field, item.casing(), item.env_casing());
(field, item)
let item = Item::from_args_field(field, item.casing(), item.env_casing())?;
Ok((field, item))
})
.collect::<Vec<_>>();
args::gen_constructor(&fields)
.collect::<Result<Vec<_>, syn::Error>>()?;
args::gen_constructor(&fields)?
},
Unit => quote!(),
Unnamed(ref fields) if fields.unnamed.len() == 1 => {
@ -506,18 +502,18 @@ fn gen_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream {
Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident),
};
quote! {
Ok(quote! {
if #subcommand_name_var == #sub_name && !#sub_arg_matches_var.contains_id("") {
return ::std::result::Result::Ok(Self :: #variant_name #constructor_block)
}
}
});
})
}).collect::<Result<Vec<_>, syn::Error>>()?;
let child_subcommands = flatten_variants.iter().map(|(variant, _attrs)| {
let variant_name = &variant.ident;
match variant.fields {
Unnamed(ref fields) if fields.unnamed.len() == 1 => {
let ty = &fields.unnamed[0];
quote! {
Ok(quote! {
if __clap_arg_matches
.subcommand_name()
.map(|__clap_name| <#ty as clap::Subcommand>::has_subcommand(__clap_name))
@ -526,14 +522,14 @@ fn gen_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream {
let __clap_res = <#ty as clap::FromArgMatches>::from_arg_matches_mut(__clap_arg_matches)?;
return ::std::result::Result::Ok(Self :: #variant_name (__clap_res));
}
}
})
}
_ => abort!(
variant,
"`flatten` is usable only with single-typed tuple variants"
),
}
});
}).collect::<Result<Vec<_>, syn::Error>>()?;
let wildcard = match ext_subcmd {
Some((span, var_name, str_ty)) => quote_spanned! { span=>
@ -555,7 +551,7 @@ fn gen_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream {
};
let raw_deprecated = args::raw_deprecated();
quote! {
Ok(quote! {
fn from_arg_matches_mut(__clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
#raw_deprecated
@ -570,10 +566,10 @@ fn gen_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream {
::std::result::Result::Err(clap::Error::raw(clap::error::ErrorKind::MissingSubcommand, "A subcommand is required but one was not provided."))
}
}
}
})
}
fn gen_update_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream {
fn gen_update_from_arg_matches(variants: &[(&Variant, Item)]) -> Result<TokenStream, syn::Error> {
use syn::Fields::*;
let (flatten, variants): (Vec<_>, Vec<_>) = variants
@ -607,11 +603,11 @@ fn gen_update_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream {
.named
.iter()
.map(|field| {
let item = Item::from_args_field(field, item.casing(), item.env_casing());
(field, item)
let item = Item::from_args_field(field, item.casing(), item.env_casing())?;
Ok((field, item))
})
.collect::<Vec<_>>();
let update = args::gen_updater(&fields, false);
.collect::<Result<Vec<_>, syn::Error>>()?;
let update = args::gen_updater(&fields, false)?;
(quote!( { #( #field_names, )* }), quote!( { #update } ))
}
Unit => (quote!(), quote!({})),
@ -630,38 +626,38 @@ fn gen_update_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream {
}
};
quote! {
Ok(quote! {
Self :: #variant_name #pattern if #sub_name == __clap_name => {
let (_, mut __clap_arg_sub_matches) = __clap_arg_matches.remove_subcommand().unwrap();
let __clap_arg_matches = &mut __clap_arg_sub_matches;
#updater
}
}
});
})
}).collect::<Result<Vec<_>, _>>()?;
let child_subcommands = flatten.iter().map(|(variant, _attrs)| {
let variant_name = &variant.ident;
match variant.fields {
Unnamed(ref fields) if fields.unnamed.len() == 1 => {
let ty = &fields.unnamed[0];
quote! {
Ok(quote! {
if <#ty as clap::Subcommand>::has_subcommand(__clap_name) {
if let Self :: #variant_name (child) = s {
<#ty as clap::FromArgMatches>::update_from_arg_matches_mut(child, __clap_arg_matches)?;
return ::std::result::Result::Ok(());
}
}
}
})
}
_ => abort!(
variant,
"`flatten` is usable only with single-typed tuple variants"
),
}
});
}).collect::<Result<Vec<_>, _>>()?;
let raw_deprecated = args::raw_deprecated();
quote! {
Ok(quote! {
fn update_from_arg_matches_mut<'b>(
&mut self,
__clap_arg_matches: &mut clap::ArgMatches,
@ -679,5 +675,5 @@ fn gen_update_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream {
}
::std::result::Result::Ok(())
}
}
})
}

View File

@ -9,39 +9,36 @@
// except according to those terms.
use proc_macro2::TokenStream;
use proc_macro_error::{abort, abort_call_site};
use quote::quote;
use quote::quote_spanned;
use syn::{spanned::Spanned, Data, DeriveInput, Fields, Ident, Variant};
use crate::dummies;
use crate::item::{Item, Kind, Name};
pub fn derive_value_enum(input: &DeriveInput) -> TokenStream {
pub fn derive_value_enum(input: &DeriveInput) -> Result<TokenStream, syn::Error> {
let ident = &input.ident;
dummies::value_enum(ident);
match input.data {
Data::Enum(ref e) => {
let name = Name::Derived(ident.clone());
let item = Item::from_value_enum(input, name);
let variants = e
.variants
.iter()
.map(|variant| {
let item =
Item::from_value_enum_variant(variant, item.casing(), item.env_casing());
(variant, item)
})
.collect::<Vec<_>>();
let item = Item::from_value_enum(input, name)?;
let mut variants = Vec::new();
for variant in &e.variants {
let item =
Item::from_value_enum_variant(variant, item.casing(), item.env_casing())?;
variants.push((variant, item));
}
gen_for_enum(&item, ident, &variants)
}
_ => abort_call_site!("`#[derive(ValueEnum)]` only supports enums"),
}
}
pub fn gen_for_enum(item: &Item, item_name: &Ident, variants: &[(&Variant, Item)]) -> TokenStream {
pub fn gen_for_enum(
item: &Item,
item_name: &Ident,
variants: &[(&Variant, Item)],
) -> Result<TokenStream, syn::Error> {
if !matches!(&*item.kind(), Kind::Value) {
abort! { item.kind().span(),
"`{}` cannot be used with `value`",
@ -49,11 +46,11 @@ pub fn gen_for_enum(item: &Item, item_name: &Ident, variants: &[(&Variant, Item)
}
}
let lits = lits(variants);
let lits = lits(variants)?;
let value_variants = gen_value_variants(&lits);
let to_possible_value = gen_to_possible_value(item, &lits);
quote! {
Ok(quote! {
#[allow(dead_code, unreachable_code, unused_variables, unused_braces)]
#[allow(
clippy::style,
@ -65,39 +62,37 @@ pub fn gen_for_enum(item: &Item, item_name: &Ident, variants: &[(&Variant, Item)
clippy::nursery,
clippy::cargo,
clippy::suspicious_else_formatting,
clippy::almost_swapped,
)]
#[deny(clippy::correctness)]
impl clap::ValueEnum for #item_name {
#value_variants
#to_possible_value
}
}
})
}
fn lits(variants: &[(&Variant, Item)]) -> Vec<(TokenStream, Ident)> {
variants
.iter()
.filter_map(|(variant, item)| {
if let Kind::Skip(_, _) = &*item.kind() {
None
} else {
if !matches!(variant.fields, Fields::Unit) {
abort!(variant.span(), "`#[derive(ValueEnum)]` only supports unit variants. Non-unit variants must be skipped");
}
let fields = item.field_methods();
let deprecations = item.deprecations();
let name = item.cased_name();
Some((
quote_spanned! { variant.span()=> {
#deprecations
clap::builder::PossibleValue::new(#name)
#fields
}},
variant.ident.clone(),
))
}
})
.collect::<Vec<_>>()
fn lits(variants: &[(&Variant, Item)]) -> Result<Vec<(TokenStream, Ident)>, syn::Error> {
let mut genned = Vec::new();
for (variant, item) in variants {
if let Kind::Skip(_, _) = &*item.kind() {
continue;
}
if !matches!(variant.fields, Fields::Unit) {
abort!(variant.span(), "`#[derive(ValueEnum)]` only supports unit variants. Non-unit variants must be skipped");
}
let fields = item.field_methods();
let deprecations = item.deprecations();
let name = item.cased_name();
genned.push((
quote_spanned! { variant.span()=> {
#deprecations
clap::builder::PossibleValue::new(#name)
#fields
}},
variant.ident.clone(),
));
}
Ok(genned)
}
fn gen_value_variants(lits: &[(TokenStream, Ident)]) -> TokenStream {

View File

@ -1,23 +1,20 @@
//! Dummy implementations that we emit along with an error.
use proc_macro2::Ident;
use proc_macro_error::append_dummy;
use quote::quote;
pub fn parser_struct(name: &Ident) {
into_app(name);
args(name);
append_dummy(quote!( impl clap::Parser for #name {} ));
#[must_use]
pub fn parser(name: &Ident) -> proc_macro2::TokenStream {
let into_app = into_app(name);
quote!(
impl clap::Parser for #name {}
#into_app
)
}
pub fn parser_enum(name: &Ident) {
into_app(name);
subcommand(name);
append_dummy(quote!( impl clap::Parser for #name {} ));
}
pub fn into_app(name: &Ident) {
append_dummy(quote! {
#[must_use]
pub fn into_app(name: &Ident) -> proc_macro2::TokenStream {
quote! {
impl clap::CommandFactory for #name {
fn command<'b>() -> clap::Command {
unimplemented!()
@ -26,11 +23,12 @@ pub fn into_app(name: &Ident) {
unimplemented!()
}
}
});
}
}
pub fn from_arg_matches(name: &Ident) {
append_dummy(quote! {
#[must_use]
pub fn from_arg_matches(name: &Ident) -> proc_macro2::TokenStream {
quote! {
impl clap::FromArgMatches for #name {
fn from_arg_matches(_m: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
unimplemented!()
@ -39,12 +37,13 @@ pub fn from_arg_matches(name: &Ident) {
unimplemented!()
}
}
});
}
}
pub fn subcommand(name: &Ident) {
from_arg_matches(name);
append_dummy(quote! {
#[must_use]
pub fn subcommand(name: &Ident) -> proc_macro2::TokenStream {
let from_arg_matches = from_arg_matches(name);
quote! {
impl clap::Subcommand for #name {
fn augment_subcommands(_cmd: clap::Command) -> clap::Command {
unimplemented!()
@ -56,12 +55,14 @@ pub fn subcommand(name: &Ident) {
unimplemented!()
}
}
});
#from_arg_matches
}
}
pub fn args(name: &Ident) {
from_arg_matches(name);
append_dummy(quote! {
#[must_use]
pub fn args(name: &Ident) -> proc_macro2::TokenStream {
let from_arg_matches = from_arg_matches(name);
quote! {
impl clap::Args for #name {
fn augment_args(_cmd: clap::Command) -> clap::Command {
unimplemented!()
@ -70,11 +71,13 @@ pub fn args(name: &Ident) {
unimplemented!()
}
}
});
#from_arg_matches
}
}
pub fn value_enum(name: &Ident) {
append_dummy(quote! {
#[must_use]
pub fn value_enum(name: &Ident) -> proc_macro2::TokenStream {
quote! {
impl clap::ValueEnum for #name {
fn value_variants<'a>() -> &'a [Self]{
unimplemented!()
@ -86,5 +89,5 @@ pub fn value_enum(name: &Ident) {
unimplemented!()
}
}
})
}
}

View File

@ -16,7 +16,6 @@ use std::env;
use heck::{ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
use proc_macro2::{self, Span, TokenStream};
use proc_macro_error::abort;
use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::DeriveInput;
use syn::{self, ext::IdentExt, spanned::Spanned, Attribute, Field, Ident, LitStr, Type, Variant};
@ -53,7 +52,7 @@ pub struct Item {
}
impl Item {
pub fn from_args_struct(input: &DeriveInput, name: Name) -> Self {
pub fn from_args_struct(input: &DeriveInput, name: Name) -> Result<Self, syn::Error> {
let ident = input.ident.clone();
let span = input.ident.span();
let attrs = &input.attrs;
@ -62,15 +61,15 @@ impl Item {
let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
let parsed_attrs = ClapAttr::parse_all(attrs);
res.infer_kind(&parsed_attrs);
res.push_attrs(&parsed_attrs);
let parsed_attrs = ClapAttr::parse_all(attrs)?;
res.infer_kind(&parsed_attrs)?;
res.push_attrs(&parsed_attrs)?;
res.push_doc_comment(attrs, "about", Some("long_about"));
res
Ok(res)
}
pub fn from_subcommand_enum(input: &DeriveInput, name: Name) -> Self {
pub fn from_subcommand_enum(input: &DeriveInput, name: Name) -> Result<Self, syn::Error> {
let ident = input.ident.clone();
let span = input.ident.span();
let attrs = &input.attrs;
@ -79,15 +78,15 @@ impl Item {
let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
let parsed_attrs = ClapAttr::parse_all(attrs);
res.infer_kind(&parsed_attrs);
res.push_attrs(&parsed_attrs);
let parsed_attrs = ClapAttr::parse_all(attrs)?;
res.infer_kind(&parsed_attrs)?;
res.push_attrs(&parsed_attrs)?;
res.push_doc_comment(attrs, "about", Some("long_about"));
res
Ok(res)
}
pub fn from_value_enum(input: &DeriveInput, name: Name) -> Self {
pub fn from_value_enum(input: &DeriveInput, name: Name) -> Result<Self, syn::Error> {
let ident = input.ident.clone();
let span = input.ident.span();
let attrs = &input.attrs;
@ -96,9 +95,9 @@ impl Item {
let kind = Sp::new(Kind::Value, span);
let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
let parsed_attrs = ClapAttr::parse_all(attrs);
res.infer_kind(&parsed_attrs);
res.push_attrs(&parsed_attrs);
let parsed_attrs = ClapAttr::parse_all(attrs)?;
res.infer_kind(&parsed_attrs)?;
res.push_attrs(&parsed_attrs)?;
// Ignoring `push_doc_comment` as there is no top-level clap builder to add documentation
// to
@ -110,14 +109,14 @@ impl Item {
);
}
res
Ok(res)
}
pub fn from_subcommand_variant(
variant: &Variant,
struct_casing: Sp<CasingStyle>,
env_casing: Sp<CasingStyle>,
) -> Self {
) -> Result<Self, syn::Error> {
let name = variant.ident.clone();
let ident = variant.ident.clone();
let span = variant.span();
@ -138,9 +137,9 @@ impl Item {
env_casing,
kind,
);
let parsed_attrs = ClapAttr::parse_all(&variant.attrs);
res.infer_kind(&parsed_attrs);
res.push_attrs(&parsed_attrs);
let parsed_attrs = ClapAttr::parse_all(&variant.attrs)?;
res.infer_kind(&parsed_attrs)?;
res.push_attrs(&parsed_attrs)?;
if matches!(&*res.kind, Kind::Command(_) | Kind::Subcommand(_)) {
res.push_doc_comment(&variant.attrs, "about", Some("long_about"));
}
@ -164,14 +163,14 @@ impl Item {
| Kind::Arg(_) => (),
}
res
Ok(res)
}
pub fn from_value_enum_variant(
variant: &Variant,
argument_casing: Sp<CasingStyle>,
env_casing: Sp<CasingStyle>,
) -> Self {
) -> Result<Self, syn::Error> {
let ident = variant.ident.clone();
let span = variant.span();
let kind = Sp::new(Kind::Value, span);
@ -183,21 +182,21 @@ impl Item {
env_casing,
kind,
);
let parsed_attrs = ClapAttr::parse_all(&variant.attrs);
res.infer_kind(&parsed_attrs);
res.push_attrs(&parsed_attrs);
let parsed_attrs = ClapAttr::parse_all(&variant.attrs)?;
res.infer_kind(&parsed_attrs)?;
res.push_attrs(&parsed_attrs)?;
if matches!(&*res.kind, Kind::Value) {
res.push_doc_comment(&variant.attrs, "help", None);
}
res
Ok(res)
}
pub fn from_args_field(
field: &Field,
struct_casing: Sp<CasingStyle>,
env_casing: Sp<CasingStyle>,
) -> Self {
) -> Result<Self, syn::Error> {
let name = field.ident.clone().unwrap();
let ident = field.ident.clone().unwrap();
let span = field.span();
@ -211,9 +210,9 @@ impl Item {
env_casing,
kind,
);
let parsed_attrs = ClapAttr::parse_all(&field.attrs);
res.infer_kind(&parsed_attrs);
res.push_attrs(&parsed_attrs);
let parsed_attrs = ClapAttr::parse_all(&field.attrs)?;
res.infer_kind(&parsed_attrs)?;
res.push_attrs(&parsed_attrs)?;
if matches!(&*res.kind, Kind::Arg(_)) {
res.push_doc_comment(&field.attrs, "help", Some("long_help"));
}
@ -244,7 +243,7 @@ impl Item {
| Kind::ExternalSubcommand => {}
}
res
Ok(res)
}
fn new(
@ -329,7 +328,7 @@ impl Item {
}
}
fn infer_kind(&mut self, attrs: &[ClapAttr]) {
fn infer_kind(&mut self, attrs: &[ClapAttr]) -> Result<(), syn::Error> {
for attr in attrs {
if let Some(AttrValue::Call(_)) = &attr.value {
continue;
@ -339,7 +338,7 @@ impl Item {
let kind = match &attr.magic {
Some(MagicAttrName::FromGlobal) => {
if attr.value.is_some() {
let expr = attr.value_or_abort();
let expr = attr.value_or_abort()?;
abort!(expr, "attribute `{}` does not accept a value", attr.name);
}
let ty = self
@ -352,7 +351,7 @@ impl Item {
}
Some(MagicAttrName::Subcommand) if attr.value.is_none() => {
if attr.value.is_some() {
let expr = attr.value_or_abort();
let expr = attr.value_or_abort()?;
abort!(expr, "attribute `{}` does not accept a value", attr.name);
}
let ty = self
@ -365,7 +364,7 @@ impl Item {
}
Some(MagicAttrName::ExternalSubcommand) if attr.value.is_none() => {
if attr.value.is_some() {
let expr = attr.value_or_abort();
let expr = attr.value_or_abort()?;
abort!(expr, "attribute `{}` does not accept a value", attr.name);
}
let kind = Sp::new(Kind::ExternalSubcommand, attr.name.clone().span());
@ -373,7 +372,7 @@ impl Item {
}
Some(MagicAttrName::Flatten) if attr.value.is_none() => {
if attr.value.is_some() {
let expr = attr.value_or_abort();
let expr = attr.value_or_abort()?;
abort!(expr, "attribute `{}` does not accept a value", attr.name);
}
let ty = self
@ -396,12 +395,14 @@ impl Item {
};
if let Some(kind) = kind {
self.set_kind(kind);
self.set_kind(kind)?;
}
}
Ok(())
}
fn push_attrs(&mut self, attrs: &[ClapAttr]) {
fn push_attrs(&mut self, attrs: &[ClapAttr]) -> Result<(), syn::Error> {
for attr in attrs {
let actual_attr_kind = *attr.kind.get();
let expected_attr_kind = self.kind.attr_kind();
@ -437,7 +438,7 @@ impl Item {
match &attr.magic {
Some(MagicAttrName::Short) if attr.value.is_none() => {
assert_attr_kind(attr, &[AttrKind::Arg]);
assert_attr_kind(attr, &[AttrKind::Arg])?;
self.push_method(
*attr.kind.get(),
@ -447,13 +448,13 @@ impl Item {
}
Some(MagicAttrName::Long) if attr.value.is_none() => {
assert_attr_kind(attr, &[AttrKind::Arg]);
assert_attr_kind(attr, &[AttrKind::Arg])?;
self.push_method(*attr.kind.get(), attr.name.clone(), self.name.clone().translate(*self.casing));
}
Some(MagicAttrName::ValueParser) if attr.value.is_none() => {
assert_attr_kind(attr, &[AttrKind::Arg]);
assert_attr_kind(attr, &[AttrKind::Arg])?;
self.deprecations.push(Deprecation {
span: attr.name.span(),
@ -465,7 +466,7 @@ impl Item {
}
Some(MagicAttrName::Action) if attr.value.is_none() => {
assert_attr_kind(attr, &[AttrKind::Arg]);
assert_attr_kind(attr, &[AttrKind::Arg])?;
self.deprecations.push(Deprecation {
span: attr.name.span(),
@ -477,7 +478,7 @@ impl Item {
}
Some(MagicAttrName::Env) if attr.value.is_none() => {
assert_attr_kind(attr, &[AttrKind::Arg]);
assert_attr_kind(attr, &[AttrKind::Arg])?;
self.push_method(
*attr.kind.get(),
@ -487,7 +488,7 @@ impl Item {
}
Some(MagicAttrName::ValueEnum) if attr.value.is_none() => {
assert_attr_kind(attr, &[AttrKind::Arg]);
assert_attr_kind(attr, &[AttrKind::Arg])?;
self.is_enum = true
}
@ -497,45 +498,45 @@ impl Item {
}
Some(MagicAttrName::About) if attr.value.is_none() => {
assert_attr_kind(attr, &[AttrKind::Command]);
assert_attr_kind(attr, &[AttrKind::Command])?;
if let Some(method) =
Method::from_env(attr.name.clone(), "CARGO_PKG_DESCRIPTION")
Method::from_env(attr.name.clone(), "CARGO_PKG_DESCRIPTION")?
{
self.methods.push(method);
}
}
Some(MagicAttrName::LongAbout) if attr.value.is_none() => {
assert_attr_kind(attr, &[AttrKind::Command]);
assert_attr_kind(attr, &[AttrKind::Command])?;
self.force_long_help = true;
}
Some(MagicAttrName::LongHelp) if attr.value.is_none() => {
assert_attr_kind(attr, &[AttrKind::Arg]);
assert_attr_kind(attr, &[AttrKind::Arg])?;
self.force_long_help = true;
}
Some(MagicAttrName::Author) if attr.value.is_none() => {
assert_attr_kind(attr, &[AttrKind::Command]);
assert_attr_kind(attr, &[AttrKind::Command])?;
if let Some(method) = Method::from_env(attr.name.clone(), "CARGO_PKG_AUTHORS") {
if let Some(method) = Method::from_env(attr.name.clone(), "CARGO_PKG_AUTHORS")? {
self.methods.push(method);
}
}
Some(MagicAttrName::Version) if attr.value.is_none() => {
assert_attr_kind(attr, &[AttrKind::Command]);
assert_attr_kind(attr, &[AttrKind::Command])?;
if let Some(method) = Method::from_env(attr.name.clone(), "CARGO_PKG_VERSION") {
if let Some(method) = Method::from_env(attr.name.clone(), "CARGO_PKG_VERSION")? {
self.methods.push(method);
}
}
Some(MagicAttrName::DefaultValueT) => {
assert_attr_kind(attr, &[AttrKind::Arg]);
assert_attr_kind(attr, &[AttrKind::Arg])?;
let ty = if let Some(ty) = self.ty.as_ref() {
ty
@ -543,7 +544,7 @@ impl Item {
abort!(
attr.name.clone(),
"#[arg(default_value_t)] (without an argument) can be used \
only on field level";
only on field level\n\n= note: {note}\n\n",
note = "see \
https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
@ -583,7 +584,7 @@ impl Item {
}
Some(MagicAttrName::DefaultValuesT) => {
assert_attr_kind(attr, &[AttrKind::Arg]);
assert_attr_kind(attr, &[AttrKind::Arg])?;
let ty = if let Some(ty) = self.ty.as_ref() {
ty
@ -591,18 +592,18 @@ impl Item {
abort!(
attr.name.clone(),
"#[arg(default_values_t)] (without an argument) can be used \
only on field level";
only on field level\n\n= note: {note}\n\n",
note = "see \
https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
};
let expr = attr.value_or_abort();
let expr = attr.value_or_abort()?;
let container_type = Ty::from_syn_ty(ty);
if *container_type != Ty::Vec {
abort!(
attr.name.clone(),
"#[arg(default_values_t)] can be used only on Vec types";
"#[arg(default_values_t)] can be used only on Vec types\n\n= note: {note}\n\n",
note = "see \
https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
@ -667,7 +668,7 @@ impl Item {
}
Some(MagicAttrName::DefaultValueOsT) => {
assert_attr_kind(attr, &[AttrKind::Arg]);
assert_attr_kind(attr, &[AttrKind::Arg])?;
let ty = if let Some(ty) = self.ty.as_ref() {
ty
@ -675,7 +676,7 @@ impl Item {
abort!(
attr.name.clone(),
"#[arg(default_value_os_t)] (without an argument) can be used \
only on field level";
only on field level\n\n= note: {note}\n\n",
note = "see \
https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
@ -715,7 +716,7 @@ impl Item {
}
Some(MagicAttrName::DefaultValuesOsT) => {
assert_attr_kind(attr, &[AttrKind::Arg]);
assert_attr_kind(attr, &[AttrKind::Arg])?;
let ty = if let Some(ty) = self.ty.as_ref() {
ty
@ -723,18 +724,18 @@ impl Item {
abort!(
attr.name.clone(),
"#[arg(default_values_os_t)] (without an argument) can be used \
only on field level";
only on field level\n\n= note: {note}\n\n",
note = "see \
https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
};
let expr = attr.value_or_abort();
let expr = attr.value_or_abort()?;
let container_type = Ty::from_syn_ty(ty);
if *container_type != Ty::Vec {
abort!(
attr.name.clone(),
"#[arg(default_values_os_t)] can be used only on Vec types";
"#[arg(default_values_os_t)] can be used only on Vec types\n\n= note: {note}\n\n",
note = "see \
https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
@ -799,29 +800,29 @@ impl Item {
}
Some(MagicAttrName::NextDisplayOrder) => {
assert_attr_kind(attr, &[AttrKind::Command]);
assert_attr_kind(attr, &[AttrKind::Command])?;
let expr = attr.value_or_abort();
let expr = attr.value_or_abort()?;
self.next_display_order = Some(Method::new(attr.name.clone(), quote!(#expr)));
}
Some(MagicAttrName::NextHelpHeading) => {
assert_attr_kind(attr, &[AttrKind::Command]);
assert_attr_kind(attr, &[AttrKind::Command])?;
let expr = attr.value_or_abort();
let expr = attr.value_or_abort()?;
self.next_help_heading = Some(Method::new(attr.name.clone(), quote!(#expr)));
}
Some(MagicAttrName::RenameAll) => {
let lit = attr.lit_str_or_abort();
self.casing = CasingStyle::from_lit(lit);
let lit = attr.lit_str_or_abort()?;
self.casing = CasingStyle::from_lit(lit)?;
}
Some(MagicAttrName::RenameAllEnv) => {
assert_attr_kind(attr, &[AttrKind::Command, AttrKind::Arg]);
assert_attr_kind(attr, &[AttrKind::Command, AttrKind::Arg])?;
let lit = attr.lit_str_or_abort();
self.env_casing = CasingStyle::from_lit(lit);
let lit = attr.lit_str_or_abort()?;
self.env_casing = CasingStyle::from_lit(lit)?;
}
Some(MagicAttrName::Skip) if actual_attr_kind == AttrKind::Group => {
@ -839,20 +840,20 @@ impl Item {
| Some(MagicAttrName::Author)
| Some(MagicAttrName::Version)
=> {
let expr = attr.value_or_abort();
let expr = attr.value_or_abort()?;
self.push_method(*attr.kind.get(), attr.name.clone(), expr);
}
// Magic only for the default, otherwise just forward to the builder
Some(MagicAttrName::ValueParser) | Some(MagicAttrName::Action) => {
let expr = attr.value_or_abort();
let expr = attr.value_or_abort()?;
self.push_method(*attr.kind.get(), attr.name.clone(), expr);
}
// Directives that never receive a value
Some(MagicAttrName::ValueEnum)
| Some(MagicAttrName::VerbatimDocComment) => {
let expr = attr.value_or_abort();
let expr = attr.value_or_abort()?;
abort!(expr, "attribute `{}` does not accept a value", attr.name);
}
@ -883,6 +884,8 @@ impl Item {
);
}
}
Ok(())
}
fn push_doc_comment(&mut self, attrs: &[Attribute], short_name: &str, long_name: Option<&str>) {
@ -912,7 +915,7 @@ impl Item {
}
}
fn set_kind(&mut self, kind: Sp<Kind>) {
fn set_kind(&mut self, kind: Sp<Kind>) -> Result<(), syn::Error> {
match (self.kind.get(), kind.get()) {
(Kind::Arg(_), Kind::FromGlobal(_))
| (Kind::Arg(_), Kind::Subcommand(_))
@ -932,6 +935,7 @@ impl Item {
abort!(kind.span(), "`{}` cannot be used with `{}`", new, old);
}
}
Ok(())
}
pub fn find_default_method(&self) -> Option<&Method> {
@ -1211,19 +1215,21 @@ impl Method {
Method { name, args }
}
fn from_env(ident: Ident, env_var: &str) -> Option<Self> {
fn from_env(ident: Ident, env_var: &str) -> Result<Option<Self>, syn::Error> {
let mut lit = match env::var(env_var) {
Ok(val) => {
if val.is_empty() {
return None;
return Ok(None);
}
LitStr::new(&val, ident.span())
}
Err(_) => {
abort!(ident,
"cannot derive `{}` from Cargo.toml", ident;
note = "`{}` environment variable is not set", env_var;
help = "use `{} = \"...\"` to set {} manually", ident, ident;
abort!(
ident,
"cannot derive `{}` from Cargo.toml\n\n= note: {note}\n\n= help: {help}\n\n",
ident,
note = format_args!("`{}` environment variable is not set", env_var),
help = format_args!("use `{} = \"...\"` to set {} manually", ident, ident)
);
}
};
@ -1233,7 +1239,7 @@ impl Method {
lit = LitStr::new(&edited, lit.span());
}
Some(Method::new(ident, quote!(#lit)))
Ok(Some(Method::new(ident, quote!(#lit))))
}
pub(crate) fn args(&self) -> &TokenStream {
@ -1299,7 +1305,7 @@ impl ToTokens for Deprecation {
}
}
fn assert_attr_kind(attr: &ClapAttr, possible_kind: &[AttrKind]) {
fn assert_attr_kind(attr: &ClapAttr, possible_kind: &[AttrKind]) -> Result<(), syn::Error> {
if *attr.kind.get() == AttrKind::Clap || *attr.kind.get() == AttrKind::StructOpt {
// deprecated
} else if !possible_kind.contains(attr.kind.get()) {
@ -1315,6 +1321,7 @@ fn assert_attr_kind(attr: &ClapAttr, possible_kind: &[AttrKind]) {
options.join(", ")
);
}
Ok(())
}
/// replace all `:` with `, ` when not inside the `<>`
@ -1364,13 +1371,13 @@ pub enum CasingStyle {
}
impl CasingStyle {
fn from_lit(name: &LitStr) -> Sp<Self> {
fn from_lit(name: &LitStr) -> Result<Sp<Self>, syn::Error> {
use self::CasingStyle::*;
let normalized = name.value().to_upper_camel_case().to_lowercase();
let cs = |kind| Sp::new(kind, name.span());
match normalized.as_ref() {
let s = match normalized.as_ref() {
"camel" | "camelcase" => cs(Camel),
"kebab" | "kebabcase" => cs(Kebab),
"pascal" | "pascalcase" => cs(Pascal),
@ -1380,7 +1387,8 @@ impl CasingStyle {
"upper" | "uppercase" => cs(Upper),
"verbatim" | "verbatimcase" => cs(Verbatim),
s => abort!(name, "unsupported casing: `{}`", s),
}
};
Ok(s)
}
}

View File

@ -19,8 +19,11 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;
use syn::{parse_macro_input, DeriveInput};
use syn::{Data, DataStruct, Fields};
#[macro_use]
mod macros;
mod attr;
mod derives;
@ -30,10 +33,14 @@ mod utils;
/// Generates the `ValueEnum` impl.
#[proc_macro_derive(ValueEnum, attributes(clap, value))]
#[proc_macro_error]
pub fn value_enum(input: TokenStream) -> TokenStream {
let input: DeriveInput = parse_macro_input!(input);
derives::derive_value_enum(&input).into()
derives::derive_value_enum(&input)
.unwrap_or_else(|err| {
let dummy = dummies::value_enum(&input.ident);
to_compile_error(err, dummy)
})
.into()
}
/// Generates the `Parser` implementation.
@ -43,24 +50,67 @@ pub fn value_enum(input: TokenStream) -> TokenStream {
/// implementing a conversion code to instantiate an instance of the user
/// context struct.
#[proc_macro_derive(Parser, attributes(clap, structopt, command, arg, group))]
#[proc_macro_error]
pub fn parser(input: TokenStream) -> TokenStream {
let input: DeriveInput = parse_macro_input!(input);
derives::derive_parser(&input).into()
derives::derive_parser(&input)
.unwrap_or_else(|err| {
let specific_dummy = match input.data {
Data::Struct(DataStruct {
fields: Fields::Named(ref _fields),
..
}) => Some(dummies::args(&input.ident)),
Data::Struct(DataStruct {
fields: Fields::Unit,
..
}) => Some(dummies::args(&input.ident)),
Data::Enum(_) => Some(dummies::subcommand(&input.ident)),
_ => None,
};
let dummy = specific_dummy
.map(|specific_dummy| {
let parser_dummy = dummies::parser(&input.ident);
quote::quote! {
#parser_dummy
#specific_dummy
}
})
.unwrap_or_else(|| quote::quote!());
to_compile_error(err, dummy)
})
.into()
}
/// Generates the `Subcommand` impl.
#[proc_macro_derive(Subcommand, attributes(clap, command, arg, group))]
#[proc_macro_error]
pub fn subcommand(input: TokenStream) -> TokenStream {
let input: DeriveInput = parse_macro_input!(input);
derives::derive_subcommand(&input).into()
derives::derive_subcommand(&input)
.unwrap_or_else(|err| {
let dummy = dummies::subcommand(&input.ident);
to_compile_error(err, dummy)
})
.into()
}
/// Generates the `Args` impl.
#[proc_macro_derive(Args, attributes(clap, command, arg, group))]
#[proc_macro_error]
pub fn args(input: TokenStream) -> TokenStream {
let input: DeriveInput = parse_macro_input!(input);
derives::derive_args(&input).into()
derives::derive_args(&input)
.unwrap_or_else(|err| {
let dummy = dummies::args(&input.ident);
to_compile_error(err, dummy)
})
.into()
}
fn to_compile_error(
error: syn::Error,
dummy: proc_macro2::TokenStream,
) -> proc_macro2::TokenStream {
let compile_errors = error.to_compile_error();
quote::quote!(
#dummy
#compile_errors
)
}

21
clap_derive/src/macros.rs Normal file
View File

@ -0,0 +1,21 @@
macro_rules! format_err {
($obj:expr, $($format:tt)+) => {{
#[allow(unused_imports)]
use $crate::utils::error::*;
let msg = format!($($format)+);
$obj.EXPECTED_Span_OR_ToTokens(msg)
}};
}
macro_rules! abort {
($obj:expr, $($format:tt)+) => {{
return Err(format_err!($obj, $($format)+));
}};
}
macro_rules! abort_call_site {
($($format:tt)+) => {{
let span = proc_macro2::Span::call_site();
abort!(span, $($format)+)
}};
}

View File

@ -6,24 +6,26 @@
use std::iter;
pub fn extract_doc_comment(attrs: &[syn::Attribute]) -> Vec<String> {
use syn::Lit::*;
use syn::Meta::*;
use syn::MetaNameValue;
// multiline comments (`/** ... */`) may have LFs (`\n`) in them,
// we need to split so we could handle the lines correctly
//
// we also need to remove leading and trailing blank lines
let mut lines: Vec<_> = attrs
.iter()
.filter(|attr| attr.path.is_ident("doc"))
.filter(|attr| attr.path().is_ident("doc"))
.filter_map(|attr| {
if let Ok(NameValue(MetaNameValue { lit: Str(s), .. })) = attr.parse_meta() {
Some(s.value())
} else {
// non #[doc = "..."] attributes are not our concern
// we leave them for rustc to handle
None
// non #[doc = "..."] attributes are not our concern
// we leave them for rustc to handle
match &attr.meta {
syn::Meta::NameValue(syn::MetaNameValue {
value:
syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(s),
..
}),
..
}) => Some(s.value()),
_ => None,
}
})
.skip_while(|s| is_blank(s))

View File

@ -0,0 +1,22 @@
pub trait SpanError {
#[allow(non_snake_case)]
fn EXPECTED_Span_OR_ToTokens<D: std::fmt::Display>(&self, msg: D) -> syn::Error;
}
pub trait ToTokensError {
#[allow(non_snake_case)]
fn EXPECTED_Span_OR_ToTokens<D: std::fmt::Display>(&self, msg: D) -> syn::Error;
}
impl<T: quote::ToTokens> ToTokensError for T {
fn EXPECTED_Span_OR_ToTokens<D: std::fmt::Display>(&self, msg: D) -> syn::Error {
// Curb monomorphization from generating too many identical `new_spanned`.
syn::Error::new_spanned(self.to_token_stream(), msg)
}
}
impl SpanError for proc_macro2::Span {
fn EXPECTED_Span_OR_ToTokens<D: std::fmt::Display>(&self, msg: D) -> syn::Error {
syn::Error::new(*self, msg)
}
}

View File

@ -1,3 +1,5 @@
pub mod error;
mod doc_comments;
mod spanned;
mod ty;

View File

@ -14,14 +14,14 @@
import("//build/ohos.gni")
ohos_cargo_crate("lib") {
crate_name = "clap_lex"
crate_type = "rlib"
crate_root = "src/lib.rs"
crate_name = "clap_lex"
crate_type = "rlib"
crate_root = "src/lib.rs"
sources = ["src/lib.rs"]
edition = "2021"
cargo_pkg_version = "0.3.1"
cargo_pkg_name = "clap_lex"
cargo_pkg_description = "Minimal, flexible command line parser"
deps = ["//third_party/rust/crates/os_str_bytes:lib"]
sources = [ "src/lib.rs" ]
edition = "2021"
cargo_pkg_version = "0.3.3"
cargo_pkg_name = "clap_lex"
cargo_pkg_description = "Minimal, flexible command line parser"
deps = [ "//third_party/rust/crates/os_str_bytes:lib" ]
}

View File

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
<!-- next-header -->
## [Unreleased] - ReleaseDate
## [0.3.3] - 2023-03-16
## [0.3.2] - 2023-02-23
## [0.3.1] - 2023-01-13
### Compatibility
@ -46,7 +50,9 @@ MSRV changed to 1.64.0
- Drop `memchr` dependency
<!-- next-url -->
[Unreleased]: https://github.com/clap-rs/clap/compare/clap_lex-v0.3.1...HEAD
[Unreleased]: https://github.com/clap-rs/clap/compare/clap_lex-v0.3.3...HEAD
[0.3.3]: https://github.com/clap-rs/clap/compare/clap_lex-v0.3.2...clap_lex-v0.3.3
[0.3.2]: https://github.com/clap-rs/clap/compare/clap_lex-v0.3.1...clap_lex-v0.3.2
[0.3.1]: https://github.com/clap-rs/clap/compare/clap_lex-v0.3.0...clap_lex-v0.3.1
[0.3.0]: https://github.com/clap-rs/clap/compare/clap_lex-v0.2.4...clap_lex-v0.3.0
[0.2.4]: https://github.com/clap-rs/clap/compare/clap_lex-v0.2.3...clap_lex-v0.2.4

View File

@ -1,6 +1,6 @@
[package]
name = "clap_lex"
version = "0.3.1"
version = "0.3.3"
description = "Minimal, flexible command line parser"
repository = "https://github.com/clap-rs/clap/tree/master/clap_lex"
categories = ["command-line-interface"]
@ -30,4 +30,4 @@ pre-release-replacements = [
bench = false
[dependencies]
os_str_bytes = { version = "6.0", default-features = false, features = ["raw_os_str"] }
os_str_bytes = { version = "6.0.0", default-features = false, features = ["raw_os_str"] }

View File

@ -5,15 +5,15 @@
[![Crates.io](https://img.shields.io/crates/v/clap_lex?style=flat-square)](https://crates.io/crates/clap_lex)
[![Crates.io](https://img.shields.io/crates/d/clap_lex?style=flat-square)](https://crates.io/crates/clap_lex)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_lex-v0.3.1/LICENSE-APACHE)
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_lex-v0.3.1/LICENSE-MIT)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_lex-v0.3.3/LICENSE-APACHE)
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_lex-v0.3.3/LICENSE-MIT)
Dual-licensed under [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT).
1. [About](#about)
2. [API Reference](https://docs.rs/clap_lex)
3. [Questions & Discussions](https://github.com/clap-rs/clap/discussions)
4. [CONTRIBUTING](https://github.com/clap-rs/clap/blob/clap_lex-v0.3.1/clap_lex/CONTRIBUTING.md)
5. [Sponsors](https://github.com/clap-rs/clap/blob/clap_lex-v0.3.1/README.md#sponsors)
4. [CONTRIBUTING](https://github.com/clap-rs/clap/blob/clap_lex-v0.3.3/clap_lex/CONTRIBUTING.md)
5. [Sponsors](https://github.com/clap-rs/clap/blob/clap_lex-v0.3.3/README.md#sponsors)
## About

View File

@ -7,8 +7,10 @@
//! # Examples
//!
//! ```rust
//! # use std::path::PathBuf;
//! # type BoxedError = Box<dyn std::error::Error + Send + Sync>;
//! use std::path::PathBuf;
//!
//! type BoxedError = Box<dyn std::error::Error + Send + Sync>;
//!
//! #[derive(Debug)]
//! struct Args {
//! paths: Vec<PathBuf>,

View File

@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
<!-- next-header -->
## [Unreleased] - ReleaseDate
## [0.2.10] - 2023-03-16
## [0.2.9] - 2023-02-22
### Fixes
- Only show value names if a value is taken
## [0.2.8] - 2023-02-15
## [0.2.7] - 2023-01-13
### Compatibility
@ -72,7 +82,10 @@ MSRV changed to 1.64.0
- Expanded the documentation
<!-- next-url -->
[Unreleased]: https://github.com/clap-rs/clap/compare/clap_mangen-v0.2.7...HEAD
[Unreleased]: https://github.com/clap-rs/clap/compare/clap_mangen-v0.2.10...HEAD
[0.2.10]: https://github.com/clap-rs/clap/compare/clap_mangen-v0.2.9...clap_mangen-v0.2.10
[0.2.9]: https://github.com/clap-rs/clap/compare/clap_mangen-v0.2.8...clap_mangen-v0.2.9
[0.2.8]: https://github.com/clap-rs/clap/compare/clap_mangen-v0.2.7...clap_mangen-v0.2.8
[0.2.7]: https://github.com/clap-rs/clap/compare/clap_mangen-v0.2.6...clap_mangen-v0.2.7
[0.2.6]: https://github.com/clap-rs/clap/compare/clap_mangen-v0.2.5...clap_mangen-v0.2.6
[0.2.5]: https://github.com/clap-rs/clap/compare/clap_mangen-v0.2.4...clap_mangen-v0.2.5

View File

@ -1,6 +1,6 @@
[package]
name = "clap_mangen"
version = "0.2.7"
version = "0.2.10"
description = "A manpage generator for clap"
repository = "https://github.com/clap-rs/clap/tree/master/clap_mangen"
categories = ["command-line-interface"]
@ -36,7 +36,7 @@ roff = "0.2.1"
clap = { path = "../", version = "4.0.0", default-features = false, features = ["std", "env"] }
[dev-dependencies]
snapbox = { version = "0.4", features = ["diff"] }
snapbox = { version = "0.4.10", features = ["diff"] }
clap = { path = "../", version = "4.0.0", default-features = false, features = ["std", "help"] }
[features]

View File

@ -5,16 +5,16 @@
[![Crates.io](https://img.shields.io/crates/v/clap_mangen?style=flat-square)](https://crates.io/crates/clap_mangen)
[![Crates.io](https://img.shields.io/crates/d/clap_mangen?style=flat-square)](https://crates.io/crates/clap_mangen)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_mangen-v0.2.7/LICENSE-APACHE)
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_mangen-v0.2.7/LICENSE-MIT)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_mangen-v0.2.10/LICENSE-APACHE)
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_mangen-v0.2.10/LICENSE-MIT)
Dual-licensed under [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT).
1. [About](#about)
2. [API Reference](https://docs.rs/clap_mangen)
3. [Questions & Discussions](https://github.com/clap-rs/clap/discussions)
4. [CONTRIBUTING](https://github.com/clap-rs/clap/blob/clap_mangen-v0.2.7/clap_mangen/CONTRIBUTING.md)
5. [Sponsors](https://github.com/clap-rs/clap/blob/clap_mangen-v0.2.7/README.md#sponsors)
4. [CONTRIBUTING](https://github.com/clap-rs/clap/blob/clap_mangen-v0.2.10/clap_mangen/CONTRIBUTING.md)
5. [Sponsors](https://github.com/clap-rs/clap/blob/clap_mangen-v0.2.10/README.md#sponsors)
## About
@ -25,10 +25,9 @@ Generate [ROFF](https://en.wikipedia.org/wiki/Roff_(software)) from a `clap::Com
We're going to assume you want to generate your man page as part of your
development rather than your shipped program having a flag to generate it.
In your `Cargo.toml`:
```toml
[build-dependencies]
clap_mangen = "0.1"
Run
```console
$ cargo add --build clap_mangen
```
In your `build.rs`:

View File

@ -36,19 +36,19 @@ pub(crate) fn synopsis(roff: &mut Roff, cmd: &clap::Command) {
match (opt.get_short(), opt.get_long()) {
(Some(short), Some(long)) => {
line.push(roman(lhs));
line.push(bold(format!("-{}", short)));
line.push(bold(format!("-{short}")));
line.push(roman("|"));
line.push(bold(format!("--{}", long)));
line.push(bold(format!("--{long}",)));
line.push(roman(rhs));
}
(Some(short), None) => {
line.push(roman(lhs));
line.push(bold(format!("-{} ", short)));
line.push(bold(format!("-{short} ")));
line.push(roman(rhs));
}
(None, Some(long)) => {
line.push(roman(lhs));
line.push(bold(format!("--{}", long)));
line.push(bold(format!("--{long}")));
line.push(roman(rhs));
}
(None, None) => continue,
@ -99,9 +99,11 @@ pub(crate) fn options(roff: &mut Roff, cmd: &clap::Command) {
(None, None) => vec![],
};
if let Some(value) = &opt.get_value_names() {
header.push(roman("="));
header.push(italic(value.join(" ")));
if opt.get_action().takes_values() {
if let Some(value) = &opt.get_value_names() {
header.push(roman("="));
header.push(italic(value.join(" ")));
}
}
if let Some(defs) = option_default_values(opt) {
@ -168,7 +170,7 @@ pub(crate) fn options(roff: &mut Roff, cmd: &clap::Command) {
header.push(roman(rhs));
if let Some(defs) = option_default_values(pos) {
header.push(roman(format!(" {}", defs)));
header.push(roman(format!(" {defs}")));
}
let mut body = vec![];
@ -273,11 +275,11 @@ fn markers(required: bool) -> (&'static str, &'static str) {
}
fn short_option(opt: char) -> Inline {
bold(format!("-{}", opt))
bold(format!("-{opt}"))
}
fn long_option(opt: &str) -> Inline {
bold(format!("--{}", opt))
bold(format!("--{opt}"))
}
fn option_help(opt: &clap::Arg) -> Option<&clap::builder::StyledStr> {
@ -319,7 +321,7 @@ fn option_default_values(opt: &clap::Arg) -> Option<String> {
.collect::<Vec<_>>()
.join(",");
return Some(format!("[default: {}]", values));
return Some(format!("[default: {values}]"));
}
None
@ -343,7 +345,7 @@ fn format_possible_values(possibles: &Vec<&clap::builder::PossibleValue>) -> (Ve
for value in possibles {
let val_name = value.get_name();
match value.get_help() {
Some(help) => lines.push(format!("{}: {}", val_name, help)),
Some(help) => lines.push(format!("{val_name}: {help}")),
None => lines.push(val_name.to_string()),
}
}

View File

@ -312,3 +312,12 @@ pub fn possible_values_command(name: &'static str) -> clap::Command {
]),
)
}
pub fn value_name_without_arg(name: &'static str) -> clap::Command {
clap::Command::new(name).arg(
clap::Arg::new("flag")
.long("flag")
.value_name("SPURIOUS")
.action(clap::ArgAction::SetTrue),
)
}

View File

@ -83,3 +83,10 @@ fn sub_subcommands_help() {
common::assert_matches_path("tests/snapshots/sub_subcommand_help.roff", cmd.clone());
}
}
#[test]
fn value_name_without_arg() {
let name = "my-app";
let cmd = common::value_name_without_arg(name);
common::assert_matches_path("tests/snapshots/value_name_without_arg.bash.roff", cmd);
}

View File

@ -0,0 +1,15 @@
.ie /n(.g .ds Aq /(aq
.el .ds Aq '
.TH my-app 1 "my-app "
.SH NAME
my/-app
.SH SYNOPSIS
/fBmy/-app/fR [/fB/-/-flag/fR] [/fB/-h/fR|/fB/-/-help/fR]
.SH DESCRIPTION
.SH OPTIONS
.TP
/fB/-/-flag/fR
.TP
/fB/-h/fR, /fB/-/-help/fR
Print help

149
deny.toml Normal file
View File

@ -0,0 +1,149 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Note that all fields that take a lint level have these possible values:
# * deny - An error will be produced and the check will fail
# * warn - A warning will be produced, but the check will not fail
# * allow - No warning or error will be produced, though in some cases a note
# will be
# This section is considered when running `cargo deny check advisories`
# More documentation for the advisories section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
[advisories]
# The lint level for security vulnerabilities
vulnerability = "deny"
# The lint level for unmaintained crates
unmaintained = "warn"
# The lint level for crates that have been yanked from their source registry
yanked = "warn"
# The lint level for crates with security notices. Note that as of
# 2019-12-17 there are no security notice advisories in
# https://github.com/rustsec/advisory-db
notice = "warn"
# A list of advisory IDs to ignore. Note that ignored advisories will still
# output a note when they are encountered.
#
# e.g. "RUSTSEC-0000-0000",
ignore = [
]
# This section is considered when running `cargo deny check licenses`
# More documentation for the licenses section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
[licenses]
unlicensed = "deny"
# List of explicitly allowed licenses
# See https://spdx.org/licenses/ for list of possible licenses
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
allow = [
"MIT",
"Apache-2.0",
"Unicode-DFS-2016",
#"Apache-2.0 WITH LLVM-exception",
]
# List of explicitly disallowed licenses
# See https://spdx.org/licenses/ for list of possible licenses
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
deny = [
]
# Lint level for licenses considered copyleft
copyleft = "deny"
# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses
# * both - The license will be approved if it is both OSI-approved *AND* FSF
# * either - The license will be approved if it is either OSI-approved *OR* FSF
# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF
# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved
# * neither - This predicate is ignored and the default lint level is used
allow-osi-fsf-free = "neither"
# Lint level used when no other predicates are matched
# 1. License isn't in the allow or deny lists
# 2. License isn't copyleft
# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither"
default = "deny"
# The confidence threshold for detecting a license from license text.
# The higher the value, the more closely the license text must be to the
# canonical license text of a valid SPDX license file.
# [possible values: any between 0.0 and 1.0].
confidence-threshold = 0.8
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
# aren't accepted for every possible crate as with the normal allow list
exceptions = [
# Each entry is the crate and version constraint, and its specific allow
# list
#{ allow = ["Zlib"], name = "adler32", version = "*" },
]
[licenses.private]
# If true, ignores workspace crates that aren't published, or are only
# published to private registries.
# To see how to mark a crate as unpublished (to the official registry),
# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.
ignore = true
# This section is considered when running `cargo deny check bans`.
# More documentation about the 'bans' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
[bans]
# Lint level for when multiple versions of the same crate are detected
multiple-versions = "warn"
# Lint level for when a crate version requirement is `*`
wildcards = "deny"
# The graph highlighting used when creating dotgraphs for crates
# with multiple versions
# * lowest-version - The path to the lowest versioned duplicate is highlighted
# * simplest-path - The path to the version with the fewest edges is highlighted
# * all - Both lowest-version and simplest-path are used
highlight = "all"
# The default lint level for `default` features for crates that are members of
# the workspace that is being checked. This can be overridden by allowing/denying
# `default` on a crate-by-crate basis if desired.
workspace-default-features = "allow"
# The default lint level for `default` features for external crates that are not
# members of the workspace. This can be overridden by allowing/denying `default`
# on a crate-by-crate basis if desired.
external-default-features = "allow"
# List of crates that are allowed. Use with care!
allow = [
#{ name = "ansi_term", version = "=0.11.0" },
]
# List of crates to deny
deny = [
# Each entry the name of a crate and a version range. If version is
# not specified, all versions will be matched.
#{ name = "ansi_term", version = "=0.11.0" },
#
# Wrapper crates can optionally be specified to allow the crate when it
# is a direct dependency of the otherwise banned crate
#{ name = "ansi_term", version = "=0.11.0", wrappers = [] },
]
# This section is considered when running `cargo deny check sources`.
# More documentation about the 'sources' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
[sources]
# Lint level for what to happen when a crate from a crate registry that is not
# in the allow list is encountered
unknown-registry = "deny"
# Lint level for what to happen when a crate from a git repository that is not
# in the allow list is encountered
unknown-git = "deny"
# List of URLs for allowed crate registries. Defaults to the crates.io index
# if not specified. If it is specified but empty, no registries are allowed.
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
# List of URLs for allowed Git repositories
allow-git = []
[sources.allow-org]
# 1 or more github.com organizations to allow git sources for
github = []

View File

@ -3,18 +3,18 @@ use clap::Parser;
#[derive(Parser)] // requires `derive` feature
#[command(name = "cargo")]
#[command(bin_name = "cargo")]
enum Cargo {
ExampleDerive(ExampleDerive),
enum CargoCli {
ExampleDerive(ExampleDeriveArgs),
}
#[derive(clap::Args)]
#[command(author, version, about, long_about = None)]
struct ExampleDerive {
struct ExampleDeriveArgs {
#[arg(long)]
manifest_path: Option<std::path::PathBuf>,
}
fn main() {
let Cargo::ExampleDerive(args) = Cargo::parse();
let CargoCli::ExampleDerive(args) = CargoCli::parse();
println!("{:?}", args.manifest_path);
}

View File

@ -23,5 +23,5 @@ fn main() {
let derived_matches = DerivedArgs::from_arg_matches(&matches)
.map_err(|err| err.exit())
.unwrap();
println!("Value of derived: {:#?}", derived_matches);
println!("Value of derived: {derived_matches:#?}");
}

View File

@ -17,5 +17,5 @@ fn main() {
let derived_subcommands = Subcommands::from_arg_matches(&matches)
.map_err(|err| err.exit())
.unwrap();
println!("Derived subcommands: {:#?}", derived_subcommands);
println!("Derived subcommands: {derived_subcommands:#?}");
}

View File

@ -87,5 +87,5 @@ struct Cli {
fn main() {
let args = Cli::parse();
println!("{:#?}", args);
println!("{args:#?}");
}

View File

@ -69,11 +69,11 @@ impl Subcommand for CliSub {
struct Cli {
#[arg(short, long)]
top_level: bool,
#[clap(subcommand)]
#[command(subcommand)]
subcommand: CliSub,
}
fn main() {
let args = Cli::parse();
println!("{:#?}", args);
println!("{args:#?}");
}

View File

@ -102,13 +102,13 @@ Options:
-h, --help Print help
$ git-derive stash -m "Prototype"
Pushing StashPush { message: Some("Prototype") }
Pushing StashPushArgs { message: Some("Prototype") }
$ git-derive stash pop
Popping None
$ git-derive stash push -m "Prototype"
Pushing StashPush { message: Some("Prototype") }
Pushing StashPushArgs { message: Some("Prototype") }
$ git-derive stash pop
Popping None

View File

@ -53,7 +53,7 @@ enum Commands {
#[arg(required = true)]
path: Vec<PathBuf>,
},
Stash(Stash),
Stash(StashArgs),
#[command(external_subcommand)]
External(Vec<OsString>),
}
@ -76,23 +76,23 @@ impl std::fmt::Display for ColorWhen {
#[derive(Debug, Args)]
#[command(args_conflicts_with_subcommands = true)]
struct Stash {
struct StashArgs {
#[command(subcommand)]
command: Option<StashCommands>,
#[command(flatten)]
push: StashPush,
push: StashPushArgs,
}
#[derive(Debug, Subcommand)]
enum StashCommands {
Push(StashPush),
Push(StashPushArgs),
Pop { stash: Option<String> },
Apply { stash: Option<String> },
}
#[derive(Debug, Args)]
struct StashPush {
struct StashPushArgs {
#[arg(short, long)]
message: Option<String>,
}
@ -102,7 +102,7 @@ fn main() {
match args.command {
Commands::Clone { remote } => {
println!("Cloning {}", remote);
println!("Cloning {remote}");
}
Commands::Diff {
mut base,
@ -136,22 +136,22 @@ fn main() {
);
}
Commands::Push { remote } => {
println!("Pushing to {}", remote);
println!("Pushing to {remote}");
}
Commands::Add { path } => {
println!("Adding {:?}", path);
println!("Adding {path:?}");
}
Commands::Stash(stash) => {
let stash_cmd = stash.command.unwrap_or(StashCommands::Push(stash.push));
match stash_cmd {
StashCommands::Push(push) => {
println!("Pushing {:?}", push);
println!("Pushing {push:?}");
}
StashCommands::Pop { stash } => {
println!("Popping {:?}", stash);
println!("Popping {stash:?}");
}
StashCommands::Apply { stash } => {
println!("Applying {:?}", stash);
println!("Applying {stash:?}");
}
}
}

View File

@ -86,7 +86,7 @@ fn main() {
let base = base.unwrap_or("stage");
let head = head.unwrap_or("worktree");
let path = path.unwrap_or("");
println!("Diffing {}..{} {} (color={})", base, head, path, color);
println!("Diffing {base}..{head} {path} (color={color})");
}
Some(("push", sub_matches)) => {
println!(
@ -100,22 +100,22 @@ fn main() {
.into_iter()
.flatten()
.collect::<Vec<_>>();
println!("Adding {:?}", paths);
println!("Adding {paths:?}");
}
Some(("stash", sub_matches)) => {
let stash_command = sub_matches.subcommand().unwrap_or(("push", sub_matches));
match stash_command {
("apply", sub_matches) => {
let stash = sub_matches.get_one::<String>("STASH");
println!("Applying {:?}", stash);
println!("Applying {stash:?}");
}
("pop", sub_matches) => {
let stash = sub_matches.get_one::<String>("STASH");
println!("Popping {:?}", stash);
println!("Popping {stash:?}");
}
("push", sub_matches) => {
let message = sub_matches.get_one::<String>("message");
println!("Pushing {:?}", message);
println!("Pushing {message:?}");
}
(name, _) => {
unreachable!("Unsupported subcommand `{}`", name)
@ -128,9 +128,9 @@ fn main() {
.into_iter()
.flatten()
.collect::<Vec<_>>();
println!("Calling out to {:?} with {:?}", ext, args);
println!("Calling out to {ext:?} with {args:?}");
}
_ => unreachable!(), // If all subcommands are defined above, anything else is unreachabe!()
_ => unreachable!(), // If all subcommands are defined above, anything else is unreachable!()
}
// Continued program logic goes here...

View File

@ -78,7 +78,7 @@ fn main() {
.map(|s| s.as_str())
.collect();
let values = packages.join(", ");
println!("Searching for {}...", values);
println!("Searching for {values}...");
return;
}
@ -90,18 +90,18 @@ fn main() {
let values = packages.join(", ");
if sync_matches.get_flag("info") {
println!("Retrieving info for {}...", values);
println!("Retrieving info for {values}...");
} else {
println!("Installing {}...", values);
println!("Installing {values}...");
}
}
Some(("query", query_matches)) => {
if let Some(packages) = query_matches.get_many::<String>("info") {
let comma_sep = packages.map(|s| s.as_str()).collect::<Vec<_>>().join(", ");
println!("Retrieving info for {}...", comma_sep);
println!("Retrieving info for {comma_sep}...");
} else if let Some(queries) = query_matches.get_many::<String>("search") {
let comma_sep = queries.map(|s| s.as_str()).collect::<Vec<_>>().join(", ");
println!("Searching Locally for {}...", comma_sep);
println!("Searching Locally for {comma_sep}...");
} else {
println!("Displaying all locally installed packages...");
}

View File

@ -17,7 +17,7 @@ fn main() -> Result<(), String> {
}
}
Err(err) => {
write!(std::io::stdout(), "{}", err).map_err(|e| e.to_string())?;
write!(std::io::stdout(), "{err}").map_err(|e| e.to_string())?;
std::io::stdout().flush().map_err(|e| e.to_string())?;
}
}

View File

@ -35,7 +35,7 @@ fn main() {
// You can check the value provided by positional arguments, or option arguments
if let Some(name) = cli.name.as_deref() {
println!("Value for name: {}", name);
println!("Value for name: {name}");
}
if let Some(config_path) = cli.config.as_deref() {

View File

@ -21,7 +21,7 @@ fn main() {
// matches just as you would the top level cmd
match &cli.command {
Commands::Add { name } => {
println!("'myapp add' was used, name is: {:?}", name)
println!("'myapp add' was used, name is: {name:?}")
}
}
}

View File

@ -11,11 +11,11 @@ struct Cli {
#[derive(Subcommand)]
enum Commands {
/// Adds files to myapp
Add(Add),
Add(AddArgs),
}
#[derive(Args)]
struct Add {
struct AddArgs {
name: Option<String>,
}

View File

@ -21,7 +21,7 @@ const PORT_RANGE: RangeInclusive<usize> = 1..=65535;
fn port_in_range(s: &str) -> Result<u16, String> {
let port: usize = s
.parse()
.map_err(|_| format!("`{}` isn't a port number", s))?;
.map_err(|_| format!("`{s}` isn't a port number"))?;
if PORT_RANGE.contains(&port) {
Ok(port as u16)
} else {

View File

@ -56,10 +56,10 @@ fn main() {
(_, _, true) => patch += 1,
_ => unreachable!(),
};
format!("{}.{}.{}", major, minor, patch)
format!("{major}.{minor}.{patch}")
};
println!("Version: {}", version);
println!("Version: {version}");
// Check for usage of -c
if let Some(config) = cli.config.as_deref() {
@ -67,6 +67,6 @@ fn main() {
.input_file
.as_deref()
.unwrap_or_else(|| cli.spec_in.as_deref().unwrap());
println!("Doing work using input {} and config {}", input, config);
println!("Doing work using input {input} and config {config}");
}
}

View File

@ -66,10 +66,10 @@ fn main() {
.exit();
}
};
format!("{}.{}.{}", major, minor, patch)
format!("{major}.{minor}.{patch}")
};
println!("Version: {}", version);
println!("Version: {version}");
// Check for usage of -c
if let Some(config) = cli.config.as_deref() {
@ -86,6 +86,6 @@ fn main() {
)
.exit()
});
println!("Doing work using input {} and config {}", input, config);
println!("Doing work using input {input} and config {config}");
}
}

View File

@ -54,7 +54,7 @@ where
{
let pos = s
.find('=')
.ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?;
.ok_or_else(|| format!("invalid KEY=value: no `=` found in `{s}`"))?;
Ok((s[..pos].parse()?, s[pos + 1..].parse()?))
}
@ -98,5 +98,5 @@ mod foreign_crate {
fn main() {
let args = Args::parse();
println!("{:?}", args);
println!("{args:?}");
}

View File

@ -75,7 +75,7 @@
#![doc = include_str!("../../examples/tutorial_derive/03_03_positional.md")]
//!
//! Note that the default [`ArgAction`][crate::ArgAction] is [`Set`][crate::ArgAction::Set]. To
//! accept multiple values, use [`Append`][crate::ArgAction::Append]:
//! accept multiple values, use [`Append`][crate::ArgAction::Append] via `Vec`:
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_03_positional_mult.rs")]
//! ```
@ -98,7 +98,7 @@
#![doc = include_str!("../../examples/tutorial_derive/03_02_option.md")]
//!
//! Note that the default [`ArgAction`][crate::ArgAction] is [`Set`][crate::ArgAction::Set]. To
//! accept multiple occurrences, use [`Append`][crate::ArgAction::Append]:
//! accept multiple occurrences, use [`Append`][crate::ArgAction::Append] via `Vec`:
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_02_option_mult.rs")]
//! ```

View File

@ -2111,7 +2111,8 @@ impl Arg {
///
/// Args with a lower value will be displayed first in the help message. This is helpful when
/// one would like to emphasise frequently used args, or prioritize those towards the top of
/// the list. Args with duplicate display orders will be displayed in alphabetical order.
/// the list. Args with duplicate display orders will be displayed in the order they are
/// defined.
///
/// **NOTE:** The default is 999 for all arguments.
///
@ -4122,7 +4123,7 @@ impl Arg {
if self.val_names.len() > 1 {
self.val_names
.iter()
.map(|n| format!("<{}>", n))
.map(|n| format!("<{n}>"))
.collect::<Vec<_>>()
.join(delim)
} else {
@ -4206,9 +4207,9 @@ impl Arg {
debug_assert!(self.is_takes_value_set());
for (n, val_name) in val_names.iter().enumerate() {
let arg_name = if self.is_positional() && (num_vals.min_values() == 0 || !required) {
format!("[{}]", val_name)
format!("[{val_name}]")
} else {
format!("<{}>", val_name)
format!("<{val_name}>")
};
if n != 0 {

View File

@ -113,7 +113,7 @@ mod test {
assert!(m.is_required_set());
let m = m.unset_setting(ArgSettings::Required);
assert!(!m.is_required_set(), "{:#?}", m);
assert!(!m.is_required_set(), "{m:#?}");
}
#[test]
@ -138,8 +138,8 @@ mod test {
assert!(m.is_last_set());
let m = m.unset_setting(ArgSettings::Required | ArgSettings::Hidden | ArgSettings::Last);
assert!(!m.is_required_set(), "{:#?}", m);
assert!(!m.is_hide_set(), "{:#?}", m);
assert!(!m.is_last_set(), "{:#?}", m);
assert!(!m.is_required_set(), "{m:#?}");
assert!(!m.is_hide_set(), "{m:#?}");
assert!(!m.is_last_set(), "{m:#?}");
}
}

View File

@ -243,7 +243,7 @@ impl Command {
let a = self
.args
.remove_by_name(id)
.unwrap_or_else(|| panic!("Argument `{}` is undefined", id));
.unwrap_or_else(|| panic!("Argument `{id}` is undefined"));
self.args.push(f(a));
self
@ -287,7 +287,7 @@ impl Command {
let subcmd = if let Some(idx) = pos {
self.subcommands.remove(idx)
} else {
panic!("Command `{}` is undefined", name)
panic!("Command `{name}` is undefined")
};
self.subcommands.push(f(subcmd));
@ -822,7 +822,7 @@ impl Command {
let mut styled = StyledStr::new();
let usage = Usage::new(self);
write_help(&mut styled, self, &usage, false);
ok!(write!(w, "{}", styled));
ok!(write!(w, "{styled}"));
w.flush()
}
@ -837,7 +837,7 @@ impl Command {
let mut styled = StyledStr::new();
let usage = Usage::new(self);
write_help(&mut styled, self, &usage, true);
ok!(write!(w, "{}", styled));
ok!(write!(w, "{styled}"));
w.flush()
}
@ -1057,8 +1057,8 @@ impl Command {
///
/// Using `0` will ignore terminal widths and use source formatting.
///
/// Defaults to current terminal width when `wrap_help` feature flag is enabled. If the flag
/// is disabled or it cannot be determined, the default is 100.
/// Defaults to current terminal width when `wrap_help` feature flag is enabled. If current
/// width cannot be determined, the default is 100.
///
/// **NOTE:** This setting applies globally and *not* on a per-command basis.
///
@ -2599,7 +2599,7 @@ impl Command {
/// Set the placement of this subcommand within the help.
///
/// Subcommands with a lower value will be displayed first in the help message. Subcommands
/// with duplicate display orders will be displayed in alphabetical order.
/// with duplicate display orders will be displayed in order they are defined.
///
/// This is helpful when one would like to emphasize frequently used subcommands, or prioritize
/// those towards the top of the list.
@ -3947,22 +3947,22 @@ impl Command {
sc_names.push_str(sc.name.as_str());
let mut flag_subcmd = false;
if let Some(l) = sc.get_long_flag() {
write!(sc_names, "|--{}", l).unwrap();
write!(sc_names, "|--{l}").unwrap();
flag_subcmd = true;
}
if let Some(s) = sc.get_short_flag() {
write!(sc_names, "|-{}", s).unwrap();
write!(sc_names, "|-{s}").unwrap();
flag_subcmd = true;
}
if flag_subcmd {
sc_names = format!("{{{}}}", sc_names);
sc_names = format!("{{{sc_names}}}");
}
let usage_name = self
.bin_name
.as_ref()
.map(|bin_name| format!("{}{}{}", bin_name, mid_string, sc_names))
.map(|bin_name| format!("{bin_name}{mid_string}{sc_names}"))
.unwrap_or(sc_names);
sc.usage_name = Some(usage_name);
@ -4044,19 +4044,19 @@ impl Command {
sc_names.push_str(sc.name.as_str());
let mut flag_subcmd = false;
if let Some(l) = sc.get_long_flag() {
write!(sc_names, "|--{}", l).unwrap();
write!(sc_names, "|--{l}").unwrap();
flag_subcmd = true;
}
if let Some(s) = sc.get_short_flag() {
write!(sc_names, "|-{}", s).unwrap();
write!(sc_names, "|-{s}").unwrap();
flag_subcmd = true;
}
if flag_subcmd {
sc_names = format!("{{{}}}", sc_names);
sc_names = format!("{{{sc_names}}}");
}
let usage_name = format!("{}{}{}", self_bin_name, mid_string, sc_names);
let usage_name = format!("{self_bin_name}{mid_string}{sc_names}");
debug!(
"Command::_build_bin_names:iter: Setting usage_name of {} to {:?}",
sc.name, usage_name
@ -4334,7 +4334,7 @@ impl Command {
.unwrap_or_default()
};
let display_name = self.get_display_name().unwrap_or_else(|| self.get_name());
format!("{} {}\n", display_name, ver)
format!("{display_name} {ver}\n")
}
pub(crate) fn format_group(&self, g: &Id) -> StyledStr {
@ -4593,12 +4593,14 @@ impl Command {
// specified by the user is sent through. If hide_short_help is not included,
// then items specified with hidden_short_help will also be hidden.
let should_long = |v: &Arg| {
v.get_long_help().is_some()
|| v.is_hide_long_help_set()
|| v.is_hide_short_help_set()
|| v.get_possible_values()
.iter()
.any(PossibleValue::should_show_help)
!v.is_hide_set()
&& (v.get_long_help().is_some()
|| v.is_hide_long_help_set()
|| v.is_hide_short_help_set()
|| (!v.is_hide_possible_values_set()
&& v.get_possible_values()
.iter()
.any(PossibleValue::should_show_help)))
};
// Subcommands aren't checked because we prefer short help for them, deferring to

View File

@ -40,20 +40,20 @@ pub(crate) fn assert_app(cmd: &Command) {
for sc in cmd.get_subcommands() {
if let Some(s) = sc.get_short_flag().as_ref() {
short_flags.push(Flag::Command(format!("-{}", s), sc.get_name()));
short_flags.push(Flag::Command(format!("-{s}"), sc.get_name()));
}
for short_alias in sc.get_all_short_flag_aliases() {
short_flags.push(Flag::Command(format!("-{}", short_alias), sc.get_name()));
short_flags.push(Flag::Command(format!("-{short_alias}"), sc.get_name()));
}
if let Some(l) = sc.get_long_flag().as_ref() {
assert!(!l.starts_with('-'), "Command {}: long_flag {:?} must not start with a `-`, that will be handled by the parser", sc.get_name(), l);
long_flags.push(Flag::Command(format!("--{}", l), sc.get_name()));
long_flags.push(Flag::Command(format!("--{l}"), sc.get_name()));
}
for long_alias in sc.get_all_long_flag_aliases() {
long_flags.push(Flag::Command(format!("--{}", long_alias), sc.get_name()));
long_flags.push(Flag::Command(format!("--{long_alias}"), sc.get_name()));
}
}
@ -68,26 +68,20 @@ pub(crate) fn assert_app(cmd: &Command) {
);
if let Some(s) = arg.get_short() {
short_flags.push(Flag::Arg(format!("-{}", s), arg.get_id().as_str()));
short_flags.push(Flag::Arg(format!("-{s}"), arg.get_id().as_str()));
}
for (short_alias, _) in &arg.short_aliases {
short_flags.push(Flag::Arg(
format!("-{}", short_alias),
arg.get_id().as_str(),
));
short_flags.push(Flag::Arg(format!("-{short_alias}"), arg.get_id().as_str()));
}
if let Some(l) = arg.get_long() {
assert!(!l.starts_with('-'), "Argument {}: long {:?} must not start with a `-`, that will be handled by the parser", arg.get_id(), l);
long_flags.push(Flag::Arg(format!("--{}", l), arg.get_id().as_str()));
long_flags.push(Flag::Arg(format!("--{l}"), arg.get_id().as_str()));
}
for (long_alias, _) in &arg.aliases {
long_flags.push(Flag::Arg(
format!("--{}", long_alias),
arg.get_id().as_str(),
));
long_flags.push(Flag::Arg(format!("--{long_alias}"), arg.get_id().as_str()));
}
// Name conflicts
@ -429,19 +423,16 @@ fn detect_duplicate_flags(flags: &[Flag], short_or_long: &str) {
for (one, two) in find_duplicates(flags) {
match (one, two) {
(Command(flag, one), Command(_, another)) if one != another => panic!(
"the '{}' {} flag is specified for both '{}' and '{}' subcommands",
flag, short_or_long, one, another
"the '{flag}' {short_or_long} flag is specified for both '{one}' and '{another}' subcommands"
),
(Arg(flag, one), Arg(_, another)) if one != another => panic!(
"{} option names must be unique, but '{}' is in use by both '{}' and '{}'",
short_or_long, flag, one, another
"{short_or_long} option names must be unique, but '{flag}' is in use by both '{one}' and '{another}'"
),
(Arg(flag, arg), Command(_, sub)) | (Command(flag, sub), Arg(_, arg)) => panic!(
"the '{}' {} flag for the '{}' argument conflicts with the short flag \
for '{}' subcommand",
flag, short_or_long, arg, sub
"the '{flag}' {short_or_long} flag for the '{arg}' argument conflicts with the short flag \
for '{sub}' subcommand"
),
_ => {}
@ -529,10 +520,8 @@ fn _verify_positionals(cmd: &Command) -> bool {
assert!(
highest_idx == num_p,
"Found positional argument whose index is {} but there \
are only {} positional arguments defined",
highest_idx,
num_p
"Found positional argument whose index is {highest_idx} but there \
are only {num_p} positional arguments defined",
);
for arg in cmd.get_arguments() {

View File

@ -183,7 +183,7 @@ impl std::fmt::Display for ValueRange {
impl std::fmt::Debug for ValueRange {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self)
write!(f, "{self}")
}
}

View File

@ -246,7 +246,10 @@ pub(crate) mod inner {
}
pub(crate) fn into_string(self) -> String {
self.as_str().to_owned()
match self {
Self::Static(s) => s.to_owned(),
Self::Owned(s) => s.into(),
}
}
}
}

View File

@ -89,7 +89,7 @@ impl FromStr for ValueHint {
"hostname" => ValueHint::Hostname,
"url" => ValueHint::Url,
"emailaddress" => ValueHint::EmailAddress,
_ => return Err(format!("unknown ValueHint: `{}`", s)),
_ => return Err(format!("unknown ValueHint: `{s}`")),
})
}
}

View File

@ -385,7 +385,7 @@ pub trait ValueEnum: Sized + Clone {
.matches(input, ignore_case)
})
.cloned()
.ok_or_else(|| format!("invalid variant: {}", input))
.ok_or_else(|| format!("invalid variant: {input}"))
}
/// The canonical argument value.

View File

@ -461,7 +461,7 @@ fn did_you_mean(styled: &mut StyledStr, context: &str, valid: &ContextValue) {
fn escape(s: impl AsRef<str>) -> String {
let s = s.as_ref();
if s.contains(char::is_whitespace) {
format!("{:?}", s)
format!("{s:?}")
} else {
s.to_owned()
}

View File

@ -692,7 +692,7 @@ impl<F: ErrorFormatter> Error<F> {
Some((flag, None)) => {
err = err.insert_context_unchecked(
ContextKind::SuggestedArg,
ContextValue::String(format!("--{}", flag)),
ContextValue::String(format!("--{flag}")),
);
}
None => {}
@ -782,7 +782,7 @@ impl<F: ErrorFormatter> Display for Error<F> {
if let Some(backtrace) = self.inner.backtrace.as_ref() {
ok!(writeln!(f));
ok!(writeln!(f, "Backtrace:"));
ok!(writeln!(f, "{}", backtrace));
ok!(writeln!(f, "{backtrace}"));
}
Ok(())
}

View File

@ -126,6 +126,8 @@ impl MKeyMap {
/// We need a lazy build here since some we may change args after creating
/// the map, you can checkout who uses `args_mut`.
pub(crate) fn _build(&mut self) {
// There will be at least as many keys as args, so that is a good starting point
self.keys.reserve(self.args.len());
for (i, arg) in self.args.iter().enumerate() {
append_keys(&mut self.keys, arg, i);
}

View File

@ -368,7 +368,8 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
.get_subcommand_help_heading()
.unwrap_or(&default_help_heading),
);
self.header(":\n");
self.header(":");
self.none("\n");
self.write_subcommands(self.cmd);
}
@ -379,7 +380,8 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
}
first = false;
// Write positional args if any
self.header("Arguments:\n");
self.header("Arguments:");
self.none("\n");
self.write_args(&pos, "Arguments", positional_sort_key);
}
@ -388,7 +390,8 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
self.none("\n\n");
}
first = false;
self.header("Options:\n");
self.header("Options:");
self.none("\n");
self.write_args(&non_pos, "Options", option_sort_key);
}
if !custom_headings.is_empty() {
@ -410,7 +413,9 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
self.none("\n\n");
}
first = false;
self.header(format!("{}:\n", heading));
self.header(heading);
self.header(":");
self.none("\n");
self.write_args(&args, heading, option_sort_key);
}
}
@ -485,7 +490,7 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
debug!("HelpTemplate::short");
if let Some(s) = arg.get_short() {
self.literal(format!("-{}", s));
self.literal(format!("-{s}"));
} else if arg.get_long().is_some() {
self.none(" ");
}
@ -498,7 +503,7 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
if arg.get_short().is_some() {
self.none(", ");
}
self.literal(format!("--{}", long));
self.literal(format!("--{long}"));
}
}
@ -738,7 +743,7 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
.map(|pvs| pvs.to_string_lossy())
.map(|pvs| {
if pvs.contains(char::is_whitespace) {
Cow::from(format!("{:?}", pvs))
Cow::from(format!("{pvs:?}"))
} else {
pvs
}
@ -746,7 +751,7 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
.collect::<Vec<_>>()
.join(" ");
spec_vals.push(format!("[default: {}]", pvs));
spec_vals.push(format!("[default: {pvs}]"));
}
let als = a
@ -758,7 +763,7 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
.join(", ");
if !als.is_empty() {
debug!("HelpTemplate::spec_vals: Found aliases...{:?}", a.aliases);
spec_vals.push(format!("[aliases: {}]", als));
spec_vals.push(format!("[aliases: {als}]"));
}
let als = a
@ -773,7 +778,7 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
"HelpTemplate::spec_vals: Found short aliases...{:?}",
a.short_aliases
);
spec_vals.push(format!("[short aliases: {}]", als));
spec_vals.push(format!("[short aliases: {als}]"));
}
let possible_vals = a.get_possible_values();
@ -792,7 +797,7 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
.collect::<Vec<_>>()
.join(", ");
spec_vals.push(format!("[possible values: {}]", pvs));
spec_vals.push(format!("[possible values: {pvs}]"));
}
let connector = if self.use_long { "\n" } else { " " };
spec_vals.join(connector)
@ -835,11 +840,11 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
styled.literal(subcommand.get_name());
if let Some(short) = subcommand.get_short_flag() {
styled.none(", ");
styled.literal(format!("-{}", short));
styled.literal(format!("-{short}"));
}
if let Some(long) = subcommand.get_long_flag() {
styled.none(", ");
styled.literal(format!("--{}", long));
styled.literal(format!("--{long}"));
}
longest = longest.max(styled.display_width());
ord_v.push((subcommand.get_display_order(), styled, subcommand));
@ -902,7 +907,7 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
let mut short_als = a
.get_visible_short_flag_aliases()
.map(|a| format!("-{}", a))
.map(|a| format!("-{a}"))
.collect::<Vec<_>>();
let als = a.get_visible_aliases().map(|s| s.to_string());
short_als.extend(als);
@ -916,7 +921,7 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
"HelpTemplate::spec_vals: Found short flag aliases...{:?}",
a.get_all_short_flag_aliases().collect::<Vec<_>>()
);
spec_vals.push(format!("[aliases: {}]", all_als));
spec_vals.push(format!("[aliases: {all_als}]"));
}
spec_vals.join(" ")

Some files were not shown because too many files have changed in this diff Show More