mirror of
https://gitee.com/openharmony/third_party_rust_clap
synced 2024-11-23 06:59:54 +00:00
clap 4.1.4升级至4.1.13
Signed-off-by: 徐未来 <xuweilai2@huawei.com>
This commit is contained in:
parent
4871ecbd72
commit
a85e791e75
37
.github/workflows/audit.yml
vendored
37
.github/workflows/audit.yml
vendored
@ -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
|
||||
|
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@ -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
|
||||
|
4
BUILD.gn
4
BUILD.gn
@ -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 = [
|
||||
|
70
CHANGELOG.md
70
CHANGELOG.md
@ -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
35
CITATION.cff
Normal 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
341
Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
24
Cargo.toml
24
Cargo.toml
@ -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"
|
||||
|
@ -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."
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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]]
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:#?}");
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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!(
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -42,7 +42,7 @@ impl FromStr for Shell {
|
||||
return Ok(*variant);
|
||||
}
|
||||
}
|
||||
Err(format!("invalid variant: {}", s))
|
||||
Err(format!("invalid variant: {s}"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
":"
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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]
|
||||
}
|
@ -0,0 +1 @@
|
||||
complete -c my-app -s h -l help -d 'Print help'
|
32
clap_complete/tests/snapshots/two_multi_valued_arguments.ps1
Normal file
32
clap_complete/tests/snapshots/two_multi_valued_arguments.ps1
Normal 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
|
||||
}
|
34
clap_complete/tests/snapshots/two_multi_valued_arguments.zsh
Normal file
34
clap_complete/tests/snapshots/two_multi_valued_arguments.zsh
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"] }
|
||||
|
@ -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 {
|
||||
|
@ -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",
|
||||
]
|
||||
}
|
||||
|
@ -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 = []
|
||||
|
@ -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
|
||||
|
@ -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")]
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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!()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
21
clap_derive/src/macros.rs
Normal 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)+)
|
||||
}};
|
||||
}
|
@ -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))
|
||||
|
22
clap_derive/src/utils/error.rs
Normal file
22
clap_derive/src/utils/error.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
pub mod error;
|
||||
|
||||
mod doc_comments;
|
||||
mod spanned;
|
||||
mod ty;
|
||||
|
@ -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" ]
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"] }
|
||||
|
@ -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
|
||||
|
@ -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>,
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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`:
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
15
clap_mangen/tests/snapshots/value_name_without_arg.bash.roff
Normal file
15
clap_mangen/tests/snapshots/value_name_without_arg.bash.roff
Normal 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
149
deny.toml
Normal 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 = []
|
@ -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);
|
||||
}
|
||||
|
@ -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:#?}");
|
||||
}
|
||||
|
@ -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:#?}");
|
||||
}
|
||||
|
@ -87,5 +87,5 @@ struct Cli {
|
||||
|
||||
fn main() {
|
||||
let args = Cli::parse();
|
||||
println!("{:#?}", args);
|
||||
println!("{args:#?}");
|
||||
}
|
||||
|
@ -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:#?}");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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...
|
||||
|
@ -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...");
|
||||
}
|
||||
|
@ -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())?;
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>,
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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}");
|
||||
}
|
||||
}
|
||||
|
@ -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}");
|
||||
}
|
||||
}
|
||||
|
@ -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:?}");
|
||||
}
|
||||
|
@ -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")]
|
||||
//! ```
|
||||
|
@ -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 {
|
||||
|
@ -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:#?}");
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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}`")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user