зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1915426 - Update clap/heck/darling/anstyle/strsim, r=glandium,supply-chain-reviewers
Updated: - heck 0.4.1 -> 0.5.0 - clap 4.4.5 -> 4.5.16 - darling v0.20.1 -> v0.20.10 - strsim 0.10.0 -> 0.11.1 - anstyle 1.0.3 -> 1.0.8 This is in preparation of the UniFFI 0.28 upgrade: https://bugzilla.mozilla.org/show_bug.cgi?id=1914241 Differential Revision: https://phabricator.services.mozilla.com/D220437
This commit is contained in:
Родитель
19b97ca2a6
Коммит
e2f0822153
|
@ -88,9 +88,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.3"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46"
|
||||
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||
|
||||
[[package]]
|
||||
name = "any_all_workaround"
|
||||
|
@ -790,9 +790,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.5"
|
||||
version = "4.5.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "824956d0dca8334758a5b7f7e50518d66ea319330cbceedcf76905c2f6ab30e3"
|
||||
checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -810,9 +810,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.5"
|
||||
version = "4.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "122ec64120a49b4563ccaedcbea7818d069ed8e9aa6d829b82d8a4128936b2ab"
|
||||
checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
|
@ -822,11 +822,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.4.2"
|
||||
version = "4.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
|
||||
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
|
@ -834,9 +834,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.5.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
|
||||
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
|
@ -1263,9 +1263,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.1"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944"
|
||||
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
|
@ -1273,9 +1273,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.1"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb"
|
||||
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
|
@ -1287,9 +1287,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.1"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
|
||||
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
|
@ -2666,9 +2666,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
version = "0.4.999"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
|
@ -5588,9 +5595,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "style"
|
||||
|
@ -6227,7 +6234,7 @@ dependencies = [
|
|||
"camino",
|
||||
"clap",
|
||||
"extend",
|
||||
"heck",
|
||||
"heck 0.4.999",
|
||||
"serde",
|
||||
"toml",
|
||||
"uniffi",
|
||||
|
@ -6320,7 +6327,7 @@ dependencies = [
|
|||
"fs-err",
|
||||
"glob",
|
||||
"goblin 0.8.1",
|
||||
"heck",
|
||||
"heck 0.4.999",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"serde",
|
||||
|
|
|
@ -172,6 +172,9 @@ hashbrown = { path = "build/rust/hashbrown" }
|
|||
# Patch `socket2` 0.4 to 0.5
|
||||
socket2 = { path = "build/rust/socket2" }
|
||||
|
||||
# Patch heck 0.4 to 0.5
|
||||
heck = { path = "build/rust/heck" }
|
||||
|
||||
# The following overrides point to dummy projects, as a temporary measure until this is resolved:
|
||||
# https://github.com/rust-lang/cargo/issues/6179
|
||||
js-sys = { path = "build/rust/dummy-web/js-sys" }
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "heck"
|
||||
version = "0.4.999"
|
||||
edition = "2018"
|
||||
license = "MPL-2.0"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies.heck]
|
||||
version = "0.5.0"
|
|
@ -0,0 +1,5 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
pub use heck::*;
|
|
@ -56,7 +56,7 @@ serde = { version = "1", features = ["alloc", "derive", "rc"] }
|
|||
serde_json = { version = "1", features = ["preserve_order", "unbounded_depth"], optional = true }
|
||||
smallvec = { version = "1", features = ["const_new", "serde", "union"], optional = true }
|
||||
stable_deref_trait = { version = "1", features = ["std"], optional = true }
|
||||
strsim = { version = "0.10", optional = true }
|
||||
strsim = { version = "0.11", optional = true }
|
||||
time = { version = "0.3", features = ["macros", "parsing", "serde"], optional = true }
|
||||
tinystr = { version = "0.7", features = ["zerovec"], optional = true }
|
||||
tokio = { version = "1", features = ["fs", "macros", "rt-multi-thread"], optional = true }
|
||||
|
|
|
@ -1512,6 +1512,11 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
|
|||
criteria = "safe-to-deploy"
|
||||
delta = "0.14.3 -> 0.20.1"
|
||||
|
||||
[[audits.darling]]
|
||||
who = "Ben Dean-Kawamura <bdk@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.20.1 -> 0.20.10"
|
||||
|
||||
[[audits.darling_core]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -1527,6 +1532,11 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
|
|||
criteria = "safe-to-deploy"
|
||||
delta = "0.14.3 -> 0.20.1"
|
||||
|
||||
[[audits.darling_core]]
|
||||
who = "Ben Dean-Kawamura <bdk@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.20.1 -> 0.20.10"
|
||||
|
||||
[[audits.darling_macro]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -1542,6 +1552,11 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
|
|||
criteria = "safe-to-deploy"
|
||||
delta = "0.14.3 -> 0.20.1"
|
||||
|
||||
[[audits.darling_macro]]
|
||||
who = "Ben Dean-Kawamura <bdk@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.20.1 -> 0.20.10"
|
||||
|
||||
[[audits.data-encoding]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -4217,6 +4232,11 @@ criteria = "safe-to-deploy"
|
|||
version = "0.1.2"
|
||||
notes = "This crate doesn't use unsafe block, network access and filesystem access."
|
||||
|
||||
[[audits.strsim]]
|
||||
who = "Ben Dean-Kawamura <bdk@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.10.0 -> 0.11.1"
|
||||
|
||||
[[audits.subtle]]
|
||||
who = "Simon Friedberger <simon@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -5504,7 +5524,7 @@ end = "2025-02-26"
|
|||
criteria = "safe-to-deploy"
|
||||
user-id = 6743 # Ed Page (epage)
|
||||
start = "2021-12-08"
|
||||
end = "2024-06-02"
|
||||
end = "2025-08-21"
|
||||
|
||||
[[trusted.clap_builder]]
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -5516,13 +5536,13 @@ end = "2024-06-02"
|
|||
criteria = "safe-to-deploy"
|
||||
user-id = 6743 # Ed Page (epage)
|
||||
start = "2021-12-08"
|
||||
end = "2024-06-02"
|
||||
end = "2025-08-21"
|
||||
|
||||
[[trusted.clap_lex]]
|
||||
criteria = "safe-to-deploy"
|
||||
user-id = 6743 # Ed Page (epage)
|
||||
start = "2022-04-15"
|
||||
end = "2024-06-02"
|
||||
end = "2025-08-21"
|
||||
|
||||
[[trusted.dtoa]]
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
|
@ -15,6 +15,13 @@ user-id = 6743
|
|||
user-login = "epage"
|
||||
user-name = "Ed Page"
|
||||
|
||||
[[publisher.anstyle]]
|
||||
version = "1.0.8"
|
||||
when = "2024-07-25"
|
||||
user-id = 6743
|
||||
user-login = "epage"
|
||||
user-name = "Ed Page"
|
||||
|
||||
[[publisher.arbitrary]]
|
||||
version = "1.3.2"
|
||||
when = "2023-10-30"
|
||||
|
@ -99,6 +106,13 @@ user-id = 6743
|
|||
user-login = "epage"
|
||||
user-name = "Ed Page"
|
||||
|
||||
[[publisher.clap]]
|
||||
version = "4.5.16"
|
||||
when = "2024-08-15"
|
||||
user-id = 6743
|
||||
user-login = "epage"
|
||||
user-name = "Ed Page"
|
||||
|
||||
[[publisher.clap_builder]]
|
||||
version = "4.4.5"
|
||||
when = "2023-09-25"
|
||||
|
@ -113,6 +127,13 @@ user-id = 6743
|
|||
user-login = "epage"
|
||||
user-name = "Ed Page"
|
||||
|
||||
[[publisher.clap_derive]]
|
||||
version = "4.5.13"
|
||||
when = "2024-07-31"
|
||||
user-id = 6743
|
||||
user-login = "epage"
|
||||
user-name = "Ed Page"
|
||||
|
||||
[[publisher.clap_lex]]
|
||||
version = "0.5.1"
|
||||
when = "2023-08-24"
|
||||
|
@ -120,6 +141,13 @@ user-id = 6743
|
|||
user-login = "epage"
|
||||
user-name = "Ed Page"
|
||||
|
||||
[[publisher.clap_lex]]
|
||||
version = "0.7.2"
|
||||
when = "2024-07-25"
|
||||
user-id = 6743
|
||||
user-login = "epage"
|
||||
user-name = "Ed Page"
|
||||
|
||||
[[publisher.core-foundation]]
|
||||
version = "0.9.3"
|
||||
when = "2022-02-07"
|
||||
|
@ -1033,6 +1061,12 @@ criteria = "safe-to-deploy"
|
|||
version = "0.4.0"
|
||||
notes = "Contains `forbid_unsafe` and only uses `std::fmt` from the standard library. Otherwise only contains string manipulation."
|
||||
|
||||
[[audits.bytecode-alliance.audits.heck]]
|
||||
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.4.1 -> 0.5.0"
|
||||
notes = "Minor changes for a `no_std` upgrade but otherwise everything looks as expected."
|
||||
|
||||
[[audits.bytecode-alliance.audits.id-arena]]
|
||||
who = "Nick Fitzgerald <fitzgen@gmail.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -1265,6 +1299,16 @@ delta = "2.5.0 -> 2.6.0"
|
|||
notes = "The changes from the previous version are negligible and thus it retains the same properties."
|
||||
aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
|
||||
|
||||
[[audits.google.audits.clap_builder]]
|
||||
who = "Lukasz Anforowicz <lukasza@chromium.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "4.5.15"
|
||||
notes = '''
|
||||
Grepped for `-i cipher`, `-i crypto`, `'\bfs\b'`, `'\bnet\b'`, `'\bunsafe\b'`
|
||||
and there were no hits.
|
||||
'''
|
||||
aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
|
||||
|
||||
[[audits.google.audits.equivalent]]
|
||||
who = "George Burgess IV <gbiv@google.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -1297,6 +1341,19 @@ criteria = "safe-to-deploy"
|
|||
version = "0.3.1"
|
||||
aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT"
|
||||
|
||||
[[audits.google.audits.heck]]
|
||||
who = "Lukasz Anforowicz <lukasza@chromium.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.4.1"
|
||||
notes = """
|
||||
Grepped for `-i cipher`, `-i crypto`, `'\bfs\b'``, `'\bnet\b'``, `'\bunsafe\b'``
|
||||
and there were no hits.
|
||||
|
||||
`heck` (version `0.3.3`) has been added to Chromium in
|
||||
https://source.chromium.org/chromium/chromium/src/+/28841c33c77833cc30b286f9ae24c97e7a8f4057
|
||||
"""
|
||||
aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
|
||||
|
||||
[[audits.google.audits.http]]
|
||||
who = "ChromeOS"
|
||||
criteria = "safe-to-run"
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.lock":"25a8765691ebacef2996651a2a08b57a2e9f7f782a7894fd3bb8016ca0c9a4e7","Cargo.toml":"1595ad36f00f988ce802dd2916ce25f07e476bf5d7440a192991d9472614c03c","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"3dad3b7606dec7ce40f54546e0dd485aeb52a45d4fcdfdaf830fd8349bbe43a5","README.md":"dcb157ba695dd8f1572944cc5bf84b8f67f8bb73925a5b725a9e274c755ce1a6","examples/dump.rs":"236dd2a3dce7512d1faeda5caec8d272299441b5d204696957940c687a021be8","src/color.rs":"33c9af0614e86612430e496d3add4cdcf4b9a6b5a8cc532d3caeb561a7d8fdfd","src/effect.rs":"c622c5472ba34d368a25341ce9488674b1e8516704aba80ae308e04b28136cd5","src/lib.rs":"0106395ba7263dbee67458e5ff4038cab493a3d34f3dcf0cb75504b1531a58e1","src/macros.rs":"0c90b45626fe8331d5b3326abb831f4ba6e04bcc975b1b9c01e465715050caa2","src/reset.rs":"65658e159fdf8f018bcfe6fdcfff688dbc4f3579fe1c685abdf92af6267165f8","src/style.rs":"f17ae53e38a3551ee8e3092f259aadfafabd3103e2db7fb3af291241dc6b8f46"},"package":"b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46"}
|
||||
{"files":{"Cargo.lock":"f1b654e343f2784fcee83c618945ba6ebfd0dfa378f2d77c231348150322c58b","Cargo.toml":"647d64af5a7a10bdad5bc17e6678315d80382da525737f04e05a8a9ff996ce31","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"3dad3b7606dec7ce40f54546e0dd485aeb52a45d4fcdfdaf830fd8349bbe43a5","README.md":"dcb157ba695dd8f1572944cc5bf84b8f67f8bb73925a5b725a9e274c755ce1a6","examples/dump-style.rs":"a6c89b70be79594485312ec4670886ea9f4bebbf2f39fedfbd16d92745824f82","src/color.rs":"5a53d01fe9c28794ffbbf6f687f2f2ab70f19beea583bbdf7bdf874ea8280886","src/effect.rs":"f4dc053212f0a0da33fb75ad5888feaf8a76be382e889e002f9e9c74885f98a2","src/lib.rs":"fdd7cb0f5ae4b6a964be6bccd0651dbde50d7bf82a24c044f4cc4ac61957e8dd","src/macros.rs":"0c90b45626fe8331d5b3326abb831f4ba6e04bcc975b1b9c01e465715050caa2","src/reset.rs":"df498292ee2670f40e101a99099135db29c603a01b7cb5124e4cd5e553b4e84b","src/style.rs":"9dbe81c3efc24603ba1bac2a8297f5118398b5799e546b1236e84767e181d3f0"},"package":"1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"}
|
|
@ -4,7 +4,7 @@ version = 3
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.3"
|
||||
version = "1.0.8"
|
||||
dependencies = [
|
||||
"lexopt",
|
||||
]
|
||||
|
|
|
@ -11,9 +11,10 @@
|
|||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.70.0"
|
||||
rust-version = "1.65.0"
|
||||
name = "anstyle"
|
||||
version = "1.0.3"
|
||||
version = "1.0.8"
|
||||
build = false
|
||||
include = [
|
||||
"build.rs",
|
||||
"src/**/*",
|
||||
|
@ -24,6 +25,10 @@ include = [
|
|||
"benches/**/*",
|
||||
"examples/**/*",
|
||||
]
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "ANSI text styling"
|
||||
homepage = "https://github.com/rust-cli/anstyle"
|
||||
readme = "README.md"
|
||||
|
@ -37,6 +42,13 @@ categories = ["command-line-interface"]
|
|||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rust-cli/anstyle.git"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"docsrs",
|
||||
]
|
||||
|
||||
[package.metadata.release]
|
||||
tag-prefix = ""
|
||||
|
||||
|
@ -75,6 +87,14 @@ replace = """
|
|||
[Unreleased]: https://github.com/rust-cli/anstyle/compare/{{tag_name}}...HEAD"""
|
||||
search = "<!-- next-url -->"
|
||||
|
||||
[lib]
|
||||
name = "anstyle"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[example]]
|
||||
name = "dump-style"
|
||||
path = "examples/dump-style.rs"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dev-dependencies.lexopt]
|
||||
|
@ -83,3 +103,73 @@ version = "0.3.0"
|
|||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
|
||||
[lints.clippy]
|
||||
bool_assert_comparison = "allow"
|
||||
branches_sharing_code = "allow"
|
||||
checked_conversions = "warn"
|
||||
collapsible_else_if = "allow"
|
||||
create_dir = "warn"
|
||||
dbg_macro = "warn"
|
||||
debug_assert_with_mut_call = "warn"
|
||||
doc_markdown = "warn"
|
||||
empty_enum = "warn"
|
||||
enum_glob_use = "warn"
|
||||
expl_impl_clone_on_copy = "warn"
|
||||
explicit_deref_methods = "warn"
|
||||
explicit_into_iter_loop = "warn"
|
||||
fallible_impl_from = "warn"
|
||||
filter_map_next = "warn"
|
||||
flat_map_option = "warn"
|
||||
float_cmp_const = "warn"
|
||||
fn_params_excessive_bools = "warn"
|
||||
from_iter_instead_of_collect = "warn"
|
||||
if_same_then_else = "allow"
|
||||
implicit_clone = "warn"
|
||||
imprecise_flops = "warn"
|
||||
inconsistent_struct_constructor = "warn"
|
||||
inefficient_to_string = "warn"
|
||||
infinite_loop = "warn"
|
||||
invalid_upcast_comparisons = "warn"
|
||||
items_after_statements = "warn"
|
||||
large_digit_groups = "warn"
|
||||
large_stack_arrays = "warn"
|
||||
large_types_passed_by_value = "warn"
|
||||
let_and_return = "allow"
|
||||
linkedlist = "warn"
|
||||
lossy_float_literal = "warn"
|
||||
macro_use_imports = "warn"
|
||||
match_wildcard_for_single_variants = "warn"
|
||||
mem_forget = "warn"
|
||||
mutex_integer = "warn"
|
||||
needless_continue = "warn"
|
||||
needless_for_each = "warn"
|
||||
negative_feature_names = "warn"
|
||||
path_buf_push_overwrite = "warn"
|
||||
ptr_as_ptr = "warn"
|
||||
rc_mutex = "warn"
|
||||
redundant_feature_names = "warn"
|
||||
ref_option_ref = "warn"
|
||||
rest_pat_in_fully_bound_structs = "warn"
|
||||
same_functions_in_if_condition = "warn"
|
||||
self_named_module_files = "warn"
|
||||
semicolon_if_nothing_returned = "warn"
|
||||
single_match_else = "warn"
|
||||
str_to_string = "warn"
|
||||
string_add = "warn"
|
||||
string_add_assign = "warn"
|
||||
string_lit_as_bytes = "warn"
|
||||
string_to_string = "warn"
|
||||
todo = "warn"
|
||||
trait_duplication_in_bounds = "warn"
|
||||
verbose_file_reads = "warn"
|
||||
wildcard_imports = "warn"
|
||||
zero_sized_map_values = "warn"
|
||||
|
||||
[lints.rust]
|
||||
rust_2018_idioms = "warn"
|
||||
unreachable_pub = "warn"
|
||||
unsafe_op_in_unsafe_fn = "warn"
|
||||
unused_lifetimes = "warn"
|
||||
unused_macro_rules = "warn"
|
||||
unused_qualifications = "warn"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Write ANSI escape code colored text
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
fn main() -> Result<(), lexopt::Error> {
|
||||
|
@ -6,39 +8,45 @@ fn main() -> Result<(), lexopt::Error> {
|
|||
let mut stdout = stdout.lock();
|
||||
|
||||
for fixed in 0..16 {
|
||||
let style = style(fixed, args.layer, args.effects);
|
||||
let color = anstyle::Ansi256Color(fixed)
|
||||
.into_ansi()
|
||||
.expect("4-bit range used");
|
||||
let style = style(color, args.layer, args.effects);
|
||||
let _ = print_number(&mut stdout, fixed, style);
|
||||
if fixed == 7 || fixed == 15 {
|
||||
let _ = writeln!(&mut stdout);
|
||||
}
|
||||
}
|
||||
|
||||
for r in 0..6 {
|
||||
let _ = writeln!(stdout);
|
||||
for g in 0..6 {
|
||||
for b in 0..6 {
|
||||
let fixed = r * 36 + g * 6 + b + 16;
|
||||
let style = style(fixed, args.layer, args.effects);
|
||||
let _ = print_number(&mut stdout, fixed, style);
|
||||
}
|
||||
for fixed in 16..232 {
|
||||
let col = (fixed - 16) % 36;
|
||||
if col == 0 {
|
||||
let _ = writeln!(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
for c in 0..24 {
|
||||
if 0 == c % 8 {
|
||||
let _ = writeln!(stdout);
|
||||
}
|
||||
let fixed = 232 + c;
|
||||
let style = style(fixed, args.layer, args.effects);
|
||||
let color = anstyle::Ansi256Color(fixed);
|
||||
let style = style(color, args.layer, args.effects);
|
||||
let _ = print_number(&mut stdout, fixed, style);
|
||||
}
|
||||
|
||||
let _ = writeln!(stdout);
|
||||
let _ = writeln!(stdout);
|
||||
for fixed in 232..=255 {
|
||||
let color = anstyle::Ansi256Color(fixed);
|
||||
let style = style(color, args.layer, args.effects);
|
||||
let _ = print_number(&mut stdout, fixed, style);
|
||||
}
|
||||
|
||||
let _ = writeln!(stdout);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn style(fixed: u8, layer: Layer, effects: anstyle::Effects) -> anstyle::Style {
|
||||
let color = anstyle::Ansi256Color(fixed).into();
|
||||
fn style(
|
||||
color: impl Into<anstyle::Color>,
|
||||
layer: Layer,
|
||||
effects: anstyle::Effects,
|
||||
) -> anstyle::Style {
|
||||
let color = color.into();
|
||||
(match layer {
|
||||
Layer::Fg => anstyle::Style::new().fg_color(Some(color)),
|
||||
Layer::Bg => anstyle::Style::new().bg_color(Some(color)),
|
||||
|
@ -51,13 +59,7 @@ fn print_number(
|
|||
fixed: u8,
|
||||
style: anstyle::Style,
|
||||
) -> std::io::Result<()> {
|
||||
write!(
|
||||
stdout,
|
||||
"{}{:>4}{}",
|
||||
style.render(),
|
||||
fixed,
|
||||
anstyle::Reset.render()
|
||||
)
|
||||
write!(stdout, "{style}{fixed:>3X}{style:#}",)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
|
@ -1,8 +1,18 @@
|
|||
/// Any ANSI color code scheme
|
||||
#[allow(clippy::exhaustive_enums)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Color {
|
||||
/// Available 4-bit ANSI color palette codes
|
||||
///
|
||||
/// The user's terminal defines the meaning of the each palette code.
|
||||
Ansi(AnsiColor),
|
||||
/// 256 (8-bit) color support
|
||||
///
|
||||
/// - `0..16` are [`AnsiColor`] palette codes
|
||||
/// - `0..232` map to [`RgbColor`] color values
|
||||
/// - `232..` map to [`RgbColor`] gray-scale values
|
||||
Ansi256(Ansi256Color),
|
||||
/// 24-bit ANSI RGB color codes
|
||||
Rgb(RgbColor),
|
||||
}
|
||||
|
||||
|
@ -23,9 +33,9 @@ impl Color {
|
|||
|
||||
/// Render the ANSI code for a foreground color
|
||||
#[inline]
|
||||
pub fn render_fg(self) -> impl core::fmt::Display {
|
||||
pub fn render_fg(self) -> impl core::fmt::Display + Copy {
|
||||
match self {
|
||||
Self::Ansi(color) => DisplayBuffer::default().write_str(color.as_fg_str()),
|
||||
Self::Ansi(color) => color.as_fg_buffer(),
|
||||
Self::Ansi256(color) => color.as_fg_buffer(),
|
||||
Self::Rgb(color) => color.as_fg_buffer(),
|
||||
}
|
||||
|
@ -35,7 +45,7 @@ impl Color {
|
|||
#[cfg(feature = "std")]
|
||||
pub(crate) fn write_fg_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> {
|
||||
let buffer = match self {
|
||||
Self::Ansi(color) => DisplayBuffer::default().write_str(color.as_fg_str()),
|
||||
Self::Ansi(color) => color.as_fg_buffer(),
|
||||
Self::Ansi256(color) => color.as_fg_buffer(),
|
||||
Self::Rgb(color) => color.as_fg_buffer(),
|
||||
};
|
||||
|
@ -44,9 +54,9 @@ impl Color {
|
|||
|
||||
/// Render the ANSI code for a background color
|
||||
#[inline]
|
||||
pub fn render_bg(self) -> impl core::fmt::Display {
|
||||
pub fn render_bg(self) -> impl core::fmt::Display + Copy {
|
||||
match self {
|
||||
Self::Ansi(color) => DisplayBuffer::default().write_str(color.as_bg_str()),
|
||||
Self::Ansi(color) => color.as_bg_buffer(),
|
||||
Self::Ansi256(color) => color.as_bg_buffer(),
|
||||
Self::Rgb(color) => color.as_bg_buffer(),
|
||||
}
|
||||
|
@ -56,7 +66,7 @@ impl Color {
|
|||
#[cfg(feature = "std")]
|
||||
pub(crate) fn write_bg_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> {
|
||||
let buffer = match self {
|
||||
Self::Ansi(color) => DisplayBuffer::default().write_str(color.as_bg_str()),
|
||||
Self::Ansi(color) => color.as_bg_buffer(),
|
||||
Self::Ansi256(color) => color.as_bg_buffer(),
|
||||
Self::Rgb(color) => color.as_bg_buffer(),
|
||||
};
|
||||
|
@ -64,7 +74,7 @@ impl Color {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn render_underline(self) -> impl core::fmt::Display {
|
||||
pub(crate) fn render_underline(self) -> impl core::fmt::Display + Copy {
|
||||
match self {
|
||||
Self::Ansi(color) => color.as_underline_buffer(),
|
||||
Self::Ansi256(color) => color.as_underline_buffer(),
|
||||
|
@ -122,6 +132,7 @@ impl From<(u8, u8, u8)> for Color {
|
|||
/// Available 4-bit ANSI color palette codes
|
||||
///
|
||||
/// The user's terminal defines the meaning of the each palette code.
|
||||
#[allow(clippy::exhaustive_enums)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum AnsiColor {
|
||||
|
@ -191,8 +202,8 @@ impl AnsiColor {
|
|||
|
||||
/// Render the ANSI code for a foreground color
|
||||
#[inline]
|
||||
pub fn render_fg(self) -> impl core::fmt::Display {
|
||||
self.as_fg_str()
|
||||
pub fn render_fg(self) -> impl core::fmt::Display + Copy {
|
||||
NullFormatter(self.as_fg_str())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -217,10 +228,15 @@ impl AnsiColor {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_fg_buffer(&self) -> DisplayBuffer {
|
||||
DisplayBuffer::default().write_str(self.as_fg_str())
|
||||
}
|
||||
|
||||
/// Render the ANSI code for a background color
|
||||
#[inline]
|
||||
pub fn render_bg(self) -> impl core::fmt::Display {
|
||||
self.as_bg_str()
|
||||
pub fn render_bg(self) -> impl core::fmt::Display + Copy {
|
||||
NullFormatter(self.as_bg_str())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -245,6 +261,11 @@ impl AnsiColor {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_bg_buffer(&self) -> DisplayBuffer {
|
||||
DisplayBuffer::default().write_str(self.as_bg_str())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_underline_buffer(&self) -> DisplayBuffer {
|
||||
// No per-color codes; must delegate to `Ansi256Color`
|
||||
|
@ -325,6 +346,7 @@ impl AnsiColor {
|
|||
/// - `0..16` are [`AnsiColor`] palette codes
|
||||
/// - `0..232` map to [`RgbColor`] color values
|
||||
/// - `232..` map to [`RgbColor`] gray-scale values
|
||||
#[allow(clippy::exhaustive_structs)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct Ansi256Color(pub u8);
|
||||
|
@ -344,11 +366,13 @@ impl Ansi256Color {
|
|||
crate::Style::new().fg_color(Some(Color::Ansi256(self)))
|
||||
}
|
||||
|
||||
/// Get the raw value
|
||||
#[inline]
|
||||
pub const fn index(self) -> u8 {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Convert to [`AnsiColor`] when there is a 1:1 mapping
|
||||
#[inline]
|
||||
pub const fn into_ansi(self) -> Option<AnsiColor> {
|
||||
match self.index() {
|
||||
|
@ -372,6 +396,7 @@ impl Ansi256Color {
|
|||
}
|
||||
}
|
||||
|
||||
/// Losslessly convert from [`AnsiColor`]
|
||||
#[inline]
|
||||
pub const fn from_ansi(color: AnsiColor) -> Self {
|
||||
match color {
|
||||
|
@ -396,7 +421,7 @@ impl Ansi256Color {
|
|||
|
||||
/// Render the ANSI code for a foreground color
|
||||
#[inline]
|
||||
pub fn render_fg(self) -> impl core::fmt::Display {
|
||||
pub fn render_fg(self) -> impl core::fmt::Display + Copy {
|
||||
self.as_fg_buffer()
|
||||
}
|
||||
|
||||
|
@ -410,7 +435,7 @@ impl Ansi256Color {
|
|||
|
||||
/// Render the ANSI code for a background color
|
||||
#[inline]
|
||||
pub fn render_bg(self) -> impl core::fmt::Display {
|
||||
pub fn render_bg(self) -> impl core::fmt::Display + Copy {
|
||||
self.as_bg_buffer()
|
||||
}
|
||||
|
||||
|
@ -446,6 +471,7 @@ impl From<AnsiColor> for Ansi256Color {
|
|||
}
|
||||
|
||||
/// 24-bit ANSI RGB color codes
|
||||
#[allow(clippy::exhaustive_structs)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct RgbColor(pub u8, pub u8, pub u8);
|
||||
|
||||
|
@ -464,16 +490,19 @@ impl RgbColor {
|
|||
crate::Style::new().fg_color(Some(Color::Rgb(self)))
|
||||
}
|
||||
|
||||
/// Red
|
||||
#[inline]
|
||||
pub const fn r(self) -> u8 {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Green
|
||||
#[inline]
|
||||
pub const fn g(self) -> u8 {
|
||||
self.1
|
||||
}
|
||||
|
||||
/// Blue
|
||||
#[inline]
|
||||
pub const fn b(self) -> u8 {
|
||||
self.2
|
||||
|
@ -481,7 +510,7 @@ impl RgbColor {
|
|||
|
||||
/// Render the ANSI code for a foreground color
|
||||
#[inline]
|
||||
pub fn render_fg(self) -> impl core::fmt::Display {
|
||||
pub fn render_fg(self) -> impl core::fmt::Display + Copy {
|
||||
self.as_fg_buffer()
|
||||
}
|
||||
|
||||
|
@ -499,7 +528,7 @@ impl RgbColor {
|
|||
|
||||
/// Render the ANSI code for a background color
|
||||
#[inline]
|
||||
pub fn render_bg(self) -> impl core::fmt::Display {
|
||||
pub fn render_bg(self) -> impl core::fmt::Display + Copy {
|
||||
self.as_bg_buffer()
|
||||
}
|
||||
|
||||
|
@ -536,9 +565,11 @@ impl From<(u8, u8, u8)> for RgbColor {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
const DISPLAY_BUFFER_CAPACITY: usize = 19;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
struct DisplayBuffer {
|
||||
buffer: [u8; 19],
|
||||
buffer: [u8; DISPLAY_BUFFER_CAPACITY],
|
||||
len: usize,
|
||||
}
|
||||
|
||||
|
@ -580,7 +611,10 @@ impl DisplayBuffer {
|
|||
#[inline]
|
||||
fn as_str(&self) -> &str {
|
||||
// SAFETY: Only `&str` can be written to the buffer
|
||||
unsafe { core::str::from_utf8_unchecked(&self.buffer[0..self.len]) }
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
core::str::from_utf8_unchecked(&self.buffer[0..self.len])
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -593,7 +627,19 @@ impl DisplayBuffer {
|
|||
impl core::fmt::Display for DisplayBuffer {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.as_str().fmt(f)
|
||||
let s = self.as_str();
|
||||
write!(f, "{s}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
struct NullFormatter<D: core::fmt::Display>(D);
|
||||
|
||||
impl<D: core::fmt::Display> core::fmt::Display for NullFormatter<D> {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let d = &self.0;
|
||||
write!(f, "{d}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -607,5 +653,35 @@ mod test {
|
|||
let c = RgbColor(255, 255, 255);
|
||||
let actual = c.render_fg().to_string();
|
||||
assert_eq!(actual, "\u{1b}[38;2;255;255;255m");
|
||||
assert_eq!(actual.len(), DISPLAY_BUFFER_CAPACITY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_size_of() {
|
||||
use std::mem::size_of;
|
||||
dbg!(size_of::<Color>());
|
||||
dbg!(size_of::<AnsiColor>());
|
||||
dbg!(size_of::<Ansi256Color>());
|
||||
dbg!(size_of::<RgbColor>());
|
||||
dbg!(size_of::<DisplayBuffer>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_align() {
|
||||
#[track_caller]
|
||||
fn assert_no_align(d: impl core::fmt::Display) {
|
||||
let expected = format!("{d}");
|
||||
let actual = format!("{d:<10}");
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
assert_no_align(AnsiColor::White.render_fg());
|
||||
assert_no_align(AnsiColor::White.render_bg());
|
||||
assert_no_align(Ansi256Color(0).render_fg());
|
||||
assert_no_align(Ansi256Color(0).render_bg());
|
||||
assert_no_align(RgbColor(0, 0, 0).render_fg());
|
||||
assert_no_align(RgbColor(0, 0, 0).render_bg());
|
||||
assert_no_align(Color::Ansi(AnsiColor::White).render_fg());
|
||||
assert_no_align(Color::Ansi(AnsiColor::White).render_bg());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,21 +9,30 @@
|
|||
pub struct Effects(u16);
|
||||
|
||||
impl Effects {
|
||||
/// No [`Effects`] applied
|
||||
const PLAIN: Self = Effects(0);
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub const BOLD: Self = Effects(1 << 0);
|
||||
#[allow(missing_docs)]
|
||||
pub const DIMMED: Self = Effects(1 << 1);
|
||||
/// Not widely supported. Sometimes treated as inverse or blink
|
||||
pub const ITALIC: Self = Effects(1 << 2);
|
||||
/// Style extensions exist for Kitty, VTE, mintty and iTerm2.
|
||||
pub const UNDERLINE: Self = Effects(1 << 3);
|
||||
#[allow(missing_docs)]
|
||||
pub const DOUBLE_UNDERLINE: Self = Effects(1 << 4);
|
||||
#[allow(missing_docs)]
|
||||
pub const CURLY_UNDERLINE: Self = Effects(1 << 5);
|
||||
#[allow(missing_docs)]
|
||||
pub const DOTTED_UNDERLINE: Self = Effects(1 << 6);
|
||||
#[allow(missing_docs)]
|
||||
pub const DASHED_UNDERLINE: Self = Effects(1 << 7);
|
||||
#[allow(missing_docs)]
|
||||
pub const BLINK: Self = Effects(1 << 8);
|
||||
/// Swap foreground and background colors; inconsistent emulation
|
||||
pub const INVERT: Self = Effects(1 << 9);
|
||||
#[allow(missing_docs)]
|
||||
pub const HIDDEN: Self = Effects(1 << 10);
|
||||
/// Characters legible but marked as if for deletion. Not supported in Terminal.app
|
||||
pub const STRIKETHROUGH: Self = Effects(1 << 11);
|
||||
|
@ -156,7 +165,7 @@ impl Effects {
|
|||
|
||||
/// Render the ANSI code
|
||||
#[inline]
|
||||
pub fn render(self) -> impl core::fmt::Display {
|
||||
pub fn render(self) -> impl core::fmt::Display + Copy {
|
||||
EffectsDisplay(self)
|
||||
}
|
||||
|
||||
|
@ -307,18 +316,21 @@ pub(crate) const METADATA: [Metadata; 12] = [
|
|||
},
|
||||
];
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
struct EffectsDisplay(Effects);
|
||||
|
||||
impl core::fmt::Display for EffectsDisplay {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
for index in self.0.index_iter() {
|
||||
METADATA[index].escape.fmt(f)?;
|
||||
let escape = METADATA[index].escape;
|
||||
write!(f, "{escape}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Enumerate each enabled value in [`Effects`]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct EffectIter {
|
||||
index: usize,
|
||||
|
@ -366,3 +378,28 @@ impl Iterator for EffectIndexIter {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "std")]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn print_size_of() {
|
||||
use std::mem::size_of;
|
||||
dbg!(size_of::<Effects>());
|
||||
dbg!(size_of::<EffectsDisplay>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_align() {
|
||||
#[track_caller]
|
||||
fn assert_no_align(d: impl core::fmt::Display) {
|
||||
let expected = format!("{d}");
|
||||
let actual = format!("{d:<10}");
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
assert_no_align(Effects::BOLD.render());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,12 @@
|
|||
//!
|
||||
//! User-styling parsers:
|
||||
//! - [anstyle-git](https://docs.rs/anstyle-git): Parse Git style descriptions
|
||||
//! - [anstyle-ls](https://docs.rs/anstyle-ls): Parse LS_COLORS style descriptions
|
||||
//! - [anstyle-ls](https://docs.rs/anstyle-ls): Parse `LS_COLORS` style descriptions
|
||||
//!
|
||||
//! Convert to other formats
|
||||
//! - [anstream](https://docs.rs/anstream): A simple cross platform library for writing colored text to a terminal
|
||||
//! - [anstyle-roff](https://docs.rs/anstyle-roff): For converting to ROFF
|
||||
//! - [anstyle-syntect](https://docs.rs/anstyle-syntect): For working with syntax highlighting
|
||||
//!
|
||||
//! Utilities
|
||||
//! - [anstyle-lossy](https://docs.rs/anstyle-lossy): Convert between `anstyle::Color` types
|
||||
|
@ -44,6 +45,10 @@
|
|||
//! ```
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![warn(missing_docs)]
|
||||
#![warn(clippy::print_stderr)]
|
||||
#![warn(clippy::print_stdout)]
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
|
|
@ -1,21 +1,47 @@
|
|||
/// Reset terminal formatting
|
||||
#[allow(clippy::exhaustive_structs)]
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Reset;
|
||||
|
||||
impl Reset {
|
||||
/// Render the ANSI code
|
||||
///
|
||||
/// `Reset` also implements `Display` directly, so calling this method is optional.
|
||||
#[inline]
|
||||
pub fn render(self) -> impl core::fmt::Display {
|
||||
ResetDisplay
|
||||
pub fn render(self) -> impl core::fmt::Display + Copy {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
struct ResetDisplay;
|
||||
|
||||
impl core::fmt::Display for ResetDisplay {
|
||||
impl core::fmt::Display for Reset {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
RESET.fmt(f)
|
||||
write!(f, "{RESET}")
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const RESET: &str = "\x1B[0m";
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "std")]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn print_size_of() {
|
||||
use std::mem::size_of;
|
||||
dbg!(size_of::<Reset>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_align() {
|
||||
#[track_caller]
|
||||
fn assert_no_align(d: impl core::fmt::Display) {
|
||||
let expected = format!("{d}");
|
||||
let actual = format!("{d:<10}");
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
assert_no_align(Reset);
|
||||
assert_no_align(Reset.render());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,17 @@ use crate::reset::RESET;
|
|||
|
||||
/// ANSI Text styling
|
||||
///
|
||||
/// You can print a `Style` to render the corresponding ANSI code.
|
||||
/// Using the alternate flag `#` will render the ANSI reset code, if needed.
|
||||
/// Together, this makes it convenient to render styles using inline format arguments.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// let style = anstyle::Style::new().bold();
|
||||
///
|
||||
/// let value = 42;
|
||||
/// println!("{style}{value}{style:#}");
|
||||
/// ```
|
||||
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Style {
|
||||
|
@ -91,11 +98,33 @@ impl Style {
|
|||
}
|
||||
|
||||
/// Render the ANSI code
|
||||
///
|
||||
/// `Style` also implements `Display` directly, so calling this method is optional.
|
||||
#[inline]
|
||||
pub fn render(self) -> impl core::fmt::Display {
|
||||
pub fn render(self) -> impl core::fmt::Display + Copy {
|
||||
StyleDisplay(self)
|
||||
}
|
||||
|
||||
fn fmt_to(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
use core::fmt::Display as _;
|
||||
|
||||
self.effects.render().fmt(f)?;
|
||||
|
||||
if let Some(fg) = self.fg {
|
||||
fg.render_fg().fmt(f)?;
|
||||
}
|
||||
|
||||
if let Some(bg) = self.bg {
|
||||
bg.render_bg().fmt(f)?;
|
||||
}
|
||||
|
||||
if let Some(underline) = self.underline {
|
||||
underline.render_underline().fmt(f)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write the ANSI code
|
||||
#[inline]
|
||||
#[cfg(feature = "std")]
|
||||
|
@ -121,7 +150,7 @@ impl Style {
|
|||
///
|
||||
/// Unlike [`Reset::render`][crate::Reset::render], this will elide the code if there is nothing to reset.
|
||||
#[inline]
|
||||
pub fn render_reset(self) -> impl core::fmt::Display {
|
||||
pub fn render_reset(self) -> impl core::fmt::Display + Copy {
|
||||
if self != Self::new() {
|
||||
RESET
|
||||
} else {
|
||||
|
@ -260,27 +289,32 @@ impl Style {
|
|||
|
||||
/// # Reflection
|
||||
impl Style {
|
||||
/// Get the foreground color
|
||||
#[inline]
|
||||
pub const fn get_fg_color(self) -> Option<crate::Color> {
|
||||
self.fg
|
||||
}
|
||||
|
||||
/// Get the background color
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub const fn get_bg_color(self) -> Option<crate::Color> {
|
||||
self.bg
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub const fn get_underline_color(self) -> Option<crate::Color> {
|
||||
self.underline
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub const fn get_effects(self) -> crate::Effects {
|
||||
self.effects
|
||||
}
|
||||
|
||||
/// Check if no effects are enabled
|
||||
/// Check if no styling is enabled
|
||||
#[inline]
|
||||
pub const fn is_plain(self) -> bool {
|
||||
self.fg.is_none()
|
||||
|
@ -366,7 +400,7 @@ impl core::ops::SubAssign<crate::Effects> for Style {
|
|||
/// assert_ne!(anstyle::Effects::UNDERLINE | effects, effects);
|
||||
/// assert_ne!(anstyle::RgbColor(0, 0, 0).on_default() | effects, effects);
|
||||
/// ```
|
||||
impl core::cmp::PartialEq<crate::Effects> for Style {
|
||||
impl PartialEq<crate::Effects> for Style {
|
||||
#[inline]
|
||||
fn eq(&self, other: &crate::Effects) -> bool {
|
||||
let other = Self::from(*other);
|
||||
|
@ -374,24 +408,30 @@ impl core::cmp::PartialEq<crate::Effects> for Style {
|
|||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for Style {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
if f.alternate() {
|
||||
self.render_reset().fmt(f)
|
||||
} else {
|
||||
self.fmt_to(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
struct StyleDisplay(Style);
|
||||
|
||||
impl core::fmt::Display for StyleDisplay {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
self.0.effects.render().fmt(f)?;
|
||||
|
||||
if let Some(fg) = self.0.fg {
|
||||
fg.render_fg().fmt(f)?;
|
||||
}
|
||||
|
||||
if let Some(bg) = self.0.bg {
|
||||
bg.render_bg().fmt(f)?;
|
||||
}
|
||||
|
||||
if let Some(underline) = self.0.underline {
|
||||
underline.render_underline().fmt(f)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
self.0.fmt_to(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "std")]
|
||||
fn print_size_of() {
|
||||
use std::mem::size_of;
|
||||
dbg!(size_of::<Style>());
|
||||
dbg!(size_of::<StyleDisplay>());
|
||||
}
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -11,9 +11,10 @@
|
|||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.70.0"
|
||||
rust-version = "1.74"
|
||||
name = "clap"
|
||||
version = "4.4.5"
|
||||
version = "4.5.16"
|
||||
build = false
|
||||
include = [
|
||||
"build.rs",
|
||||
"src/**/*",
|
||||
|
@ -23,6 +24,10 @@ include = [
|
|||
"benches/**/*",
|
||||
"examples/**/*",
|
||||
]
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
|
@ -100,6 +105,12 @@ file = "CITATION.cff"
|
|||
replace = "version: {{version}}"
|
||||
search = '^version: .+\..+\..+'
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
exactly = 1
|
||||
file = "src/lib.rs"
|
||||
replace = "blob/v{{version}}/CHANGELOG.md"
|
||||
search = 'blob/v.+\..+\..+/CHANGELOG.md'
|
||||
|
||||
[profile.bench]
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
|
@ -108,244 +119,258 @@ codegen-units = 1
|
|||
opt-level = 1
|
||||
|
||||
[lib]
|
||||
name = "clap"
|
||||
path = "src/lib.rs"
|
||||
bench = false
|
||||
|
||||
[[example]]
|
||||
name = "demo"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "cargo-example"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "cargo-example-derive"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "escaped-positional"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "escaped-positional-derive"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "find"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "git-derive"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "typed-derive"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "busybox"
|
||||
path = "examples/multicall-busybox.rs"
|
||||
|
||||
[[example]]
|
||||
name = "hostname"
|
||||
path = "examples/multicall-hostname.rs"
|
||||
|
||||
[[example]]
|
||||
name = "repl"
|
||||
path = "examples/repl.rs"
|
||||
required-features = ["help"]
|
||||
[[bin]]
|
||||
name = "stdio-fixture"
|
||||
path = "src/bin/stdio-fixture.rs"
|
||||
|
||||
[[example]]
|
||||
name = "01_quick"
|
||||
path = "examples/tutorial_builder/01_quick.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "02_apps"
|
||||
path = "examples/tutorial_builder/02_apps.rs"
|
||||
|
||||
[[example]]
|
||||
name = "02_crate"
|
||||
path = "examples/tutorial_builder/02_crate.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "02_app_settings"
|
||||
path = "examples/tutorial_builder/02_app_settings.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_01_flag_bool"
|
||||
path = "examples/tutorial_builder/03_01_flag_bool.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_01_flag_count"
|
||||
path = "examples/tutorial_builder/03_01_flag_count.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_02_option"
|
||||
path = "examples/tutorial_builder/03_02_option.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_02_option_mult"
|
||||
path = "examples/tutorial_builder/03_02_option_mult.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_03_positional"
|
||||
path = "examples/tutorial_builder/03_03_positional.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_03_positional_mult"
|
||||
path = "examples/tutorial_builder/03_03_positional_mult.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_04_subcommands"
|
||||
path = "examples/tutorial_builder/03_04_subcommands.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_05_default_values"
|
||||
path = "examples/tutorial_builder/03_05_default_values.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "04_01_possible"
|
||||
path = "examples/tutorial_builder/04_01_possible.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "04_01_enum"
|
||||
path = "examples/tutorial_builder/04_01_enum.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "04_02_parse"
|
||||
path = "examples/tutorial_builder/04_02_parse.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "04_02_validate"
|
||||
path = "examples/tutorial_builder/04_02_validate.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "04_03_relations"
|
||||
path = "examples/tutorial_builder/04_03_relations.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "04_04_custom"
|
||||
path = "examples/tutorial_builder/04_04_custom.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "05_01_assert"
|
||||
path = "examples/tutorial_builder/05_01_assert.rs"
|
||||
test = true
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "01_quick_derive"
|
||||
path = "examples/tutorial_derive/01_quick.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "02_apps_derive"
|
||||
path = "examples/tutorial_derive/02_apps.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "02_crate_derive"
|
||||
path = "examples/tutorial_derive/02_crate.rs"
|
||||
required-features = ["derive"]
|
||||
name = "02_app_settings"
|
||||
path = "examples/tutorial_builder/02_app_settings.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "02_app_settings_derive"
|
||||
path = "examples/tutorial_derive/02_app_settings.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "02_apps"
|
||||
path = "examples/tutorial_builder/02_apps.rs"
|
||||
|
||||
[[example]]
|
||||
name = "02_apps_derive"
|
||||
path = "examples/tutorial_derive/02_apps.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "02_crate"
|
||||
path = "examples/tutorial_builder/02_crate.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "02_crate_derive"
|
||||
path = "examples/tutorial_derive/02_crate.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "03_01_flag_bool"
|
||||
path = "examples/tutorial_builder/03_01_flag_bool.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_01_flag_bool_derive"
|
||||
path = "examples/tutorial_derive/03_01_flag_bool.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "03_01_flag_count"
|
||||
path = "examples/tutorial_builder/03_01_flag_count.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_01_flag_count_derive"
|
||||
path = "examples/tutorial_derive/03_01_flag_count.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "03_02_option"
|
||||
path = "examples/tutorial_builder/03_02_option.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_02_option_derive"
|
||||
path = "examples/tutorial_derive/03_02_option.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "03_02_option_mult"
|
||||
path = "examples/tutorial_builder/03_02_option_mult.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_02_option_mult_derive"
|
||||
path = "examples/tutorial_derive/03_02_option_mult.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "03_03_positional"
|
||||
path = "examples/tutorial_builder/03_03_positional.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_03_positional_derive"
|
||||
path = "examples/tutorial_derive/03_03_positional.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "03_03_positional_mult"
|
||||
path = "examples/tutorial_builder/03_03_positional_mult.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_03_positional_mult_derive"
|
||||
path = "examples/tutorial_derive/03_03_positional_mult.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "03_04_subcommands"
|
||||
path = "examples/tutorial_builder/03_04_subcommands.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_04_subcommands_alt_derive"
|
||||
path = "examples/tutorial_derive/03_04_subcommands_alt.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "03_04_subcommands_derive"
|
||||
path = "examples/tutorial_derive/03_04_subcommands.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "03_04_subcommands_alt_derive"
|
||||
path = "examples/tutorial_derive/03_04_subcommands_alt.rs"
|
||||
required-features = ["derive"]
|
||||
name = "03_05_default_values"
|
||||
path = "examples/tutorial_builder/03_05_default_values.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "03_05_default_values_derive"
|
||||
path = "examples/tutorial_derive/03_05_default_values.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "04_01_enum"
|
||||
path = "examples/tutorial_builder/04_01_enum.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "04_01_enum_derive"
|
||||
path = "examples/tutorial_derive/04_01_enum.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "04_01_possible"
|
||||
path = "examples/tutorial_builder/04_01_possible.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "04_02_parse"
|
||||
path = "examples/tutorial_builder/04_02_parse.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "04_02_parse_derive"
|
||||
path = "examples/tutorial_derive/04_02_parse.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "04_02_validate"
|
||||
path = "examples/tutorial_builder/04_02_validate.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "04_02_validate_derive"
|
||||
path = "examples/tutorial_derive/04_02_validate.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "04_03_relations"
|
||||
path = "examples/tutorial_builder/04_03_relations.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "04_03_relations_derive"
|
||||
path = "examples/tutorial_derive/04_03_relations.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "04_04_custom"
|
||||
path = "examples/tutorial_builder/04_04_custom.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "04_04_custom_derive"
|
||||
path = "examples/tutorial_derive/04_04_custom.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "05_01_assert"
|
||||
path = "examples/tutorial_builder/05_01_assert.rs"
|
||||
test = true
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "05_01_assert_derive"
|
||||
path = "examples/tutorial_derive/05_01_assert.rs"
|
||||
test = true
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "busybox"
|
||||
path = "examples/multicall-busybox.rs"
|
||||
|
||||
[[example]]
|
||||
name = "cargo-example"
|
||||
path = "examples/cargo-example.rs"
|
||||
required-features = [
|
||||
"cargo",
|
||||
"color",
|
||||
]
|
||||
|
||||
[[example]]
|
||||
name = "cargo-example-derive"
|
||||
path = "examples/cargo-example-derive.rs"
|
||||
required-features = [
|
||||
"derive",
|
||||
"color",
|
||||
]
|
||||
|
||||
[[example]]
|
||||
name = "demo"
|
||||
path = "examples/demo.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "escaped-positional"
|
||||
path = "examples/escaped-positional.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "escaped-positional-derive"
|
||||
path = "examples/escaped-positional-derive.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "find"
|
||||
path = "examples/find.rs"
|
||||
required-features = ["cargo"]
|
||||
|
||||
[[example]]
|
||||
name = "git"
|
||||
path = "examples/git.rs"
|
||||
|
||||
[[example]]
|
||||
name = "git-derive"
|
||||
path = "examples/git-derive.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "hostname"
|
||||
path = "examples/multicall-hostname.rs"
|
||||
|
||||
[[example]]
|
||||
name = "interop_augment_args"
|
||||
path = "examples/derive_ref/augment_args.rs"
|
||||
|
@ -356,44 +381,67 @@ name = "interop_augment_subcommands"
|
|||
path = "examples/derive_ref/augment_subcommands.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "interop_flatten_hand_args"
|
||||
path = "examples/derive_ref/flatten_hand_args.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "interop_hand_subcommand"
|
||||
path = "examples/derive_ref/hand_subcommand.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "interop_flatten_hand_args"
|
||||
path = "examples/derive_ref/flatten_hand_args.rs"
|
||||
name = "pacman"
|
||||
path = "examples/pacman.rs"
|
||||
|
||||
[[example]]
|
||||
name = "repl"
|
||||
path = "examples/repl.rs"
|
||||
required-features = ["help"]
|
||||
|
||||
[[example]]
|
||||
name = "repl-derive"
|
||||
path = "examples/repl-derive.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[[example]]
|
||||
name = "typed-derive"
|
||||
path = "examples/typed-derive.rs"
|
||||
required-features = ["derive"]
|
||||
|
||||
[dependencies.clap_builder]
|
||||
version = "=4.4.5"
|
||||
version = "=4.5.15"
|
||||
default-features = false
|
||||
|
||||
[dependencies.clap_derive]
|
||||
version = "=4.4.2"
|
||||
version = "=4.5.13"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.automod]
|
||||
version = "1.0.14"
|
||||
|
||||
[dev-dependencies.clap-cargo]
|
||||
version = "0.14.1"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.humantime]
|
||||
version = "2.1.0"
|
||||
|
||||
[dev-dependencies.rustversion]
|
||||
version = "1.0.14"
|
||||
version = "1.0.15"
|
||||
|
||||
[dev-dependencies.shlex]
|
||||
version = "1.1.0"
|
||||
version = "1.3.0"
|
||||
|
||||
[dev-dependencies.snapbox]
|
||||
version = "0.4.12"
|
||||
|
||||
[dev-dependencies.static_assertions]
|
||||
version = "1.1.0"
|
||||
version = "0.6.16"
|
||||
|
||||
[dev-dependencies.trybuild]
|
||||
version = "1.0.83"
|
||||
version = "1.0.91"
|
||||
|
||||
[dev-dependencies.trycmd]
|
||||
version = "0.14.17"
|
||||
version = "0.15.3"
|
||||
features = [
|
||||
"color-auto",
|
||||
"diff",
|
||||
|
@ -401,9 +449,6 @@ features = [
|
|||
]
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.unic-emoji-char]
|
||||
version = "0.9.0"
|
||||
|
||||
[features]
|
||||
cargo = ["clap_builder/cargo"]
|
||||
color = ["clap_builder/color"]
|
||||
|
@ -435,6 +480,7 @@ unstable-doc = [
|
|||
"clap_builder/unstable-doc",
|
||||
"derive",
|
||||
]
|
||||
unstable-ext = ["clap_builder/unstable-ext"]
|
||||
unstable-styles = ["clap_builder/unstable-styles"]
|
||||
unstable-v5 = [
|
||||
"clap_builder/unstable-v5",
|
||||
|
@ -443,3 +489,72 @@ unstable-v5 = [
|
|||
]
|
||||
usage = ["clap_builder/usage"]
|
||||
wrap_help = ["clap_builder/wrap_help"]
|
||||
|
||||
[lints.clippy]
|
||||
assigning_clones = "allow"
|
||||
blocks_in_conditions = "allow"
|
||||
bool_assert_comparison = "allow"
|
||||
branches_sharing_code = "allow"
|
||||
checked_conversions = "warn"
|
||||
collapsible_else_if = "allow"
|
||||
create_dir = "warn"
|
||||
dbg_macro = "warn"
|
||||
debug_assert_with_mut_call = "warn"
|
||||
doc_markdown = "warn"
|
||||
empty_enum = "warn"
|
||||
enum_glob_use = "warn"
|
||||
expl_impl_clone_on_copy = "warn"
|
||||
explicit_deref_methods = "warn"
|
||||
explicit_into_iter_loop = "warn"
|
||||
fallible_impl_from = "warn"
|
||||
filter_map_next = "warn"
|
||||
flat_map_option = "warn"
|
||||
float_cmp_const = "warn"
|
||||
fn_params_excessive_bools = "warn"
|
||||
from_iter_instead_of_collect = "warn"
|
||||
if_same_then_else = "allow"
|
||||
implicit_clone = "warn"
|
||||
imprecise_flops = "warn"
|
||||
inconsistent_struct_constructor = "warn"
|
||||
inefficient_to_string = "warn"
|
||||
infinite_loop = "warn"
|
||||
invalid_upcast_comparisons = "warn"
|
||||
large_digit_groups = "warn"
|
||||
large_stack_arrays = "warn"
|
||||
large_types_passed_by_value = "warn"
|
||||
let_and_return = "allow"
|
||||
linkedlist = "warn"
|
||||
lossy_float_literal = "warn"
|
||||
macro_use_imports = "warn"
|
||||
mem_forget = "warn"
|
||||
multiple_bound_locations = "allow"
|
||||
mutex_integer = "warn"
|
||||
needless_continue = "warn"
|
||||
needless_for_each = "warn"
|
||||
negative_feature_names = "warn"
|
||||
path_buf_push_overwrite = "warn"
|
||||
ptr_as_ptr = "warn"
|
||||
rc_mutex = "warn"
|
||||
redundant_feature_names = "warn"
|
||||
ref_option_ref = "warn"
|
||||
rest_pat_in_fully_bound_structs = "warn"
|
||||
same_functions_in_if_condition = "warn"
|
||||
self_named_module_files = "warn"
|
||||
semicolon_if_nothing_returned = "warn"
|
||||
string_add_assign = "warn"
|
||||
string_lit_as_bytes = "warn"
|
||||
todo = "warn"
|
||||
trait_duplication_in_bounds = "warn"
|
||||
verbose_file_reads = "warn"
|
||||
zero_sized_map_values = "warn"
|
||||
|
||||
[lints.rust]
|
||||
unreachable_pub = "warn"
|
||||
unsafe_op_in_unsafe_fn = "warn"
|
||||
unused_lifetimes = "warn"
|
||||
unused_macro_rules = "warn"
|
||||
unused_qualifications = "warn"
|
||||
|
||||
[lints.rust.rust_2018_idioms]
|
||||
level = "warn"
|
||||
priority = -1
|
||||
|
|
|
@ -3,12 +3,23 @@ use clap::Parser;
|
|||
#[derive(Parser)] // requires `derive` feature
|
||||
#[command(name = "cargo")]
|
||||
#[command(bin_name = "cargo")]
|
||||
#[command(styles = CLAP_STYLING)]
|
||||
enum CargoCli {
|
||||
ExampleDerive(ExampleDeriveArgs),
|
||||
}
|
||||
|
||||
// See also `clap_cargo::style::CLAP_STYLING`
|
||||
pub const CLAP_STYLING: clap::builder::styling::Styles = clap::builder::styling::Styles::styled()
|
||||
.header(clap_cargo::style::HEADER)
|
||||
.usage(clap_cargo::style::USAGE)
|
||||
.literal(clap_cargo::style::LITERAL)
|
||||
.placeholder(clap_cargo::style::PLACEHOLDER)
|
||||
.error(clap_cargo::style::ERROR)
|
||||
.valid(clap_cargo::style::VALID)
|
||||
.invalid(clap_cargo::style::INVALID);
|
||||
|
||||
#[derive(clap::Args)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct ExampleDeriveArgs {
|
||||
#[arg(long)]
|
||||
manifest_path: Option<std::path::PathBuf>,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
fn main() {
|
||||
let cmd = clap::Command::new("cargo")
|
||||
.bin_name("cargo")
|
||||
.styles(CLAP_STYLING)
|
||||
.subcommand_required(true)
|
||||
.subcommand(
|
||||
clap::command!("example").arg(
|
||||
|
@ -16,3 +17,13 @@ fn main() {
|
|||
let manifest_path = matches.get_one::<std::path::PathBuf>("manifest-path");
|
||||
println!("{manifest_path:?}");
|
||||
}
|
||||
|
||||
// See also `clap_cargo::style::CLAP_STYLING`
|
||||
pub const CLAP_STYLING: clap::builder::styling::Styles = clap::builder::styling::Styles::styled()
|
||||
.header(clap_cargo::style::HEADER)
|
||||
.usage(clap_cargo::style::USAGE)
|
||||
.literal(clap_cargo::style::LITERAL)
|
||||
.placeholder(clap_cargo::style::PLACEHOLDER)
|
||||
.error(clap_cargo::style::ERROR)
|
||||
.valid(clap_cargo::style::VALID)
|
||||
.invalid(clap_cargo::style::INVALID);
|
||||
|
|
|
@ -2,7 +2,7 @@ use clap::Parser;
|
|||
|
||||
/// Simple program to greet a person
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Args {
|
||||
/// Name of the person to greet
|
||||
#[arg(short, long)]
|
||||
|
@ -17,6 +17,6 @@ fn main() {
|
|||
let args = Args::parse();
|
||||
|
||||
for _ in 0..args.count {
|
||||
println!("Hello {}!", args.name)
|
||||
println!("Hello {}!", args.name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#![allow(dead_code)]
|
||||
use clap::error::{Error, ErrorKind};
|
||||
use clap::{ArgMatches, Args as _, Command, FromArgMatches, Parser, Subcommand};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)] // requires `derive` feature
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[arg(short = 'f')]
|
||||
eff: bool,
|
||||
|
|
|
@ -12,7 +12,7 @@ Options:
|
|||
|
||||
TESTS:
|
||||
--empty File is empty and is either a regular file or a directory
|
||||
--name <NAME> Base of file name (the path with the leading directories removed) matches shell
|
||||
--name <name> Base of file name (the path with the leading directories removed) matches shell
|
||||
pattern pattern
|
||||
|
||||
OPERATORS:
|
||||
|
@ -41,5 +41,39 @@ $ find --empty -o --name .keep
|
|||
),
|
||||
]
|
||||
|
||||
$ find --empty -o --name .keep -o --name foo
|
||||
[
|
||||
(
|
||||
"empty",
|
||||
Bool(
|
||||
true,
|
||||
),
|
||||
),
|
||||
(
|
||||
"or",
|
||||
Bool(
|
||||
true,
|
||||
),
|
||||
),
|
||||
(
|
||||
"name",
|
||||
String(
|
||||
".keep",
|
||||
),
|
||||
),
|
||||
(
|
||||
"or",
|
||||
Bool(
|
||||
true,
|
||||
),
|
||||
),
|
||||
(
|
||||
"name",
|
||||
String(
|
||||
"foo",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
```
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use clap::{arg, command, ArgGroup, ArgMatches, Command};
|
||||
use clap::{command, value_parser, Arg, ArgAction, ArgGroup, ArgMatches, Command};
|
||||
|
||||
fn main() {
|
||||
let matches = cli().get_matches();
|
||||
|
@ -13,17 +13,44 @@ fn cli() -> Command {
|
|||
.group(ArgGroup::new("tests").multiple(true))
|
||||
.next_help_heading("TESTS")
|
||||
.args([
|
||||
arg!(--empty "File is empty and is either a regular file or a directory").group("tests"),
|
||||
arg!(--name <NAME> "Base of file name (the path with the leading directories removed) matches shell pattern pattern").group("tests"),
|
||||
position_sensitive_flag(Arg::new("empty"))
|
||||
.long("empty")
|
||||
.action(ArgAction::Append)
|
||||
.help("File is empty and is either a regular file or a directory")
|
||||
.group("tests"),
|
||||
Arg::new("name")
|
||||
.long("name")
|
||||
.action(ArgAction::Append)
|
||||
.help("Base of file name (the path with the leading directories removed) matches shell pattern pattern")
|
||||
.group("tests")
|
||||
])
|
||||
.group(ArgGroup::new("operators").multiple(true))
|
||||
.next_help_heading("OPERATORS")
|
||||
.args([
|
||||
arg!(-o - -or "expr2 is not evaluate if exp1 is true").group("operators"),
|
||||
arg!(-a - -and "Same as `expr1 expr1`").group("operators"),
|
||||
position_sensitive_flag(Arg::new("or"))
|
||||
.short('o')
|
||||
.long("or")
|
||||
.action(ArgAction::Append)
|
||||
.help("expr2 is not evaluate if exp1 is true")
|
||||
.group("operators"),
|
||||
position_sensitive_flag(Arg::new("and"))
|
||||
.short('a')
|
||||
.long("and")
|
||||
.action(ArgAction::Append)
|
||||
.help("Same as `expr1 expr1`")
|
||||
.group("operators"),
|
||||
])
|
||||
}
|
||||
|
||||
fn position_sensitive_flag(arg: Arg) -> Arg {
|
||||
// Flags don't track the position of each occurrence, so we need to emulate flags with
|
||||
// value-less options to get the same result
|
||||
arg.num_args(0)
|
||||
.value_parser(value_parser!(bool))
|
||||
.default_missing_value("true")
|
||||
.default_value("false")
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum Value {
|
||||
Bool(bool),
|
||||
|
|
|
@ -73,18 +73,31 @@ Default subcommand:
|
|||
```console
|
||||
$ git-derive stash -h
|
||||
Usage: git-derive[EXE] stash [OPTIONS]
|
||||
git-derive[EXE] stash <COMMAND>
|
||||
|
||||
Commands:
|
||||
push
|
||||
pop
|
||||
apply
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
git-derive[EXE] stash push [OPTIONS]
|
||||
git-derive[EXE] stash pop [STASH]
|
||||
git-derive[EXE] stash apply [STASH]
|
||||
git-derive[EXE] stash help [COMMAND]...
|
||||
|
||||
Options:
|
||||
-m, --message <MESSAGE>
|
||||
-h, --help Print help
|
||||
|
||||
git-derive[EXE] stash push:
|
||||
-m, --message <MESSAGE>
|
||||
-h, --help Print help
|
||||
|
||||
git-derive[EXE] stash pop:
|
||||
-h, --help Print help
|
||||
[STASH]
|
||||
|
||||
git-derive[EXE] stash apply:
|
||||
-h, --help Print help
|
||||
[STASH]
|
||||
|
||||
git-derive[EXE] stash help:
|
||||
Print this message or the help of the given subcommand(s)
|
||||
[COMMAND]... Print help for the subcommand(s)
|
||||
|
||||
$ git-derive stash push -h
|
||||
Usage: git-derive[EXE] stash push [OPTIONS]
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ impl std::fmt::Display for ColorWhen {
|
|||
|
||||
#[derive(Debug, Args)]
|
||||
#[command(args_conflicts_with_subcommands = true)]
|
||||
#[command(flatten_help = true)]
|
||||
struct StashArgs {
|
||||
#[command(subcommand)]
|
||||
command: Option<StashCommands>,
|
||||
|
|
|
@ -71,18 +71,31 @@ Default subcommand:
|
|||
```console
|
||||
$ git stash -h
|
||||
Usage: git[EXE] stash [OPTIONS]
|
||||
git[EXE] stash <COMMAND>
|
||||
|
||||
Commands:
|
||||
push
|
||||
pop
|
||||
apply
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
git[EXE] stash push [OPTIONS]
|
||||
git[EXE] stash pop [STASH]
|
||||
git[EXE] stash apply [STASH]
|
||||
git[EXE] stash help [COMMAND]...
|
||||
|
||||
Options:
|
||||
-m, --message <MESSAGE>
|
||||
-h, --help Print help
|
||||
|
||||
git[EXE] stash push:
|
||||
-m, --message <MESSAGE>
|
||||
-h, --help Print help
|
||||
|
||||
git[EXE] stash pop:
|
||||
-h, --help Print help
|
||||
[STASH]
|
||||
|
||||
git[EXE] stash apply:
|
||||
-h, --help Print help
|
||||
[STASH]
|
||||
|
||||
git[EXE] stash help:
|
||||
Print this message or the help of the given subcommand(s)
|
||||
[COMMAND]... Print help for the subcommand(s)
|
||||
|
||||
$ git stash push -h
|
||||
Usage: git[EXE] stash push [OPTIONS]
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ fn cli() -> Command {
|
|||
.subcommand(
|
||||
Command::new("stash")
|
||||
.args_conflicts_with_subcommands(true)
|
||||
.flatten_help(true)
|
||||
.args(push_args())
|
||||
.subcommand(Command::new("push").args(push_args()))
|
||||
.subcommand(Command::new("pop").arg(arg!([STASH])))
|
||||
|
|
|
@ -6,7 +6,6 @@ fn main() {
|
|||
.version("5.2.1")
|
||||
.subcommand_required(true)
|
||||
.arg_required_else_help(true)
|
||||
.author("Pacman Development Team")
|
||||
// Query subcommand
|
||||
//
|
||||
// Only a few of its arguments are implemented below.
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
use std::io::Write;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
fn main() -> Result<(), String> {
|
||||
loop {
|
||||
let line = readline()?;
|
||||
let line = line.trim();
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
match respond(line) {
|
||||
Ok(quit) => {
|
||||
if quit {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
write!(std::io::stdout(), "{err}").map_err(|e| e.to_string())?;
|
||||
std::io::stdout().flush().map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn respond(line: &str) -> Result<bool, String> {
|
||||
let args = shlex::split(line).ok_or("error: Invalid quoting")?;
|
||||
let cli = Cli::try_parse_from(args).map_err(|e| e.to_string())?;
|
||||
match cli.command {
|
||||
Commands::Ping => {
|
||||
write!(std::io::stdout(), "Pong").map_err(|e| e.to_string())?;
|
||||
std::io::stdout().flush().map_err(|e| e.to_string())?;
|
||||
}
|
||||
Commands::Exit => {
|
||||
write!(std::io::stdout(), "Exiting ...").map_err(|e| e.to_string())?;
|
||||
std::io::stdout().flush().map_err(|e| e.to_string())?;
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(multicall = true)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum Commands {
|
||||
Ping,
|
||||
Exit,
|
||||
}
|
||||
|
||||
fn readline() -> Result<String, String> {
|
||||
write!(std::io::stdout(), "$ ").map_err(|e| e.to_string())?;
|
||||
std::io::stdout().flush().map_err(|e| e.to_string())?;
|
||||
let mut buffer = String::new();
|
||||
std::io::stdin()
|
||||
.read_line(&mut buffer)
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(buffer)
|
||||
}
|
|
@ -36,7 +36,7 @@ fn main() {
|
|||
// Note, only flags can have multiple occurrences
|
||||
match matches
|
||||
.get_one::<u8>("debug")
|
||||
.expect("Count's are defaulted")
|
||||
.expect("Counts are defaulted")
|
||||
{
|
||||
0 => println!("Debug mode is off"),
|
||||
1 => println!("Debug mode is kind of on"),
|
||||
|
|
|
@ -3,7 +3,6 @@ use clap::{arg, Command};
|
|||
fn main() {
|
||||
let matches = Command::new("MyApp")
|
||||
.version("1.0")
|
||||
.author("Kevin K. <kbknapp@gmail.com>")
|
||||
.about("Does awesome things")
|
||||
.arg(arg!(--two <VALUE>).required(true))
|
||||
.arg(arg!(--one <VALUE>).required(true))
|
||||
|
|
|
@ -10,21 +10,15 @@ Options:
|
|||
-V, --version Print version
|
||||
|
||||
$ 03_02_option_mult
|
||||
name: None
|
||||
names: []
|
||||
|
||||
$ 03_02_option_mult --name bob
|
||||
name: Some("bob")
|
||||
names: ["bob"]
|
||||
|
||||
$ 03_02_option_mult --name=bob
|
||||
name: Some("bob")
|
||||
$ 03_02_option_mult --name bob --name john
|
||||
names: ["bob", "john"]
|
||||
|
||||
$ 03_02_option_mult -n bob
|
||||
name: Some("bob")
|
||||
|
||||
$ 03_02_option_mult -n=bob
|
||||
name: Some("bob")
|
||||
|
||||
$ 03_02_option_mult -nbob
|
||||
name: Some("bob")
|
||||
$ 03_02_option_mult_derive --name bob --name=john -n tom -n=chris -nsteve
|
||||
name: ["bob", "john", "tom", "chris", "steve"]
|
||||
|
||||
```
|
||||
|
|
|
@ -10,5 +10,11 @@ fn main() {
|
|||
)
|
||||
.get_matches();
|
||||
|
||||
println!("name: {:?}", matches.get_one::<String>("name"));
|
||||
let args = matches
|
||||
.get_many::<String>("name")
|
||||
.unwrap_or_default()
|
||||
.map(|v| v.as_str())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
println!("names: {:?}", &args);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ impl ValueEnum for Mode {
|
|||
&[Mode::Fast, Mode::Slow]
|
||||
}
|
||||
|
||||
fn to_possible_value<'a>(&self) -> Option<PossibleValue> {
|
||||
fn to_possible_value(&self) -> Option<PossibleValue> {
|
||||
Some(match self {
|
||||
Mode::Fast => PossibleValue::new("fast").help("Run swiftly"),
|
||||
Mode::Slow => PossibleValue::new("slow").help("Crawl slowly but steadily"),
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::path::PathBuf;
|
|||
use clap::{Parser, Subcommand};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
/// Optional name to operate on
|
||||
name: Option<String>,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
#[command(next_line_help = true)]
|
||||
struct Cli {
|
||||
#[arg(long)]
|
||||
|
|
|
@ -2,7 +2,6 @@ use clap::Parser;
|
|||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "MyApp")]
|
||||
#[command(author = "Kevin K. <kbknapp@gmail.com>")]
|
||||
#[command(version = "1.0")]
|
||||
#[command(about = "Does awesome things", long_about = None)]
|
||||
struct Cli {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)] // Read from `Cargo.toml`
|
||||
#[command(version, about, long_about = None)] // Read from `Cargo.toml`
|
||||
struct Cli {
|
||||
#[arg(long)]
|
||||
two: String,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[arg(short, long)]
|
||||
verbose: bool,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[arg(short, long, action = clap::ArgAction::Count)]
|
||||
verbose: u8,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[arg(short, long)]
|
||||
name: Option<String>,
|
||||
|
|
|
@ -15,16 +15,10 @@ name: []
|
|||
$ 03_02_option_mult_derive --name bob
|
||||
name: ["bob"]
|
||||
|
||||
$ 03_02_option_mult_derive --name=bob
|
||||
name: ["bob"]
|
||||
$ 03_02_option_mult_derive --name bob --name john
|
||||
name: ["bob", "john"]
|
||||
|
||||
$ 03_02_option_mult_derive -n bob
|
||||
name: ["bob"]
|
||||
|
||||
$ 03_02_option_mult_derive -n=bob
|
||||
name: ["bob"]
|
||||
|
||||
$ 03_02_option_mult_derive -nbob
|
||||
name: ["bob"]
|
||||
$ 03_02_option_mult_derive --name bob --name=john -n tom -n=chris -nsteve
|
||||
name: ["bob", "john", "tom", "chris", "steve"]
|
||||
|
||||
```
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[arg(short, long)]
|
||||
name: Vec<String>,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
name: Option<String>,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
name: Vec<String>,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::{Parser, Subcommand};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
#[command(propagate_version = true)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
|
@ -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:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::{Args, Parser, Subcommand};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
#[command(propagate_version = true)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
|
@ -26,7 +26,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.name)
|
||||
println!("'myapp add' was used, name is: {:?}", name.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[arg(default_value_t = 2020)]
|
||||
port: u16,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::{Parser, ValueEnum};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
/// What mode to run the program in
|
||||
#[arg(value_enum)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
/// Network port to use
|
||||
#[arg(value_parser = clap::value_parser!(u16).range(1..))]
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::ops::RangeInclusive;
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
/// Network port to use
|
||||
#[arg(value_parser = port_in_range)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::{Args, Parser};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[command(flatten)]
|
||||
vers: Vers,
|
||||
|
|
|
@ -2,7 +2,7 @@ use clap::error::ErrorKind;
|
|||
use clap::{CommandFactory, Parser};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
/// set version manually
|
||||
#[arg(long, value_name = "VER")]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
/// Network port to use
|
||||
port: u16,
|
||||
|
@ -16,5 +16,5 @@ fn main() {
|
|||
#[test]
|
||||
fn verify_cli() {
|
||||
use clap::CommandFactory;
|
||||
Cli::command().debug_assert()
|
||||
Cli::command().debug_assert();
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ where
|
|||
|
||||
mod foreign_crate {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum LogLevel {
|
||||
pub(crate) enum LogLevel {
|
||||
Trace,
|
||||
Debug,
|
||||
Info,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
//! - Topics:
|
||||
//! - Subcommands
|
||||
//! - Cargo plugins
|
||||
//! - custom terminal [styles][crate::Command::styles] (colors)
|
||||
//!
|
||||
//! find-like interface: [builder][find]
|
||||
//! - Topics:
|
||||
|
@ -43,7 +44,7 @@
|
|||
//! - Topics:
|
||||
//! - Subcommands
|
||||
//!
|
||||
//! repl: [builder][repl]
|
||||
//! repl: [builder][repl], [derive][repl_derive]
|
||||
//! - Topics:
|
||||
//! - Read-Eval-Print Loops / Custom command lines
|
||||
|
||||
|
@ -58,4 +59,5 @@ pub mod multicall_busybox;
|
|||
pub mod multicall_hostname;
|
||||
pub mod pacman;
|
||||
pub mod repl;
|
||||
pub mod repl_derive;
|
||||
pub mod typed_derive;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
//! # Example: REPL (Derive API)
|
||||
//!
|
||||
//! ```rust
|
||||
#![doc = include_str!("../../examples/repl-derive.rs")]
|
|
@ -22,4 +22,4 @@
|
|||
use crate::builder::*;
|
||||
|
||||
pub use super::chapter_1 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
pub use crate::_derive::_tutorial as table_of_contents;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//!
|
||||
#![doc = include_str!("../../../examples/tutorial_derive/02_apps.md")]
|
||||
//!
|
||||
//! You can use [`#[command(author, version, about)]` attribute defaults][super#command-attributes] on the struct to fill these fields in from your `Cargo.toml` file.
|
||||
//! You can use [`#[command(version, about)]` attribute defaults][super#command-attributes] on the struct to fill these fields in from your `Cargo.toml` file.
|
||||
//!
|
||||
//! ```rust
|
||||
#![doc = include_str!("../../../examples/tutorial_derive/02_crate.rs")]
|
||||
|
@ -26,4 +26,4 @@ use crate::builder::*;
|
|||
|
||||
pub use super::chapter_0 as previous;
|
||||
pub use super::chapter_2 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
pub use crate::_derive::_tutorial as table_of_contents;
|
||||
|
|
|
@ -100,4 +100,4 @@ use crate::builder::*;
|
|||
|
||||
pub use super::chapter_1 as previous;
|
||||
pub use super::chapter_3 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
pub use crate::_derive::_tutorial as table_of_contents;
|
||||
|
|
|
@ -75,4 +75,4 @@ use crate::builder::*;
|
|||
|
||||
pub use super::chapter_2 as previous;
|
||||
pub use super::chapter_4 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
pub use crate::_derive::_tutorial as table_of_contents;
|
||||
|
|
|
@ -12,4 +12,4 @@ use crate::builder::*;
|
|||
|
||||
pub use super::chapter_3 as previous;
|
||||
pub use super::chapter_5 as next;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
pub use crate::_derive::_tutorial as table_of_contents;
|
||||
|
|
|
@ -11,4 +11,4 @@
|
|||
use crate::builder::*;
|
||||
|
||||
pub use super::chapter_4 as previous;
|
||||
pub use crate::_tutorial as table_of_contents;
|
||||
pub use crate::_derive::_tutorial as table_of_contents;
|
||||
|
|
|
@ -148,6 +148,7 @@
|
|||
//! - `author [= <expr>]`: [`Command::author`][crate::Command::author]
|
||||
//! - When not present: no author set
|
||||
//! - Without `<expr>`: defaults to [crate `authors`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-authors-field)
|
||||
//! - **NOTE:** A custom [`help_template`][crate::Command::help_template] is needed for author to show up.
|
||||
//! - `about [= <expr>]`: [`Command::about`][crate::Command::about]
|
||||
//! - When not present: [Doc comment summary](#doc-comments)
|
||||
//! - Without `<expr>`: [crate `description`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-description-field) ([`Parser`][crate::Parser] container)
|
||||
|
@ -189,6 +190,9 @@
|
|||
//! [`Subcommand`][crate::Subcommand])
|
||||
//! - When `Option<T>`, the subcommand becomes optional
|
||||
//!
|
||||
//! See [Configuring the Parser][_tutorial::chapter_1] and
|
||||
//! [Subcommands][_tutorial::chapter_2#subcommands] from the tutorial.
|
||||
//!
|
||||
//! ### ArgGroup Attributes
|
||||
//!
|
||||
//! These correspond to the [`ArgGroup`][crate::ArgGroup] which is implicitly created for each
|
||||
|
@ -203,12 +207,18 @@
|
|||
//! - `skip [= <expr>]`: Ignore this field, filling in with `<expr>`
|
||||
//! - Without `<expr>`: fills the field with `Default::default()`
|
||||
//!
|
||||
//! Note:
|
||||
//! - For `struct`s, [`multiple = true`][crate::ArgGroup::multiple] is implied
|
||||
//! - `enum` support is tracked at [#2621](https://github.com/clap-rs/clap/issues/2621)
|
||||
//!
|
||||
//! See [Argument Relations][_tutorial::chapter_3#argument-relations] from the tutorial.
|
||||
//!
|
||||
//! ### Arg Attributes
|
||||
//!
|
||||
//! These correspond to a [`Arg`][crate::Arg].
|
||||
//!
|
||||
//! **Raw attributes:** Any [`Arg` method][crate::Arg] can also be used as an attribute, see [Terminology](#terminology) for syntax.
|
||||
//! - e.g. `#[arg(max_values(3))]` would translate to `arg.max_values(3)`
|
||||
//! - e.g. `#[arg(num_args(..=3))]` would translate to `arg.num_args(..=3)`
|
||||
//!
|
||||
//! **Magic attributes**:
|
||||
//! - `id = <expr>`: [`Arg::id`][crate::Arg::id]
|
||||
|
@ -252,12 +262,17 @@
|
|||
//! - Requires field arg to be of type `Vec<T>` and `T` to implement `std::convert::Into<OsString>` or `#[arg(value_enum)]`
|
||||
//! - `<expr>` must implement `IntoIterator<T>`
|
||||
//!
|
||||
//! See [Adding Arguments][_tutorial::chapter_2] and [Validation][_tutorial::chapter_3] from the
|
||||
//! tutorial.
|
||||
//!
|
||||
//! ### ValueEnum Attributes
|
||||
//!
|
||||
//! - `rename_all = <string_literal>`: Override default field / variant name case conversion for [`PossibleValue::new`][crate::builder::PossibleValue]
|
||||
//! - When not present: `"kebab-case"`
|
||||
//! - Available values: `"camelCase"`, `"kebab-case"`, `"PascalCase"`, `"SCREAMING_SNAKE_CASE"`, `"snake_case"`, `"lower"`, `"UPPER"`, `"verbatim"`
|
||||
//!
|
||||
//! See [Enumerated values][_tutorial::chapter_3#enumerated-values] from the tutorial.
|
||||
//!
|
||||
//! ### Possible Value Attributes
|
||||
//!
|
||||
//! These correspond to a [`PossibleValue`][crate::builder::PossibleValue].
|
||||
|
@ -276,15 +291,17 @@
|
|||
//!
|
||||
//! `clap` assumes some intent based on the type used:
|
||||
//!
|
||||
//! | Type | Effect | Implies |
|
||||
//! |---------------------|--------------------------------------|-------------------------------------------------------------|
|
||||
//! | `()` | user-defined | `.action(ArgAction::Set).required(false)` |
|
||||
//! | `bool` | flag | `.action(ArgAction::SetTrue)` |
|
||||
//! | `Option<T>` | optional argument | `.action(ArgAction::Set).required(false)` |
|
||||
//! | `Option<Option<T>>` | optional value for optional argument | `.action(ArgAction::Set).required(false).num_args(0..=1)` |
|
||||
//! | `T` | required argument | `.action(ArgAction::Set).required(!has_default)` |
|
||||
//! | `Vec<T>` | `0..` occurrences of argument | `.action(ArgAction::Append).required(false)` |
|
||||
//! | `Option<Vec<T>>` | `0..` occurrences of argument | `.action(ArgAction::Append).required(false)` |
|
||||
//! | Type | Effect | Implies | Notes |
|
||||
//! |-----------------------|------------------------------------------------------|-------------------------------------------------------------|-------|
|
||||
//! | `()` | user-defined | `.action(ArgAction::Set).required(false)` | |
|
||||
//! | `bool` | flag | `.action(ArgAction::SetTrue)` | |
|
||||
//! | `Option<T>` | optional argument | `.action(ArgAction::Set).required(false)` | |
|
||||
//! | `Option<Option<T>>` | optional value for optional argument | `.action(ArgAction::Set).required(false).num_args(0..=1)` | |
|
||||
//! | `T` | required argument | `.action(ArgAction::Set).required(!has_default)` | |
|
||||
//! | `Vec<T>` | `0..` occurrences of argument | `.action(ArgAction::Append).required(false)` | |
|
||||
//! | `Option<Vec<T>>` | `0..` occurrences of argument | `.action(ArgAction::Append).required(false)` | |
|
||||
//! | `Vec<Vec<T>>` | `0..` occurrences of argument, grouped by occurrence | `.action(ArgAction::Append).required(false)` | requires `unstable-v5` |
|
||||
//! | `Option<Vec<Vec<T>>>` | `0..` occurrences of argument, grouped by occurrence | `.action(ArgAction::Append).required(false)` | requires `unstable-v5` |
|
||||
//!
|
||||
//! In addition, [`.value_parser(value_parser!(T))`][crate::value_parser!] is called for each
|
||||
//! field.
|
||||
|
@ -294,8 +311,9 @@
|
|||
//! - To force any inferred type (like `Vec<T>`) to be treated as `T`, you can refer to the type
|
||||
//! by another means, like using `std::vec::Vec` instead of `Vec`. For improving this, see
|
||||
//! [#4626](https://github.com/clap-rs/clap/issues/4626).
|
||||
//! - `Option<Vec<T>>` will be `None` instead of `vec![]` if no arguments are provided.
|
||||
//! - `Option<Vec<T>>` and `Option<Vec<Vec<T>>` will be `None` instead of `vec![]` if no arguments are provided.
|
||||
//! - This gives the user some flexibility in designing their argument, like with `num_args(0..)`
|
||||
//! - `Vec<Vec<T>>` will need [`Arg::num_args`][crate::Arg::num_args] set to be meaningful
|
||||
//!
|
||||
//! ## Doc Comments
|
||||
//!
|
||||
|
|
|
@ -31,14 +31,14 @@
|
|||
//!
|
||||
//! The benefits of integrating `structopt` and `clap` are:
|
||||
//! - Easier cross-linking in documentation
|
||||
//! - [Documentation parity](../examples)
|
||||
//! - Documentation parity
|
||||
//! - Tighter design feedback loop, ensuring all new features are designed with
|
||||
//! derives in mind and easier to change `clap` in response to `structopt` bugs.
|
||||
//! - Clearer endorsement of `structopt`
|
||||
//!
|
||||
//! See also
|
||||
//! - [`clap` v3 CHANGELOG](../CHANGELOG.md#300---2021-12-31)
|
||||
//! - [`structopt` migration guide](../CHANGELOG.md#migrate-structopt)
|
||||
//! - [`clap` v3 CHANGELOG](https://github.com/clap-rs/clap/blob/v3-master/CHANGELOG.md#300---2021-12-31)
|
||||
//! - [`structopt` migration guide](https://github.com/clap-rs/clap/blob/v3-master/CHANGELOG.md#migrate-structopt)
|
||||
//!
|
||||
//! #### What are some reasons to use `clap`? (The Pitch)
|
||||
//!
|
||||
|
|
|
@ -4,25 +4,26 @@
|
|||
//!
|
||||
//! #### Default Features
|
||||
//!
|
||||
//! * **std**: _Not Currently Used._ Placeholder for supporting `no_std` environments in a backwards compatible manner.
|
||||
//! * **color**: Turns on colored error messages.
|
||||
//! * **help**: Auto-generate help output
|
||||
//! * **usage**: Auto-generate usage
|
||||
//! * **error-context**: Include contextual information for errors (which arg failed, etc)
|
||||
//! * **suggestions**: Turns on the `Did you mean '--myoption'?` feature for when users make typos.
|
||||
//! * `std`: _Not Currently Used._ Placeholder for supporting `no_std` environments in a backwards compatible manner.
|
||||
//! * `color`: Turns on terminal styling of help and error messages. See
|
||||
//! [`Command::styles`][crate::Command::styles] to customize this.
|
||||
//! * `help`: Auto-generate help output
|
||||
//! * `usage`: Auto-generate usage
|
||||
//! * `error-context`: Include contextual information for errors (which arg failed, etc)
|
||||
//! * `suggestions`: Turns on the `Did you mean '--myoption'?` feature for when users make typos.
|
||||
//!
|
||||
//! #### Optional features
|
||||
//!
|
||||
//! * **deprecated**: Guided experience to prepare for next breaking release (at different stages of development, this may become default)
|
||||
//! * **derive**: Enables the custom derive (i.e. `#[derive(Parser)]`). Without this you must use one of the other methods of creating a `clap` CLI listed above.
|
||||
//! * **cargo**: Turns on macros that read values from [`CARGO_*` environment variables](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates).
|
||||
//! * **env**: Turns on the usage of environment variables during parsing.
|
||||
//! * **unicode**: Turns on support for unicode characters (including emoji) in arguments and help messages.
|
||||
//! * **wrap_help**: Turns on the help text wrapping feature, based on the terminal size.
|
||||
//! * **string**: Allow runtime generated strings (e.g. with [`Str`][crate::builder::Str]).
|
||||
//! * `deprecated`: Guided experience to prepare for next breaking release (at different stages of development, this may become default)
|
||||
//! * `derive`: Enables the custom derive (i.e. `#[derive(Parser)]`). Without this you must use one of the other methods of creating a `clap` CLI listed above.
|
||||
//! * `cargo`: Turns on macros that read values from [`CARGO_*` environment variables](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates).
|
||||
//! * `env`: Turns on the usage of environment variables during parsing.
|
||||
//! * `unicode`: Turns on support for unicode characters (including emoji) in arguments and help messages.
|
||||
//! * ``wrap_help``: Turns on the help text wrapping feature, based on the terminal size.
|
||||
//! * `string`: Allow runtime generated strings (e.g. with [`Str`][crate::builder::Str]).
|
||||
//!
|
||||
//! #### Experimental features
|
||||
//!
|
||||
//! **Warning:** These may contain breaking changes between minor releases.
|
||||
//!
|
||||
//! * **unstable-v5**: Preview features which will be stable on the v5.0 release
|
||||
//! * `unstable-v5`: Preview features which will be stable on the v5.0 release
|
||||
|
|
|
@ -15,12 +15,12 @@ fn main() {
|
|||
#[cfg(feature = "color")]
|
||||
{
|
||||
use clap::builder::styling;
|
||||
let styles = styling::Styles::styled()
|
||||
.header(styling::AnsiColor::Green.on_default() | styling::Effects::BOLD)
|
||||
.usage(styling::AnsiColor::Green.on_default() | styling::Effects::BOLD)
|
||||
.literal(styling::AnsiColor::Blue.on_default() | styling::Effects::BOLD)
|
||||
const STYLES: styling::Styles = styling::Styles::styled()
|
||||
.header(styling::AnsiColor::Green.on_default().bold())
|
||||
.usage(styling::AnsiColor::Green.on_default().bold())
|
||||
.literal(styling::AnsiColor::Blue.on_default().bold())
|
||||
.placeholder(styling::AnsiColor::Cyan.on_default());
|
||||
cmd = cmd.styles(styles);
|
||||
cmd = cmd.styles(STYLES);
|
||||
}
|
||||
cmd.get_matches();
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
//! - [Cookbook][_cookbook]
|
||||
//! - [FAQ][_faq]
|
||||
//! - [Discussions](https://github.com/clap-rs/clap/discussions)
|
||||
//! - [CHANGELOG](https://github.com/clap-rs/clap/blob/v4.5.16/CHANGELOG.md) (includes major version migration
|
||||
//! guides)
|
||||
//!
|
||||
//! ## Aspirations
|
||||
//!
|
||||
|
@ -24,7 +26,7 @@
|
|||
//! - Leverage feature flags to keep to one active branch
|
||||
//! - Being under [WG-CLI](https://github.com/rust-cli/team/) to increase the bus factor
|
||||
//! - We follow semver and will wait about 6-9 months between major breaking changes
|
||||
//! - We will support the last two minor Rust releases (MSRV, currently 1.70.0)
|
||||
//! - We will support the last two minor Rust releases (MSRV, currently 1.74)
|
||||
//!
|
||||
//! While these aspirations can be at odds with fast build times and low binary
|
||||
//! size, we will still strive to keep these reasonable for the flexibility you
|
||||
|
@ -62,7 +64,7 @@
|
|||
//! - [clap_complete](https://crates.io/crates/clap_complete) for shell completion support
|
||||
//!
|
||||
//! CLI Helpers
|
||||
//! - [cio](https://crates.io/crates/clio) for reading/writing to files specified as arguments
|
||||
//! - [clio](https://crates.io/crates/clio) for reading/writing to files specified as arguments
|
||||
//! - [clap-verbosity-flag](https://crates.io/crates/clap-verbosity-flag)
|
||||
//! - [clap-cargo](https://crates.io/crates/clap-cargo)
|
||||
//! - [concolor-clap](https://crates.io/crates/concolor-clap)
|
||||
|
@ -76,30 +78,17 @@
|
|||
//! - [Command-line Apps for Rust](https://rust-cli.github.io/book/index.html) book
|
||||
//!
|
||||
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
|
||||
#![warn(
|
||||
missing_docs,
|
||||
missing_debug_implementations,
|
||||
missing_copy_implementations,
|
||||
trivial_casts,
|
||||
unused_allocation,
|
||||
trivial_numeric_casts,
|
||||
clippy::single_char_pattern
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![forbid(unsafe_code)]
|
||||
// HACK https://github.com/rust-lang/rust-clippy/issues/7290
|
||||
#![allow(clippy::single_component_path_imports)]
|
||||
#![allow(clippy::branches_sharing_code)]
|
||||
// Doesn't allow for debug statements, etc to be unique
|
||||
#![allow(clippy::if_same_then_else)]
|
||||
// Breaks up parallelism that clarifies intent
|
||||
#![allow(clippy::collapsible_else_if)]
|
||||
#![warn(missing_docs)]
|
||||
#![warn(clippy::print_stderr)]
|
||||
#![warn(clippy::print_stdout)]
|
||||
|
||||
pub use clap_builder::*;
|
||||
#[cfg(feature = "derive")]
|
||||
#[doc(hidden)]
|
||||
pub use clap_derive::{self, *};
|
||||
pub use clap_derive::{self, Args, Parser, Subcommand, ValueEnum};
|
||||
|
||||
#[cfg(feature = "unstable-doc")]
|
||||
pub mod _cookbook;
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -11,9 +11,10 @@
|
|||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.70.0"
|
||||
rust-version = "1.74"
|
||||
name = "clap_builder"
|
||||
version = "4.4.5"
|
||||
version = "4.5.15"
|
||||
build = false
|
||||
include = [
|
||||
"build.rs",
|
||||
"src/**/*",
|
||||
|
@ -23,6 +24,10 @@ include = [
|
|||
"benches/**/*",
|
||||
"examples/**/*",
|
||||
]
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
|
@ -56,24 +61,26 @@ shared-version = true
|
|||
tag-name = "v{{version}}"
|
||||
|
||||
[lib]
|
||||
name = "clap_builder"
|
||||
path = "src/lib.rs"
|
||||
bench = false
|
||||
|
||||
[dependencies.anstream]
|
||||
version = "0.5.0"
|
||||
version = "0.6.7"
|
||||
optional = true
|
||||
|
||||
[dependencies.anstyle]
|
||||
version = "1.0.0"
|
||||
version = "1.0.8"
|
||||
|
||||
[dependencies.backtrace]
|
||||
version = "0.3.67"
|
||||
version = "0.3.73"
|
||||
optional = true
|
||||
|
||||
[dependencies.clap_lex]
|
||||
version = "0.5.0"
|
||||
version = "0.7.0"
|
||||
|
||||
[dependencies.strsim]
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.terminal_size]
|
||||
|
@ -89,35 +96,11 @@ version = "0.1.9"
|
|||
optional = true
|
||||
|
||||
[dev-dependencies.color-print]
|
||||
version = "0.3.4"
|
||||
|
||||
[dev-dependencies.humantime]
|
||||
version = "2.1.0"
|
||||
|
||||
[dev-dependencies.rustversion]
|
||||
version = "1.0.14"
|
||||
|
||||
[dev-dependencies.shlex]
|
||||
version = "1.1.0"
|
||||
|
||||
[dev-dependencies.snapbox]
|
||||
version = "0.4.12"
|
||||
version = "0.3.6"
|
||||
|
||||
[dev-dependencies.static_assertions]
|
||||
version = "1.1.0"
|
||||
|
||||
[dev-dependencies.trybuild]
|
||||
version = "1.0.83"
|
||||
|
||||
[dev-dependencies.trycmd]
|
||||
version = "0.14.17"
|
||||
features = [
|
||||
"color-auto",
|
||||
"diff",
|
||||
"examples",
|
||||
]
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.unic-emoji-char]
|
||||
version = "0.9.0"
|
||||
|
||||
|
@ -153,7 +136,9 @@ unstable-doc = [
|
|||
"env",
|
||||
"unicode",
|
||||
"string",
|
||||
"unstable-ext",
|
||||
]
|
||||
unstable-ext = []
|
||||
unstable-styles = ["color"]
|
||||
unstable-v5 = ["deprecated"]
|
||||
usage = []
|
||||
|
@ -161,3 +146,72 @@ wrap_help = [
|
|||
"help",
|
||||
"dep:terminal_size",
|
||||
]
|
||||
|
||||
[lints.clippy]
|
||||
assigning_clones = "allow"
|
||||
blocks_in_conditions = "allow"
|
||||
bool_assert_comparison = "allow"
|
||||
branches_sharing_code = "allow"
|
||||
checked_conversions = "warn"
|
||||
collapsible_else_if = "allow"
|
||||
create_dir = "warn"
|
||||
dbg_macro = "warn"
|
||||
debug_assert_with_mut_call = "warn"
|
||||
doc_markdown = "warn"
|
||||
empty_enum = "warn"
|
||||
enum_glob_use = "warn"
|
||||
expl_impl_clone_on_copy = "warn"
|
||||
explicit_deref_methods = "warn"
|
||||
explicit_into_iter_loop = "warn"
|
||||
fallible_impl_from = "warn"
|
||||
filter_map_next = "warn"
|
||||
flat_map_option = "warn"
|
||||
float_cmp_const = "warn"
|
||||
fn_params_excessive_bools = "warn"
|
||||
from_iter_instead_of_collect = "warn"
|
||||
if_same_then_else = "allow"
|
||||
implicit_clone = "warn"
|
||||
imprecise_flops = "warn"
|
||||
inconsistent_struct_constructor = "warn"
|
||||
inefficient_to_string = "warn"
|
||||
infinite_loop = "warn"
|
||||
invalid_upcast_comparisons = "warn"
|
||||
large_digit_groups = "warn"
|
||||
large_stack_arrays = "warn"
|
||||
large_types_passed_by_value = "warn"
|
||||
let_and_return = "allow"
|
||||
linkedlist = "warn"
|
||||
lossy_float_literal = "warn"
|
||||
macro_use_imports = "warn"
|
||||
mem_forget = "warn"
|
||||
multiple_bound_locations = "allow"
|
||||
mutex_integer = "warn"
|
||||
needless_continue = "warn"
|
||||
needless_for_each = "warn"
|
||||
negative_feature_names = "warn"
|
||||
path_buf_push_overwrite = "warn"
|
||||
ptr_as_ptr = "warn"
|
||||
rc_mutex = "warn"
|
||||
redundant_feature_names = "warn"
|
||||
ref_option_ref = "warn"
|
||||
rest_pat_in_fully_bound_structs = "warn"
|
||||
same_functions_in_if_condition = "warn"
|
||||
self_named_module_files = "warn"
|
||||
semicolon_if_nothing_returned = "warn"
|
||||
string_add_assign = "warn"
|
||||
string_lit_as_bytes = "warn"
|
||||
todo = "warn"
|
||||
trait_duplication_in_bounds = "warn"
|
||||
verbose_file_reads = "warn"
|
||||
zero_sized_map_values = "warn"
|
||||
|
||||
[lints.rust]
|
||||
unreachable_pub = "warn"
|
||||
unsafe_op_in_unsafe_fn = "warn"
|
||||
unused_lifetimes = "warn"
|
||||
unused_macro_rules = "warn"
|
||||
unused_qualifications = "warn"
|
||||
|
||||
[lints.rust.rust_2018_idioms]
|
||||
level = "warn"
|
||||
priority = -1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# clap_builder
|
||||
# `clap_builder`
|
||||
|
||||
Builder implementation for clap.
|
||||
|
||||
|
|
|
@ -194,7 +194,7 @@ pub enum ArgAction {
|
|||
/// );
|
||||
/// ```
|
||||
SetFalse,
|
||||
/// When encountered, increment a `u8` counter
|
||||
/// When encountered, increment a `u8` counter starting from `0`.
|
||||
///
|
||||
/// If no [`default_value`][super::Arg::default_value] is set, it will be `0`.
|
||||
///
|
||||
|
|
|
@ -57,6 +57,7 @@ pub(crate) enum AppSettings {
|
|||
SubcommandsNegateReqs,
|
||||
ArgsNegateSubcommands,
|
||||
SubcommandPrecedenceOverArg,
|
||||
FlattenHelp,
|
||||
ArgRequiredElseHelp,
|
||||
NextLineHelp,
|
||||
DisableColoredHelp,
|
||||
|
|
|
@ -11,6 +11,9 @@ use std::{
|
|||
|
||||
// Internal
|
||||
use super::{ArgFlags, ArgSettings};
|
||||
#[cfg(feature = "unstable-ext")]
|
||||
use crate::builder::ext::Extension;
|
||||
use crate::builder::ext::Extensions;
|
||||
use crate::builder::ArgPredicate;
|
||||
use crate::builder::IntoResettable;
|
||||
use crate::builder::OsStr;
|
||||
|
@ -85,7 +88,7 @@ pub struct Arg {
|
|||
pub(crate) terminator: Option<Str>,
|
||||
pub(crate) index: Option<usize>,
|
||||
pub(crate) help_heading: Option<Option<Str>>,
|
||||
pub(crate) value_hint: Option<ValueHint>,
|
||||
pub(crate) ext: Extensions,
|
||||
}
|
||||
|
||||
/// # Basic API
|
||||
|
@ -510,10 +513,10 @@ impl Arg {
|
|||
self
|
||||
}
|
||||
|
||||
/// This is a "VarArg" and everything that follows should be captured by it, as if the user had
|
||||
/// This is a "var arg" and everything that follows should be captured by it, as if the user had
|
||||
/// used a `--`.
|
||||
///
|
||||
/// **NOTE:** To start the trailing "VarArg" on unknown flags (and not just a positional
|
||||
/// **NOTE:** To start the trailing "var arg" on unknown flags (and not just a positional
|
||||
/// value), set [`allow_hyphen_values`][Arg::allow_hyphen_values]. Either way, users still
|
||||
/// have the option to explicitly escape ambiguous arguments with `--`.
|
||||
///
|
||||
|
@ -869,13 +872,21 @@ impl Arg {
|
|||
self.settings.unset(setting);
|
||||
self
|
||||
}
|
||||
|
||||
/// Extend [`Arg`] with [`ArgExt`] data
|
||||
#[cfg(feature = "unstable-ext")]
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
pub fn add<T: ArgExt + Extension>(mut self, tagged: T) -> Self {
|
||||
self.ext.set(tagged);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// # Value Handling
|
||||
impl Arg {
|
||||
/// Specify how to react to an argument when parsing it.
|
||||
///
|
||||
/// [ArgAction][crate::ArgAction] controls things like
|
||||
/// [`ArgAction`] controls things like
|
||||
/// - Overwriting previous values with new ones
|
||||
/// - Appending new values to all previous ones
|
||||
/// - Counting how many times a flag occurs
|
||||
|
@ -997,7 +1008,7 @@ impl Arg {
|
|||
/// - It reaches the [`Arg::value_terminator`] if set
|
||||
///
|
||||
/// Alternatively,
|
||||
/// - Use a delimiter between values with [Arg::value_delimiter]
|
||||
/// - Use a delimiter between values with [`Arg::value_delimiter`]
|
||||
/// - Require a flag occurrence per value with [`ArgAction::Append`]
|
||||
/// - Require positional arguments to appear after `--` with [`Arg::last`]
|
||||
///
|
||||
|
@ -1018,7 +1029,7 @@ impl Arg {
|
|||
/// assert_eq!(m.get_one::<String>("mode").unwrap(), "fast");
|
||||
/// ```
|
||||
///
|
||||
/// Flag/option hybrid (see also [default_missing_value][Arg::default_missing_value])
|
||||
/// Flag/option hybrid (see also [`default_missing_value`][Arg::default_missing_value])
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
|
||||
|
@ -1260,7 +1271,7 @@ impl Arg {
|
|||
|
||||
/// Provide the shell a hint about how to complete this argument.
|
||||
///
|
||||
/// See [`ValueHint`][crate::ValueHint] for more information.
|
||||
/// See [`ValueHint`] for more information.
|
||||
///
|
||||
/// **NOTE:** implicitly sets [`Arg::action(ArgAction::Set)`].
|
||||
///
|
||||
|
@ -1291,7 +1302,15 @@ impl Arg {
|
|||
/// ```
|
||||
#[must_use]
|
||||
pub fn value_hint(mut self, value_hint: impl IntoResettable<ValueHint>) -> Self {
|
||||
self.value_hint = value_hint.into_resettable().into_option();
|
||||
// HACK: we should use `Self::add` and `Self::remove` to type-check that `ArgExt` is used
|
||||
match value_hint.into_resettable().into_option() {
|
||||
Some(value_hint) => {
|
||||
self.ext.set(value_hint);
|
||||
}
|
||||
None => {
|
||||
self.ext.remove::<ValueHint>();
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -1519,11 +1538,8 @@ impl Arg {
|
|||
|
||||
/// Allow grouping of multiple values via a delimiter.
|
||||
///
|
||||
/// i.e. should `--option=val1,val2,val3` be parsed as three values (`val1`, `val2`,
|
||||
/// and `val3`) or as a single value (`val1,val2,val3`). Defaults to using `,` (comma) as the
|
||||
/// value delimiter for all arguments that accept values (options and positional arguments)
|
||||
///
|
||||
/// **NOTE:** implicitly sets [`Arg::action(ArgAction::Set)`]
|
||||
/// i.e. allow values (`val1,val2,val3`) to be parsed as three values (`val1`, `val2`,
|
||||
/// and `val3`) instead of one value (`val1,val2,val3`).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -1617,7 +1633,7 @@ impl Arg {
|
|||
/// ```
|
||||
///
|
||||
/// Will result in everything after `--` to be considered one raw argument. This behavior
|
||||
/// may not be exactly what you are expecting and using [`crate::Command::trailing_var_arg`]
|
||||
/// may not be exactly what you are expecting and using [`Arg::trailing_var_arg`]
|
||||
/// may be more appropriate.
|
||||
///
|
||||
/// **NOTE:** Implicitly sets [`Arg::action(ArgAction::Set)`] [`Arg::num_args(1..)`],
|
||||
|
@ -1741,7 +1757,7 @@ impl Arg {
|
|||
///
|
||||
/// This configuration option is often used to give the user a shortcut and allow them to
|
||||
/// efficiently specify an option argument without requiring an explicitly value. The `--color`
|
||||
/// argument is a common example. By, supplying an default, such as `default_missing_value("always")`,
|
||||
/// argument is a common example. By supplying a default, such as `default_missing_value("always")`,
|
||||
/// the user can quickly just add `--color` to the command line to produce the desired color output.
|
||||
///
|
||||
/// **NOTE:** using this configuration option requires the use of the
|
||||
|
@ -3641,8 +3657,8 @@ impl Arg {
|
|||
/// only need to be set for one of the two arguments, they do not need to be set for each.
|
||||
///
|
||||
/// **NOTE:** Defining a conflict is two-way, but does *not* need to defined for both arguments
|
||||
/// (i.e. if A conflicts with B, defining A.conflicts_with(B) is sufficient. You do not
|
||||
/// need to also do B.conflicts_with(A))
|
||||
/// (i.e. if A conflicts with B, defining `A.conflicts_with(B)` is sufficient. You do not
|
||||
/// need to also do `B.conflicts_with(A)`)
|
||||
///
|
||||
/// **NOTE:** [`Arg::conflicts_with_all(names)`] allows specifying an argument which conflicts with more than one argument.
|
||||
///
|
||||
|
@ -3701,8 +3717,8 @@ impl Arg {
|
|||
/// only need to be set for one of the two arguments, they do not need to be set for each.
|
||||
///
|
||||
/// **NOTE:** Defining a conflict is two-way, but does *not* need to defined for both arguments
|
||||
/// (i.e. if A conflicts with B, defining A.conflicts_with(B) is sufficient. You do not need
|
||||
/// need to also do B.conflicts_with(A))
|
||||
/// (i.e. if A conflicts with B, defining `A.conflicts_with(B)` is sufficient. You do not need
|
||||
/// need to also do `B.conflicts_with(A)`)
|
||||
///
|
||||
/// **NOTE:** [`Arg::exclusive(true)`] allows specifying an argument which conflicts with every other argument.
|
||||
///
|
||||
|
@ -3952,6 +3968,21 @@ impl Arg {
|
|||
Some(longs)
|
||||
}
|
||||
|
||||
/// Get hidden aliases for this argument, if any
|
||||
#[inline]
|
||||
pub fn get_aliases(&self) -> Option<Vec<&str>> {
|
||||
if self.aliases.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
self.aliases
|
||||
.iter()
|
||||
.filter_map(|(s, v)| if !*v { Some(s.as_str()) } else { None })
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the names of possible values for this argument. Only useful for user
|
||||
/// facing applications, such as building help messages or man files
|
||||
pub fn get_possible_values(&self) -> Vec<PossibleValue> {
|
||||
|
@ -3992,7 +4023,7 @@ impl Arg {
|
|||
self.val_delim
|
||||
}
|
||||
|
||||
/// Get the value terminator for this argument. The value_terminator is a value
|
||||
/// Get the value terminator for this argument. The `value_terminator` is a value
|
||||
/// that terminates parsing of multi-valued arguments.
|
||||
#[inline]
|
||||
pub fn get_value_terminator(&self) -> Option<&Str> {
|
||||
|
@ -4007,7 +4038,8 @@ impl Arg {
|
|||
|
||||
/// Get the value hint of this argument
|
||||
pub fn get_value_hint(&self) -> ValueHint {
|
||||
self.value_hint.unwrap_or_else(|| {
|
||||
// HACK: we should use `Self::add` and `Self::remove` to type-check that `ArgExt` is used
|
||||
self.ext.get::<ValueHint>().copied().unwrap_or_else(|| {
|
||||
if self.is_takes_value_set() {
|
||||
let type_id = self.get_value_parser().type_id();
|
||||
if type_id == AnyValueId::of::<std::path::PathBuf>() {
|
||||
|
@ -4078,7 +4110,9 @@ impl Arg {
|
|||
}
|
||||
|
||||
pub(crate) fn is_takes_value_set(&self) -> bool {
|
||||
self.get_action().takes_values()
|
||||
self.get_num_args()
|
||||
.unwrap_or_else(|| 1.into())
|
||||
.takes_values()
|
||||
}
|
||||
|
||||
/// Report whether [`Arg::allow_hyphen_values`] is set
|
||||
|
@ -4092,8 +4126,8 @@ impl Arg {
|
|||
}
|
||||
|
||||
/// Behavior when parsing the argument
|
||||
pub fn get_action(&self) -> &super::ArgAction {
|
||||
const DEFAULT: super::ArgAction = super::ArgAction::Set;
|
||||
pub fn get_action(&self) -> &ArgAction {
|
||||
const DEFAULT: ArgAction = ArgAction::Set;
|
||||
self.action.as_ref().unwrap_or(&DEFAULT)
|
||||
}
|
||||
|
||||
|
@ -4193,6 +4227,18 @@ impl Arg {
|
|||
pub fn is_ignore_case_set(&self) -> bool {
|
||||
self.is_set(ArgSettings::IgnoreCase)
|
||||
}
|
||||
|
||||
/// Access an [`ArgExt`]
|
||||
#[cfg(feature = "unstable-ext")]
|
||||
pub fn get<T: ArgExt + Extension>(&self) -> Option<&T> {
|
||||
self.ext.get::<T>()
|
||||
}
|
||||
|
||||
/// Remove an [`ArgExt`]
|
||||
#[cfg(feature = "unstable-ext")]
|
||||
pub fn remove<T: ArgExt + Extension>(mut self) -> Option<T> {
|
||||
self.ext.remove::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
/// # Internally used only
|
||||
|
@ -4200,7 +4246,7 @@ impl Arg {
|
|||
pub(crate) fn _build(&mut self) {
|
||||
if self.action.is_none() {
|
||||
if self.num_vals == Some(ValueRange::EMPTY) {
|
||||
let action = super::ArgAction::SetTrue;
|
||||
let action = ArgAction::SetTrue;
|
||||
self.action = Some(action);
|
||||
} else {
|
||||
let action =
|
||||
|
@ -4209,9 +4255,9 @@ impl Arg {
|
|||
//
|
||||
// Bounded values are probably a group and the user should explicitly opt-in to
|
||||
// Append
|
||||
super::ArgAction::Append
|
||||
ArgAction::Append
|
||||
} else {
|
||||
super::ArgAction::Set
|
||||
ArgAction::Set
|
||||
};
|
||||
self.action = Some(action);
|
||||
}
|
||||
|
@ -4430,14 +4476,14 @@ impl Ord for Arg {
|
|||
impl Eq for Arg {}
|
||||
|
||||
impl Display for Arg {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
let plain = Styles::plain();
|
||||
self.stylized(&plain, None).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Arg {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
let mut ds = f.debug_struct("Arg");
|
||||
|
||||
#[allow(unused_mut)]
|
||||
|
@ -4467,8 +4513,8 @@ impl fmt::Debug for Arg {
|
|||
.field("terminator", &self.terminator)
|
||||
.field("index", &self.index)
|
||||
.field("help_heading", &self.help_heading)
|
||||
.field("value_hint", &self.value_hint)
|
||||
.field("default_missing_vals", &self.default_missing_vals);
|
||||
.field("default_missing_vals", &self.default_missing_vals)
|
||||
.field("ext", &self.ext);
|
||||
|
||||
#[cfg(feature = "env")]
|
||||
{
|
||||
|
@ -4479,6 +4525,10 @@ impl fmt::Debug for Arg {
|
|||
}
|
||||
}
|
||||
|
||||
/// User-provided data that can be attached to an [`Arg`]
|
||||
#[cfg(feature = "unstable-ext")]
|
||||
pub trait ArgExt: Extension {}
|
||||
|
||||
// Flags
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
@ -4517,7 +4567,7 @@ mod test {
|
|||
.action(ArgAction::SetTrue);
|
||||
f._build();
|
||||
|
||||
assert_eq!(f.to_string(), "--flag")
|
||||
assert_eq!(f.to_string(), "--flag");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -4540,7 +4590,7 @@ mod test {
|
|||
f.short_aliases = vec![('b', true)];
|
||||
f._build();
|
||||
|
||||
assert_eq!(f.to_string(), "-a")
|
||||
assert_eq!(f.to_string(), "-a");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -236,7 +236,7 @@ impl ArgGroup {
|
|||
/// // maybe we don't know which of the two flags was used...
|
||||
/// assert!(m.contains_id("req_flags"));
|
||||
/// ```
|
||||
/// In this next example, we show the default behavior (i.e. `multiple(false)) which will throw
|
||||
/// In this next example, we show the default behavior (i.e. `multiple(false)`) which will throw
|
||||
/// an error if more than one of the args in the group was used.
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -585,7 +585,7 @@ mod test {
|
|||
#[test]
|
||||
fn arg_group_send_sync() {
|
||||
fn foo<T: Send + Sync>(_: T) {}
|
||||
foo(ArgGroup::new("test"))
|
||||
foo(ArgGroup::new("test"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -298,6 +298,45 @@ impl Command {
|
|||
self
|
||||
}
|
||||
|
||||
/// Allows one to mutate an [`ArgGroup`] after it's been added to a [`Command`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the argument is undefined
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, arg, ArgGroup};
|
||||
///
|
||||
/// Command::new("foo")
|
||||
/// .arg(arg!(--"set-ver" <ver> "set the version manually").required(false))
|
||||
/// .arg(arg!(--major "auto increase major"))
|
||||
/// .arg(arg!(--minor "auto increase minor"))
|
||||
/// .arg(arg!(--patch "auto increase patch"))
|
||||
/// .group(ArgGroup::new("vers")
|
||||
/// .args(["set-ver", "major", "minor","patch"])
|
||||
/// .required(true))
|
||||
/// .mut_group("vers", |a| a.required(false));
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
pub fn mut_group<F>(mut self, arg_id: impl AsRef<str>, f: F) -> Self
|
||||
where
|
||||
F: FnOnce(ArgGroup) -> ArgGroup,
|
||||
{
|
||||
let id = arg_id.as_ref();
|
||||
let index = self
|
||||
.groups
|
||||
.iter()
|
||||
.position(|g| g.get_id() == id)
|
||||
.unwrap_or_else(|| panic!("Group `{id}` is undefined"));
|
||||
let a = self.groups.remove(index);
|
||||
|
||||
self.groups.push(f(a));
|
||||
self
|
||||
}
|
||||
/// Allows one to mutate a [`Command`] after it's been added as a subcommand.
|
||||
///
|
||||
/// This can be useful for modifying auto-generated arguments of nested subcommands with
|
||||
|
@ -408,7 +447,7 @@ impl Command {
|
|||
/// ```
|
||||
#[must_use]
|
||||
pub fn groups(mut self, groups: impl IntoIterator<Item = impl Into<ArgGroup>>) -> Self {
|
||||
for g in groups.into_iter() {
|
||||
for g in groups {
|
||||
self = self.group(g.into());
|
||||
}
|
||||
self
|
||||
|
@ -506,7 +545,7 @@ impl Command {
|
|||
/// that exhaustively test your CLI to ensure the asserts are evaluated, this will run those
|
||||
/// asserts in a way convenient for running as a test.
|
||||
///
|
||||
/// **Note::** This will not help with asserts in [`ArgMatches`], those will need exhaustive
|
||||
/// **Note:** This will not help with asserts in [`ArgMatches`], those will need exhaustive
|
||||
/// testing of your CLI.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -545,11 +584,11 @@ impl Command {
|
|||
/// let mut cmd = Command::new("myprog");
|
||||
/// let err = cmd.error(ErrorKind::InvalidValue, "Some failure case");
|
||||
/// ```
|
||||
pub fn error(&mut self, kind: ErrorKind, message: impl std::fmt::Display) -> Error {
|
||||
pub fn error(&mut self, kind: ErrorKind, message: impl fmt::Display) -> Error {
|
||||
Error::raw(kind, message).format(self)
|
||||
}
|
||||
|
||||
/// Parse [`env::args_os`], exiting on failure.
|
||||
/// Parse [`env::args_os`], [exiting][Error::exit] on failure.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -571,7 +610,7 @@ impl Command {
|
|||
self.get_matches_from(env::args_os())
|
||||
}
|
||||
|
||||
/// Parse [`env::args_os`], exiting on failure.
|
||||
/// Parse [`env::args_os`], [exiting][Error::exit] on failure.
|
||||
///
|
||||
/// Like [`Command::get_matches`] but doesn't consume the `Command`.
|
||||
///
|
||||
|
@ -592,7 +631,7 @@ impl Command {
|
|||
/// [`env::args_os`]: std::env::args_os()
|
||||
/// [`Command::get_matches`]: Command::get_matches()
|
||||
pub fn get_matches_mut(&mut self) -> ArgMatches {
|
||||
self.try_get_matches_from_mut(&mut env::args_os())
|
||||
self.try_get_matches_from_mut(env::args_os())
|
||||
.unwrap_or_else(|e| e.exit())
|
||||
}
|
||||
|
||||
|
@ -631,7 +670,7 @@ impl Command {
|
|||
self.try_get_matches_from(env::args_os())
|
||||
}
|
||||
|
||||
/// Parse the specified arguments, exiting on failure.
|
||||
/// Parse the specified arguments, [exiting][Error::exit] on failure.
|
||||
///
|
||||
/// **NOTE:** The first argument will be parsed as the binary name unless
|
||||
/// [`Command::no_binary_name`] is used.
|
||||
|
@ -746,7 +785,7 @@ impl Command {
|
|||
I: IntoIterator<Item = T>,
|
||||
T: Into<OsString> + Clone,
|
||||
{
|
||||
let mut raw_args = clap_lex::RawArgs::new(itr.into_iter());
|
||||
let mut raw_args = clap_lex::RawArgs::new(itr);
|
||||
let mut cursor = raw_args.cursor();
|
||||
|
||||
if self.settings.is_set(AppSettings::Multicall) {
|
||||
|
@ -1070,7 +1109,7 @@ impl Command {
|
|||
/// Replace prior occurrences of arguments rather than error
|
||||
///
|
||||
/// For any argument that would conflict with itself by default (e.g.
|
||||
/// [`ArgAction::Set`][ArgAction::Set], it will now override itself.
|
||||
/// [`ArgAction::Set`], it will now override itself.
|
||||
///
|
||||
/// This is the equivalent to saying the `foo` arg using [`Arg::overrides_with("foo")`] for all
|
||||
/// defined arguments.
|
||||
|
@ -1087,7 +1126,7 @@ impl Command {
|
|||
}
|
||||
}
|
||||
|
||||
/// Disables the automatic delimiting of values after `--` or when [`Command::trailing_var_arg`]
|
||||
/// Disables the automatic delimiting of values after `--` or when [`Arg::trailing_var_arg`]
|
||||
/// was used.
|
||||
///
|
||||
/// **NOTE:** The same thing can be done manually by setting the final positional argument to
|
||||
|
@ -1118,6 +1157,8 @@ impl Command {
|
|||
|
||||
/// Sets when to color output.
|
||||
///
|
||||
/// To customize how the output is styled, see [`Command::styles`].
|
||||
///
|
||||
/// **NOTE:** This choice is propagated to all child subcommands.
|
||||
///
|
||||
/// **NOTE:** Default behaviour is [`ColorChoice::Auto`].
|
||||
|
@ -1158,13 +1199,13 @@ impl Command {
|
|||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ColorChoice, builder::styling};
|
||||
/// let styles = styling::Styles::styled()
|
||||
/// .header(styling::AnsiColor::Green.on_default() | styling::Effects::BOLD)
|
||||
/// .usage(styling::AnsiColor::Green.on_default() | styling::Effects::BOLD)
|
||||
/// .literal(styling::AnsiColor::Blue.on_default() | styling::Effects::BOLD)
|
||||
/// const STYLES: styling::Styles = styling::Styles::styled()
|
||||
/// .header(styling::AnsiColor::Green.on_default().bold())
|
||||
/// .usage(styling::AnsiColor::Green.on_default().bold())
|
||||
/// .literal(styling::AnsiColor::Blue.on_default().bold())
|
||||
/// .placeholder(styling::AnsiColor::Cyan.on_default());
|
||||
/// Command::new("myprog")
|
||||
/// .styles(styles)
|
||||
/// .styles(STYLES)
|
||||
/// .get_matches();
|
||||
/// ```
|
||||
#[cfg(feature = "color")]
|
||||
|
@ -1244,12 +1285,41 @@ impl Command {
|
|||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, error::ErrorKind};
|
||||
/// let res = Command::new("myprog")
|
||||
/// .version("1.0.0")
|
||||
/// .disable_version_flag(true)
|
||||
/// .try_get_matches_from(vec![
|
||||
/// "myprog", "--version"
|
||||
/// ]);
|
||||
/// assert!(res.is_err());
|
||||
/// assert_eq!(res.unwrap_err().kind(), ErrorKind::UnknownArgument);
|
||||
/// ```
|
||||
///
|
||||
/// You can create a custom version flag with [`ArgAction::Version`]
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgAction, error::ErrorKind};
|
||||
/// let mut cmd = Command::new("myprog")
|
||||
/// .version("1.0.0")
|
||||
/// // Remove the `-V` short flag
|
||||
/// .disable_version_flag(true)
|
||||
/// .arg(
|
||||
/// Arg::new("version")
|
||||
/// .long("version")
|
||||
/// .action(ArgAction::Version)
|
||||
/// .help("Print version")
|
||||
/// );
|
||||
///
|
||||
/// let res = cmd.try_get_matches_from_mut(vec![
|
||||
/// "myprog", "-V"
|
||||
/// ]);
|
||||
/// assert!(res.is_err());
|
||||
/// assert_eq!(res.unwrap_err().kind(), ErrorKind::UnknownArgument);
|
||||
///
|
||||
/// let res = cmd.try_get_matches_from_mut(vec![
|
||||
/// "myprog", "--version"
|
||||
/// ]);
|
||||
/// assert!(res.is_err());
|
||||
/// assert_eq!(res.unwrap_err().kind(), ErrorKind::DisplayVersion);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn disable_version_flag(self, yes: bool) -> Self {
|
||||
|
@ -1329,6 +1399,35 @@ impl Command {
|
|||
/// assert!(res.is_err());
|
||||
/// assert_eq!(res.unwrap_err().kind(), ErrorKind::UnknownArgument);
|
||||
/// ```
|
||||
///
|
||||
/// You can create a custom help flag with [`ArgAction::Help`], [`ArgAction::HelpShort`], or
|
||||
/// [`ArgAction::HelpLong`]
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgAction, error::ErrorKind};
|
||||
/// let mut cmd = Command::new("myprog")
|
||||
/// // Change help short flag to `?`
|
||||
/// .disable_help_flag(true)
|
||||
/// .arg(
|
||||
/// Arg::new("help")
|
||||
/// .short('?')
|
||||
/// .long("help")
|
||||
/// .action(ArgAction::Help)
|
||||
/// .help("Print help")
|
||||
/// );
|
||||
///
|
||||
/// let res = cmd.try_get_matches_from_mut(vec![
|
||||
/// "myprog", "-h"
|
||||
/// ]);
|
||||
/// assert!(res.is_err());
|
||||
/// assert_eq!(res.unwrap_err().kind(), ErrorKind::UnknownArgument);
|
||||
///
|
||||
/// let res = cmd.try_get_matches_from_mut(vec![
|
||||
/// "myprog", "-?"
|
||||
/// ]);
|
||||
/// assert!(res.is_err());
|
||||
/// assert_eq!(res.unwrap_err().kind(), ErrorKind::DisplayHelp);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn disable_help_flag(self, yes: bool) -> Self {
|
||||
if yes {
|
||||
|
@ -1643,7 +1742,8 @@ impl Command {
|
|||
|
||||
/// Sets the program's description for the long help (`--help`).
|
||||
///
|
||||
/// If [`Command::about`] is not specified, this message will be displayed for `-h`.
|
||||
/// If not set, [`Command::about`] will be used for long help in addition to short help
|
||||
/// (`-h`).
|
||||
///
|
||||
/// **NOTE:** Only [`Command::about`] (short format) is used in completion
|
||||
/// script generation in order to be concise.
|
||||
|
@ -1695,7 +1795,8 @@ impl Command {
|
|||
/// This is often used to describe how to use the arguments, caveats to be noted, or license
|
||||
/// and contact information.
|
||||
///
|
||||
/// If [`Command::after_help`] is not specified, this message will be displayed for `-h`.
|
||||
/// If not set, [`Command::after_help`] will be used for long help in addition to short help
|
||||
/// (`-h`).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -1738,7 +1839,8 @@ impl Command {
|
|||
///
|
||||
/// This is often used for header, copyright, or license information.
|
||||
///
|
||||
/// If [`Command::before_help`] is not specified, this message will be displayed for `-h`.
|
||||
/// If not set, [`Command::before_help`] will be used for long help in addition to short help
|
||||
/// (`-h`).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -1991,6 +2093,21 @@ impl Command {
|
|||
self
|
||||
}
|
||||
|
||||
/// Flatten subcommand help into the current command's help
|
||||
///
|
||||
/// This shows a summary of subcommands within the usage and help for the current command, similar to
|
||||
/// `git stash --help` showing information on `push`, `pop`, etc.
|
||||
/// To see more information, a user can still pass `--help` to the individual subcommands.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn flatten_help(self, yes: bool) -> Self {
|
||||
if yes {
|
||||
self.setting(AppSettings::FlattenHelp)
|
||||
} else {
|
||||
self.unset_setting(AppSettings::FlattenHelp)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the default section heading for future args.
|
||||
///
|
||||
/// This will be used for any arg that hasn't had [`Arg::help_heading`] called.
|
||||
|
@ -2105,7 +2222,7 @@ impl Command {
|
|||
/// For example, imagine a CLI which has three positional arguments `[foo] [bar] [baz]...` where
|
||||
/// `baz` accepts multiple values (similar to man `ARGS...` style training arguments).
|
||||
///
|
||||
/// With this setting the following invocations are posisble:
|
||||
/// With this setting the following invocations are possible:
|
||||
///
|
||||
/// * `$ prog foo bar baz1 baz2 baz3`
|
||||
/// * `$ prog foo -- baz1 baz2 baz3`
|
||||
|
@ -2455,7 +2572,7 @@ impl Command {
|
|||
#[must_use]
|
||||
pub fn long_flag_aliases(mut self, names: impl IntoIterator<Item = impl Into<Str>>) -> Self {
|
||||
for s in names {
|
||||
self = self.long_flag_alias(s)
|
||||
self = self.long_flag_alias(s);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -3277,6 +3394,20 @@ impl Command {
|
|||
self.usage_name.as_deref()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(feature = "usage")]
|
||||
pub(crate) fn get_usage_name_fallback(&self) -> &str {
|
||||
self.get_usage_name()
|
||||
.unwrap_or_else(|| self.get_bin_name_fallback())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(not(feature = "usage"))]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get_usage_name_fallback(&self) -> &str {
|
||||
self.get_bin_name_fallback()
|
||||
}
|
||||
|
||||
/// Get the name of the binary.
|
||||
#[inline]
|
||||
pub fn get_display_name(&self) -> Option<&str> {
|
||||
|
@ -3289,6 +3420,12 @@ impl Command {
|
|||
self.bin_name.as_deref()
|
||||
}
|
||||
|
||||
/// Get the name of the binary.
|
||||
#[inline]
|
||||
pub(crate) fn get_bin_name_fallback(&self) -> &str {
|
||||
self.bin_name.as_deref().unwrap_or_else(|| self.get_name())
|
||||
}
|
||||
|
||||
/// Set binary name. Uses `&mut self` instead of `self`.
|
||||
pub fn set_bin_name(&mut self, name: impl Into<String>) {
|
||||
self.bin_name = Some(name.into());
|
||||
|
@ -3306,6 +3443,13 @@ impl Command {
|
|||
&self.name
|
||||
}
|
||||
|
||||
/// Get all known names of the cmd (i.e. primary name and visible aliases).
|
||||
pub fn get_name_and_visible_aliases(&self) -> Vec<&str> {
|
||||
let mut names = vec![self.name.as_str()];
|
||||
names.extend(self.get_visible_aliases());
|
||||
names
|
||||
}
|
||||
|
||||
/// Get the version of the cmd.
|
||||
#[inline]
|
||||
pub fn get_version(&self) -> Option<&str> {
|
||||
|
@ -3352,6 +3496,12 @@ impl Command {
|
|||
self.long_about.as_ref()
|
||||
}
|
||||
|
||||
/// Get the custom section heading specified via [`Command::flatten_help`].
|
||||
#[inline]
|
||||
pub fn is_flatten_help_set(&self) -> bool {
|
||||
self.is_set(AppSettings::FlattenHelp)
|
||||
}
|
||||
|
||||
/// Get the custom section heading specified via [`Command::next_help_heading`].
|
||||
///
|
||||
/// [`Command::help_heading`]: Command::help_heading()
|
||||
|
@ -3405,6 +3555,15 @@ impl Command {
|
|||
self.long_flag_aliases.iter().map(|a| a.0.as_str())
|
||||
}
|
||||
|
||||
/// Iterate through the *hidden* aliases for this subcommand.
|
||||
#[inline]
|
||||
pub fn get_aliases(&self) -> impl Iterator<Item = &str> + '_ {
|
||||
self.aliases
|
||||
.iter()
|
||||
.filter(|(_, vis)| !*vis)
|
||||
.map(|a| a.0.as_str())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn is_set(&self, s: AppSettings) -> bool {
|
||||
self.settings.is_set(s) || self.g_settings.is_set(s)
|
||||
|
@ -3612,7 +3771,7 @@ impl Command {
|
|||
// Subcommand_1.1.1 (contains Arg)
|
||||
//
|
||||
fn get_subcommands_containing(&self, arg: &Arg) -> Vec<&Self> {
|
||||
let mut vec = std::vec::Vec::new();
|
||||
let mut vec = Vec::new();
|
||||
for idx in 0..self.subcommands.len() {
|
||||
if self.subcommands[idx]
|
||||
.args
|
||||
|
@ -4454,7 +4613,7 @@ impl Command {
|
|||
|
||||
#[inline]
|
||||
pub(crate) fn set(&mut self, s: AppSettings) {
|
||||
self.settings.set(s)
|
||||
self.settings.set(s);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -4518,7 +4677,7 @@ impl Command {
|
|||
|
||||
/// Iterate through all the names of all subcommands (not recursively), including aliases.
|
||||
/// Used for suggestions.
|
||||
pub(crate) fn all_subcommand_names(&self) -> impl Iterator<Item = &str> + Captures {
|
||||
pub(crate) fn all_subcommand_names(&self) -> impl Iterator<Item = &str> + Captures<'_> {
|
||||
self.get_subcommands().flat_map(|sc| {
|
||||
let name = sc.get_name();
|
||||
let aliases = sc.get_all_aliases();
|
||||
|
@ -4561,7 +4720,7 @@ impl Command {
|
|||
if !args.contains(n) {
|
||||
if self.find(n).is_some() {
|
||||
debug!("Command::unroll_args_in_group:iter: this is an arg");
|
||||
args.push(n.clone())
|
||||
args.push(n.clone());
|
||||
} else {
|
||||
debug!("Command::unroll_args_in_group:iter: this is a group");
|
||||
g_vec.push(n);
|
||||
|
@ -4592,7 +4751,7 @@ impl Command {
|
|||
for r in arg.requires.iter().filter_map(&func) {
|
||||
if let Some(req) = self.find(&r) {
|
||||
if !req.requires.is_empty() {
|
||||
r_vec.push(req.get_id())
|
||||
r_vec.push(req.get_id());
|
||||
}
|
||||
}
|
||||
args.push(r);
|
||||
|
@ -4742,18 +4901,21 @@ impl From<&'_ Command> for Command {
|
|||
}
|
||||
|
||||
impl fmt::Display for Command {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // atm dependent on features enabled
|
||||
pub(crate) trait AppTag: crate::builder::ext::Extension {}
|
||||
|
||||
#[allow(dead_code)] // atm dependent on features enabled
|
||||
#[derive(Default, Copy, Clone, Debug)]
|
||||
struct TermWidth(usize);
|
||||
|
||||
impl AppTag for TermWidth {}
|
||||
|
||||
#[allow(dead_code)] // atm dependent on features enabled
|
||||
#[derive(Default, Copy, Clone, Debug)]
|
||||
struct MaxTermWidth(usize);
|
||||
|
||||
|
|
|
@ -370,7 +370,7 @@ pub(crate) fn assert_app(cmd: &Command) {
|
|||
"Command {}: {}",
|
||||
cmd.get_name(),
|
||||
"`{bin}` template variable was removed in clap5, use `{name}` instead"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
cmd._panic_on_missing_help(cmd.is_help_expected_set());
|
||||
|
@ -398,50 +398,46 @@ enum Flag<'a> {
|
|||
}
|
||||
|
||||
impl PartialEq for Flag<'_> {
|
||||
fn eq(&self, other: &Flag) -> bool {
|
||||
fn eq(&self, other: &Flag<'_>) -> bool {
|
||||
self.cmp(other) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Flag<'_> {
|
||||
fn partial_cmp(&self, other: &Flag) -> Option<Ordering> {
|
||||
use Flag::*;
|
||||
fn partial_cmp(&self, other: &Flag<'_>) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Flag<'_> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self, other) {
|
||||
(Command(s1, _), Command(s2, _))
|
||||
| (Arg(s1, _), Arg(s2, _))
|
||||
| (Command(s1, _), Arg(s2, _))
|
||||
| (Arg(s1, _), Command(s2, _)) => {
|
||||
(Flag::Command(s1, _), Flag::Command(s2, _))
|
||||
| (Flag::Arg(s1, _), Flag::Arg(s2, _))
|
||||
| (Flag::Command(s1, _), Flag::Arg(s2, _))
|
||||
| (Flag::Arg(s1, _), Flag::Command(s2, _)) => {
|
||||
if s1 == s2 {
|
||||
Some(Ordering::Equal)
|
||||
Ordering::Equal
|
||||
} else {
|
||||
s1.partial_cmp(s2)
|
||||
s1.cmp(s2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Flag<'_> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_duplicate_flags(flags: &[Flag], short_or_long: &str) {
|
||||
use Flag::*;
|
||||
|
||||
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!(
|
||||
(Flag::Command(flag, one), Flag::Command(_, another)) if one != another => panic!(
|
||||
"the '{flag}' {short_or_long} flag is specified for both '{one}' and '{another}' subcommands"
|
||||
),
|
||||
|
||||
(Arg(flag, one), Arg(_, another)) if one != another => panic!(
|
||||
(Flag::Arg(flag, one), Flag::Arg(_, another)) if one != another => panic!(
|
||||
"{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!(
|
||||
(Flag::Arg(flag, arg), Flag::Command(_, sub)) | (Flag::Command(flag, sub), Flag::Arg(_, arg)) => panic!(
|
||||
"the '{flag}' {short_or_long} flag for the '{arg}' argument conflicts with the short flag \
|
||||
for '{sub}' subcommand"
|
||||
),
|
||||
|
@ -467,22 +463,6 @@ fn find_duplicates<T: PartialEq>(slice: &[T]) -> impl Iterator<Item = (&T, &T)>
|
|||
|
||||
fn assert_app_flags(cmd: &Command) {
|
||||
macro_rules! checker {
|
||||
($a:ident requires $($b:ident)|+) => {
|
||||
if cmd.$a() {
|
||||
let mut s = String::new();
|
||||
|
||||
$(
|
||||
if !cmd.$b() {
|
||||
use std::fmt::Write;
|
||||
write!(&mut s, " AppSettings::{} is required when AppSettings::{} is set.\n", std::stringify!($b), std::stringify!($a)).unwrap();
|
||||
}
|
||||
)+
|
||||
|
||||
if !s.is_empty() {
|
||||
panic!("{s}")
|
||||
}
|
||||
}
|
||||
};
|
||||
($a:ident conflicts $($b:ident)|+) => {
|
||||
if cmd.$a() {
|
||||
let mut s = String::new();
|
||||
|
@ -704,13 +684,14 @@ fn assert_arg(arg: &Arg) {
|
|||
arg.get_id(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
arg.get_action().takes_values(),
|
||||
arg.is_takes_value_set(),
|
||||
"Argument `{}`'s selected action {:?} contradicts `takes_value`",
|
||||
arg.get_id(),
|
||||
arg.get_action()
|
||||
);
|
||||
if arg.is_takes_value_set() {
|
||||
assert!(
|
||||
arg.get_action().takes_values(),
|
||||
"Argument `{}`'s selected action {:?} contradicts `takes_value`",
|
||||
arg.get_id(),
|
||||
arg.get_action()
|
||||
);
|
||||
}
|
||||
if let Some(action_type_id) = arg.get_action().value_type_id() {
|
||||
assert_eq!(
|
||||
action_type_id,
|
||||
|
@ -734,7 +715,7 @@ fn assert_arg(arg: &Arg) {
|
|||
arg.is_multiple_values_set(),
|
||||
"Argument '{}' uses hint CommandWithArguments and must accept multiple values",
|
||||
arg.get_id()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -774,13 +755,6 @@ fn assert_arg(arg: &Arg) {
|
|||
}
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
num_vals.takes_values(),
|
||||
arg.is_takes_value_set(),
|
||||
"Argument {}: mismatch between `num_args` ({}) and `takes_value`",
|
||||
arg.get_id(),
|
||||
num_vals,
|
||||
);
|
||||
assert_eq!(
|
||||
num_vals.is_multiple(),
|
||||
arg.is_multiple_values_set(),
|
||||
|
|
|
@ -1,43 +1,36 @@
|
|||
use crate::util::AnyValue;
|
||||
use crate::util::AnyValueId;
|
||||
use crate::util::FlatMap;
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub(crate) struct Extensions {
|
||||
extensions: FlatMap<AnyValueId, BoxedExtension>,
|
||||
extensions: FlatMap<AnyValueId, AnyValue>,
|
||||
}
|
||||
|
||||
impl Extensions {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get<T: Extension>(&self) -> Option<&T> {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions.get(&id).map(|e| e.as_ref::<T>())
|
||||
self.extensions.get(&id).map(|e| {
|
||||
e.downcast_ref::<T>()
|
||||
.expect("`Extensions` tracks values by type")
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get_mut<T: Extension>(&mut self) -> Option<&mut T> {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions.get_mut(&id).map(|e| e.as_mut::<T>())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get_or_insert_default<T: Extension + Default>(&mut self) -> &mut T {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions
|
||||
.entry(id)
|
||||
.or_insert_with(|| BoxedExtension::new(T::default()))
|
||||
.as_mut::<T>()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn set<T: Extension + Into<BoxedEntry>>(&mut self, tagged: T) -> bool {
|
||||
let BoxedEntry { id, value } = tagged.into();
|
||||
pub(crate) fn set<T: Extension>(&mut self, tagged: T) -> bool {
|
||||
let value = AnyValue::new(tagged);
|
||||
let id = value.type_id();
|
||||
self.extensions.insert(id, value).is_some()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn remove<T: Extension>(&mut self) -> Option<Box<dyn Extension>> {
|
||||
pub(crate) fn remove<T: Extension>(&mut self) -> Option<T> {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions.remove(&id).map(BoxedExtension::into_inner)
|
||||
self.extensions.remove(&id).map(|e| {
|
||||
e.downcast_into::<T>()
|
||||
.expect("`Extensions` tracks values by type")
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn update(&mut self, other: &Self) {
|
||||
|
@ -47,170 +40,7 @@ impl Extensions {
|
|||
}
|
||||
}
|
||||
|
||||
/// Supports conversion to `Any`. Traits to be extended by `impl_downcast!` must extend `Extension`.
|
||||
pub(crate) trait Extension: std::fmt::Debug + Send + Sync + 'static {
|
||||
/// Convert `Box<dyn Trait>` (where `Trait: Extension`) to `Box<dyn Any>`.
|
||||
///
|
||||
/// `Box<dyn Any>` can /// then be further `downcast` into
|
||||
/// `Box<ConcreteType>` where `ConcreteType` implements `Trait`.
|
||||
fn into_any(self: Box<Self>) -> Box<dyn std::any::Any>;
|
||||
/// Clone `&Box<dyn Trait>` (where `Trait: Extension`) to `Box<dyn Extension>`.
|
||||
///
|
||||
/// `Box<dyn Any>` can /// then be further `downcast` into
|
||||
// `Box<ConcreteType>` where `ConcreteType` implements `Trait`.
|
||||
fn clone_extension(&self) -> Box<dyn Extension>;
|
||||
/// Convert `&Trait` (where `Trait: Extension`) to `&Any`.
|
||||
///
|
||||
/// This is needed since Rust cannot /// generate `&Any`'s vtable from
|
||||
/// `&Trait`'s.
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
/// Convert `&mut Trait` (where `Trait: Extension`) to `&Any`.
|
||||
///
|
||||
/// This is needed since Rust cannot /// generate `&mut Any`'s vtable from
|
||||
/// `&mut Trait`'s.
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
|
||||
}
|
||||
#[allow(unreachable_pub)]
|
||||
pub trait Extension: std::fmt::Debug + Clone + std::any::Any + Send + Sync + 'static {}
|
||||
|
||||
impl<T> Extension for T
|
||||
where
|
||||
T: Clone + std::fmt::Debug + Send + Sync + 'static,
|
||||
{
|
||||
fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
|
||||
self
|
||||
}
|
||||
fn clone_extension(&self) -> Box<dyn Extension> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Box<dyn Extension> {
|
||||
fn clone(&self) -> Self {
|
||||
self.as_ref().clone_extension()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(transparent)]
|
||||
struct BoxedExtension(Box<dyn Extension>);
|
||||
|
||||
impl BoxedExtension {
|
||||
fn new<T: Extension>(inner: T) -> Self {
|
||||
Self(Box::new(inner))
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Box<dyn Extension> {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn as_ref<T: Extension>(&self) -> &T {
|
||||
self.0.as_ref().as_any().downcast_ref::<T>().unwrap()
|
||||
}
|
||||
|
||||
fn as_mut<T: Extension>(&mut self) -> &mut T {
|
||||
self.0.as_mut().as_any_mut().downcast_mut::<T>().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for BoxedExtension {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct BoxedEntry {
|
||||
id: AnyValueId,
|
||||
value: BoxedExtension,
|
||||
}
|
||||
|
||||
impl BoxedEntry {
|
||||
pub(crate) fn new(r: impl Extension) -> Self {
|
||||
let id = AnyValueId::from(&r);
|
||||
let value = BoxedExtension::new(r);
|
||||
BoxedEntry { id, value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Extension> From<R> for BoxedEntry {
|
||||
fn from(inner: R) -> Self {
|
||||
BoxedEntry::new(inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
struct Number(usize);
|
||||
|
||||
#[test]
|
||||
fn get() {
|
||||
let mut ext = Extensions::default();
|
||||
ext.set(Number(10));
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(10)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_mut() {
|
||||
let mut ext = Extensions::default();
|
||||
ext.set(Number(10));
|
||||
*ext.get_mut::<Number>().unwrap() = Number(20);
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(20)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_or_insert_default_empty() {
|
||||
let mut ext = Extensions::default();
|
||||
assert_eq!(ext.get_or_insert_default::<Number>(), &Number(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_or_insert_default_full() {
|
||||
let mut ext = Extensions::default();
|
||||
ext.set(Number(10));
|
||||
assert_eq!(ext.get_or_insert_default::<Number>(), &Number(10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set() {
|
||||
let mut ext = Extensions::default();
|
||||
assert!(!ext.set(Number(10)));
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(10)));
|
||||
assert!(ext.set(Number(20)));
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(20)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset() {
|
||||
let mut ext = Extensions::default();
|
||||
assert_eq!(ext.get::<Number>(), None);
|
||||
|
||||
assert!(ext.remove::<Number>().is_none());
|
||||
assert_eq!(ext.get::<Number>(), None);
|
||||
|
||||
assert!(!ext.set(Number(10)));
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(10)));
|
||||
|
||||
assert!(ext.remove::<Number>().is_some());
|
||||
assert_eq!(ext.get::<Number>(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update() {
|
||||
let mut ext = Extensions::default();
|
||||
assert_eq!(ext.get::<Number>(), None);
|
||||
|
||||
let mut new = Extensions::default();
|
||||
assert!(!new.set(Number(10)));
|
||||
|
||||
ext.update(&new);
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(10)));
|
||||
}
|
||||
}
|
||||
impl<T> Extension for T where T: std::fmt::Debug + Clone + std::any::Any + Send + Sync + 'static {}
|
||||
|
|
|
@ -28,6 +28,8 @@ pub mod styling;
|
|||
pub use self::str::Str;
|
||||
pub use action::ArgAction;
|
||||
pub use arg::Arg;
|
||||
#[cfg(feature = "unstable-ext")]
|
||||
pub use arg::ArgExt;
|
||||
pub use arg_group::ArgGroup;
|
||||
pub use arg_predicate::ArgPredicate;
|
||||
pub use command::Command;
|
||||
|
|
|
@ -64,16 +64,6 @@ impl From<Str> for OsStr {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "perf")]
|
||||
impl From<&'_ Str> for OsStr {
|
||||
fn from(id: &'_ Str) -> Self {
|
||||
match id.clone().into_inner() {
|
||||
crate::builder::StrInner::Static(s) => Self::from_static_ref(std::ffi::OsStr::new(s)),
|
||||
crate::builder::StrInner::Owned(s) => Self::from_ref(std::ffi::OsStr::new(s.as_ref())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Str> for OsStr {
|
||||
fn from(id: &'_ Str) -> Self {
|
||||
id.clone().into()
|
||||
|
@ -95,15 +85,15 @@ impl From<&'_ std::ffi::OsString> for OsStr {
|
|||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<std::string::String> for OsStr {
|
||||
fn from(name: std::string::String) -> Self {
|
||||
impl From<String> for OsStr {
|
||||
fn from(name: String) -> Self {
|
||||
Self::from_string(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ std::string::String> for OsStr {
|
||||
fn from(name: &'_ std::string::String) -> Self {
|
||||
impl From<&'_ String> for OsStr {
|
||||
fn from(name: &'_ String) -> Self {
|
||||
Self::from_ref(name.as_str().as_ref())
|
||||
}
|
||||
}
|
||||
|
@ -220,13 +210,13 @@ impl PartialEq<OsStr> for &'_ std::ffi::OsStr {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::string::String> for OsStr {
|
||||
impl PartialEq<String> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::string::String) -> bool {
|
||||
fn eq(&self, other: &String) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for std::string::String {
|
||||
impl PartialEq<OsStr> for String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_os_str())
|
||||
|
@ -316,7 +306,7 @@ impl PartialEq for Inner {
|
|||
|
||||
impl PartialOrd for Inner {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
self.as_os_str().partial_cmp(other.as_os_str())
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ impl PossibleValue {
|
|||
self.hide
|
||||
}
|
||||
|
||||
/// Report if PossibleValue is not hidden and has a help message
|
||||
/// Report if `PossibleValue` is not hidden and has a help message
|
||||
pub(crate) fn should_show_help(&self) -> bool {
|
||||
!self.hide && self.help.is_some()
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ impl From<std::ops::RangeToInclusive<usize>> for ValueRange {
|
|||
}
|
||||
|
||||
impl std::fmt::Display for ValueRange {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
ok!(self.start_inclusive.fmt(f));
|
||||
if !self.is_fixed() {
|
||||
ok!("..=".fmt(f));
|
||||
|
@ -185,7 +185,7 @@ impl std::fmt::Display for ValueRange {
|
|||
}
|
||||
|
||||
impl std::fmt::Debug for ValueRange {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{self}")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ pub struct Str {
|
|||
|
||||
impl Str {
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_string(name: std::string::String) -> Self {
|
||||
pub(crate) fn from_string(name: String) -> Self {
|
||||
Self {
|
||||
name: Inner::from_string(name),
|
||||
}
|
||||
|
@ -45,15 +45,15 @@ impl From<&'_ Str> for Str {
|
|||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<std::string::String> for Str {
|
||||
fn from(name: std::string::String) -> Self {
|
||||
impl From<String> for Str {
|
||||
fn from(name: String) -> Self {
|
||||
Self::from_string(name)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ std::string::String> for Str {
|
||||
fn from(name: &'_ std::string::String) -> Self {
|
||||
impl From<&'_ String> for Str {
|
||||
fn from(name: &'_ String) -> Self {
|
||||
Self::from_ref(name.as_str())
|
||||
}
|
||||
}
|
||||
|
@ -204,13 +204,13 @@ impl PartialEq<Str> for &'_ std::ffi::OsStr {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::string::String> for Str {
|
||||
impl PartialEq<String> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::string::String) -> bool {
|
||||
fn eq(&self, other: &String) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for std::string::String {
|
||||
impl PartialEq<Str> for String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
|
@ -226,7 +226,7 @@ pub(crate) mod inner {
|
|||
}
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_string(name: std::string::String) -> Self {
|
||||
pub(crate) fn from_string(name: String) -> Self {
|
||||
Self::Owned(name.into_boxed_str())
|
||||
}
|
||||
|
||||
|
@ -290,7 +290,7 @@ impl PartialEq for Inner {
|
|||
|
||||
impl PartialOrd for Inner {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
self.as_str().partial_cmp(other.as_str())
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,21 +45,17 @@ impl StyledStr {
|
|||
self.0.push_str(msg);
|
||||
}
|
||||
|
||||
pub(crate) fn trim(&mut self) {
|
||||
self.0 = self.0.trim().to_owned()
|
||||
}
|
||||
|
||||
pub(crate) fn trim_start_lines(&mut self) {
|
||||
if let Some(pos) = self.0.find('\n') {
|
||||
let (leading, help) = self.0.split_at(pos + 1);
|
||||
if leading.trim().is_empty() {
|
||||
self.0 = help.to_owned()
|
||||
self.0 = help.to_owned();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn trim_end(&mut self) {
|
||||
self.0 = self.0.trim_end().to_owned()
|
||||
self.0 = self.0.trim_end().to_owned();
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
|
@ -160,14 +156,14 @@ impl Default for &'_ StyledStr {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<std::string::String> for StyledStr {
|
||||
fn from(name: std::string::String) -> Self {
|
||||
impl From<String> for StyledStr {
|
||||
fn from(name: String) -> Self {
|
||||
StyledStr(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ std::string::String> for StyledStr {
|
||||
fn from(name: &'_ std::string::String) -> Self {
|
||||
impl From<&'_ String> for StyledStr {
|
||||
fn from(name: &'_ String) -> Self {
|
||||
let mut styled = StyledStr::new();
|
||||
styled.push_str(name);
|
||||
styled
|
||||
|
@ -204,7 +200,7 @@ impl std::fmt::Write for StyledStr {
|
|||
|
||||
/// Color-unaware printing. Never uses coloring.
|
||||
impl std::fmt::Display for StyledStr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for part in self.iter_text() {
|
||||
part.fmt(f)?;
|
||||
}
|
||||
|
|
|
@ -21,26 +21,26 @@ pub use anstyle::*;
|
|||
#[derive(Clone, Debug)]
|
||||
#[allow(missing_copy_implementations)] // Large enough type that I want an explicit `clone()` for now
|
||||
pub struct Styles {
|
||||
header: anstyle::Style,
|
||||
error: anstyle::Style,
|
||||
usage: anstyle::Style,
|
||||
literal: anstyle::Style,
|
||||
placeholder: anstyle::Style,
|
||||
valid: anstyle::Style,
|
||||
invalid: anstyle::Style,
|
||||
header: Style,
|
||||
error: Style,
|
||||
usage: Style,
|
||||
literal: Style,
|
||||
placeholder: Style,
|
||||
valid: Style,
|
||||
invalid: Style,
|
||||
}
|
||||
|
||||
impl Styles {
|
||||
/// No terminal styling
|
||||
pub const fn plain() -> Self {
|
||||
Self {
|
||||
header: anstyle::Style::new(),
|
||||
error: anstyle::Style::new(),
|
||||
usage: anstyle::Style::new(),
|
||||
literal: anstyle::Style::new(),
|
||||
placeholder: anstyle::Style::new(),
|
||||
valid: anstyle::Style::new(),
|
||||
invalid: anstyle::Style::new(),
|
||||
header: Style::new(),
|
||||
error: Style::new(),
|
||||
usage: Style::new(),
|
||||
literal: Style::new(),
|
||||
placeholder: Style::new(),
|
||||
valid: Style::new(),
|
||||
invalid: Style::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,17 +49,15 @@ impl Styles {
|
|||
#[cfg(feature = "color")]
|
||||
{
|
||||
Self {
|
||||
header: anstyle::Style::new().bold().underline(),
|
||||
error: anstyle::Style::new()
|
||||
.fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Red)))
|
||||
header: Style::new().bold().underline(),
|
||||
error: Style::new()
|
||||
.fg_color(Some(Color::Ansi(AnsiColor::Red)))
|
||||
.bold(),
|
||||
usage: anstyle::Style::new().bold().underline(),
|
||||
literal: anstyle::Style::new().bold(),
|
||||
placeholder: anstyle::Style::new(),
|
||||
valid: anstyle::Style::new()
|
||||
.fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Green))),
|
||||
invalid: anstyle::Style::new()
|
||||
.fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Yellow))),
|
||||
usage: Style::new().bold().underline(),
|
||||
literal: Style::new().bold(),
|
||||
placeholder: Style::new(),
|
||||
valid: Style::new().fg_color(Some(Color::Ansi(AnsiColor::Green))),
|
||||
invalid: Style::new().fg_color(Some(Color::Ansi(AnsiColor::Yellow))),
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "color"))]
|
||||
|
@ -70,49 +68,49 @@ impl Styles {
|
|||
|
||||
/// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading]
|
||||
#[inline]
|
||||
pub const fn header(mut self, style: anstyle::Style) -> Self {
|
||||
pub const fn header(mut self, style: Style) -> Self {
|
||||
self.header = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Error heading
|
||||
#[inline]
|
||||
pub const fn error(mut self, style: anstyle::Style) -> Self {
|
||||
pub const fn error(mut self, style: Style) -> Self {
|
||||
self.error = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Usage heading
|
||||
#[inline]
|
||||
pub const fn usage(mut self, style: anstyle::Style) -> Self {
|
||||
pub const fn usage(mut self, style: Style) -> Self {
|
||||
self.usage = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Literal command-line syntax, e.g. `--help`
|
||||
#[inline]
|
||||
pub const fn literal(mut self, style: anstyle::Style) -> Self {
|
||||
pub const fn literal(mut self, style: Style) -> Self {
|
||||
self.literal = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Descriptions within command-line syntax, e.g. [`value_name`][crate::Arg::value_name]
|
||||
#[inline]
|
||||
pub const fn placeholder(mut self, style: anstyle::Style) -> Self {
|
||||
pub const fn placeholder(mut self, style: Style) -> Self {
|
||||
self.placeholder = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Highlight suggested usage
|
||||
#[inline]
|
||||
pub const fn valid(mut self, style: anstyle::Style) -> Self {
|
||||
pub const fn valid(mut self, style: Style) -> Self {
|
||||
self.valid = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Highlight invalid usage
|
||||
#[inline]
|
||||
pub const fn invalid(mut self, style: anstyle::Style) -> Self {
|
||||
pub const fn invalid(mut self, style: Style) -> Self {
|
||||
self.invalid = style;
|
||||
self
|
||||
}
|
||||
|
@ -122,43 +120,43 @@ impl Styles {
|
|||
impl Styles {
|
||||
/// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading]
|
||||
#[inline(always)]
|
||||
pub const fn get_header(&self) -> &anstyle::Style {
|
||||
pub const fn get_header(&self) -> &Style {
|
||||
&self.header
|
||||
}
|
||||
|
||||
/// Error heading
|
||||
#[inline(always)]
|
||||
pub const fn get_error(&self) -> &anstyle::Style {
|
||||
pub const fn get_error(&self) -> &Style {
|
||||
&self.error
|
||||
}
|
||||
|
||||
/// Usage heading
|
||||
#[inline(always)]
|
||||
pub const fn get_usage(&self) -> &anstyle::Style {
|
||||
pub const fn get_usage(&self) -> &Style {
|
||||
&self.usage
|
||||
}
|
||||
|
||||
/// Literal command-line syntax, e.g. `--help`
|
||||
#[inline(always)]
|
||||
pub const fn get_literal(&self) -> &anstyle::Style {
|
||||
pub const fn get_literal(&self) -> &Style {
|
||||
&self.literal
|
||||
}
|
||||
|
||||
/// Descriptions within command-line syntax, e.g. [`value_name`][crate::Arg::value_name]
|
||||
#[inline(always)]
|
||||
pub const fn get_placeholder(&self) -> &anstyle::Style {
|
||||
pub const fn get_placeholder(&self) -> &Style {
|
||||
&self.placeholder
|
||||
}
|
||||
|
||||
/// Highlight suggested usage
|
||||
#[inline(always)]
|
||||
pub const fn get_valid(&self) -> &anstyle::Style {
|
||||
pub const fn get_valid(&self) -> &Style {
|
||||
&self.valid
|
||||
}
|
||||
|
||||
/// Highlight invalid usage
|
||||
#[inline(always)]
|
||||
pub const fn get_invalid(&self) -> &anstyle::Style {
|
||||
pub const fn get_invalid(&self) -> &Style {
|
||||
&self.invalid
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ fn global_setting() {
|
|||
#[test]
|
||||
fn app_send_sync() {
|
||||
fn foo<T: Send + Sync>(_: T) {}
|
||||
foo(Command::new("test"))
|
||||
foo(Command::new("test"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -52,5 +52,5 @@ fn issue_2090() {
|
|||
#[test]
|
||||
fn arg_send_sync() {
|
||||
fn foo<T: Send + Sync>(_: T) {}
|
||||
foo(Arg::new("test"))
|
||||
foo(Arg::new("test"));
|
||||
}
|
||||
|
|
|
@ -2,25 +2,25 @@ use std::str::FromStr;
|
|||
|
||||
/// Provide shell with hint on how to complete an argument.
|
||||
///
|
||||
/// See [Arg::value_hint][crate::Arg::value_hint] to set this on an argument.
|
||||
/// See [`Arg::value_hint`][crate::Arg::value_hint] to set this on an argument.
|
||||
///
|
||||
/// See the `clap_complete` crate for completion script generation.
|
||||
///
|
||||
/// Overview of which hints are supported by which shell:
|
||||
///
|
||||
/// | Hint | zsh | fish[^1]|
|
||||
/// | ---------------------- | --- | ------- |
|
||||
/// | `AnyPath` | Yes | Yes |
|
||||
/// | `FilePath` | Yes | Yes |
|
||||
/// | `DirPath` | Yes | Yes |
|
||||
/// | `ExecutablePath` | Yes | Partial |
|
||||
/// | `CommandName` | Yes | Yes |
|
||||
/// | `CommandString` | Yes | Partial |
|
||||
/// | `CommandWithArguments` | Yes | |
|
||||
/// | `Username` | Yes | Yes |
|
||||
/// | `Hostname` | Yes | Yes |
|
||||
/// | `Url` | Yes | |
|
||||
/// | `EmailAddress` | Yes | |
|
||||
/// | Hint | zsh | fish[^1] | dynamic |
|
||||
/// | ---------------------- | --- | ---------|---------|
|
||||
/// | `AnyPath` | Yes | Yes | Yes |
|
||||
/// | `FilePath` | Yes | Yes | Yes |
|
||||
/// | `DirPath` | Yes | Yes | Yes |
|
||||
/// | `ExecutablePath` | Yes | Partial | Yes |
|
||||
/// | `CommandName` | Yes | Yes | No |
|
||||
/// | `CommandString` | Yes | Partial | No |
|
||||
/// | `CommandWithArguments` | Yes | | No |
|
||||
/// | `Username` | Yes | Yes | No |
|
||||
/// | `Hostname` | Yes | Yes | No |
|
||||
/// | `Url` | Yes | | No |
|
||||
/// | `EmailAddress` | Yes | | No |
|
||||
///
|
||||
/// [^1]: fish completions currently only support named arguments (e.g. -o or --opt), not
|
||||
/// positional arguments.
|
||||
|
@ -67,6 +67,9 @@ pub enum ValueHint {
|
|||
EmailAddress,
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-ext")]
|
||||
impl crate::builder::ArgExt for ValueHint {}
|
||||
|
||||
impl FromStr for ValueHint {
|
||||
type Err = String;
|
||||
fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
|
||||
|
|
|
@ -564,7 +564,7 @@ where
|
|||
}
|
||||
|
||||
impl std::fmt::Debug for ValueParser {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
match &self.0 {
|
||||
ValueParserInner::Bool => f.debug_struct("ValueParser::bool").finish(),
|
||||
ValueParserInner::String => f.debug_struct("ValueParser::string").finish(),
|
||||
|
@ -606,23 +606,6 @@ trait AnyValueParser: Send + Sync + 'static {
|
|||
self.parse_ref(cmd, arg, value)
|
||||
}
|
||||
|
||||
fn parse(
|
||||
&self,
|
||||
cmd: &crate::Command,
|
||||
arg: Option<&crate::Arg>,
|
||||
value: std::ffi::OsString,
|
||||
) -> Result<AnyValue, crate::Error>;
|
||||
|
||||
fn parse_(
|
||||
&self,
|
||||
cmd: &crate::Command,
|
||||
arg: Option<&crate::Arg>,
|
||||
value: std::ffi::OsString,
|
||||
_source: ValueSource,
|
||||
) -> Result<AnyValue, crate::Error> {
|
||||
self.parse(cmd, arg, value)
|
||||
}
|
||||
|
||||
/// Describes the content of `AnyValue`
|
||||
fn type_id(&self) -> AnyValueId;
|
||||
|
||||
|
@ -659,27 +642,6 @@ where
|
|||
Ok(AnyValue::new(value))
|
||||
}
|
||||
|
||||
fn parse(
|
||||
&self,
|
||||
cmd: &crate::Command,
|
||||
arg: Option<&crate::Arg>,
|
||||
value: std::ffi::OsString,
|
||||
) -> Result<AnyValue, crate::Error> {
|
||||
let value = ok!(TypedValueParser::parse(self, cmd, arg, value));
|
||||
Ok(AnyValue::new(value))
|
||||
}
|
||||
|
||||
fn parse_(
|
||||
&self,
|
||||
cmd: &crate::Command,
|
||||
arg: Option<&crate::Arg>,
|
||||
value: std::ffi::OsString,
|
||||
source: ValueSource,
|
||||
) -> Result<AnyValue, crate::Error> {
|
||||
let value = ok!(TypedValueParser::parse_(self, cmd, arg, value, source));
|
||||
Ok(AnyValue::new(value))
|
||||
}
|
||||
|
||||
fn type_id(&self) -> AnyValueId {
|
||||
AnyValueId::of::<T>()
|
||||
}
|
||||
|
@ -1346,12 +1308,12 @@ where
|
|||
/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("50")).unwrap(), 50);
|
||||
/// ```
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct RangedI64ValueParser<T: std::convert::TryFrom<i64> + Clone + Send + Sync = i64> {
|
||||
pub struct RangedI64ValueParser<T: TryFrom<i64> + Clone + Send + Sync = i64> {
|
||||
bounds: (std::ops::Bound<i64>, std::ops::Bound<i64>),
|
||||
target: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync> RangedI64ValueParser<T> {
|
||||
impl<T: TryFrom<i64> + Clone + Send + Sync> RangedI64ValueParser<T> {
|
||||
/// Select full range of `i64`
|
||||
pub fn new() -> Self {
|
||||
Self::from(..)
|
||||
|
@ -1431,10 +1393,9 @@ impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync> RangedI64ValueParser<T
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync + 'static> TypedValueParser
|
||||
for RangedI64ValueParser<T>
|
||||
impl<T: TryFrom<i64> + Clone + Send + Sync + 'static> TypedValueParser for RangedI64ValueParser<T>
|
||||
where
|
||||
<T as std::convert::TryFrom<i64>>::Error: Send + Sync + 'static + std::error::Error + ToString,
|
||||
<T as TryFrom<i64>>::Error: Send + Sync + 'static + std::error::Error + ToString,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
|
@ -1490,7 +1451,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync, B: RangeBounds<i64>> From<B>
|
||||
impl<T: TryFrom<i64> + Clone + Send + Sync, B: RangeBounds<i64>> From<B>
|
||||
for RangedI64ValueParser<T>
|
||||
{
|
||||
fn from(range: B) -> Self {
|
||||
|
@ -1501,7 +1462,7 @@ impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync, B: RangeBounds<i64>> F
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync> Default for RangedI64ValueParser<T> {
|
||||
impl<T: TryFrom<i64> + Clone + Send + Sync> Default for RangedI64ValueParser<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
|
@ -1546,12 +1507,12 @@ impl<T: std::convert::TryFrom<i64> + Clone + Send + Sync> Default for RangedI64V
|
|||
/// assert_eq!(value_parser.parse_ref(&cmd, arg, OsStr::new("50")).unwrap(), 50);
|
||||
/// ```
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct RangedU64ValueParser<T: std::convert::TryFrom<u64> = u64> {
|
||||
pub struct RangedU64ValueParser<T: TryFrom<u64> = u64> {
|
||||
bounds: (std::ops::Bound<u64>, std::ops::Bound<u64>),
|
||||
target: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: std::convert::TryFrom<u64>> RangedU64ValueParser<T> {
|
||||
impl<T: TryFrom<u64>> RangedU64ValueParser<T> {
|
||||
/// Select full range of `u64`
|
||||
pub fn new() -> Self {
|
||||
Self::from(..)
|
||||
|
@ -1631,10 +1592,9 @@ impl<T: std::convert::TryFrom<u64>> RangedU64ValueParser<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: std::convert::TryFrom<u64> + Clone + Send + Sync + 'static> TypedValueParser
|
||||
for RangedU64ValueParser<T>
|
||||
impl<T: TryFrom<u64> + Clone + Send + Sync + 'static> TypedValueParser for RangedU64ValueParser<T>
|
||||
where
|
||||
<T as std::convert::TryFrom<u64>>::Error: Send + Sync + 'static + std::error::Error + ToString,
|
||||
<T as TryFrom<u64>>::Error: Send + Sync + 'static + std::error::Error + ToString,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
|
@ -1690,7 +1650,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: std::convert::TryFrom<u64>, B: RangeBounds<u64>> From<B> for RangedU64ValueParser<T> {
|
||||
impl<T: TryFrom<u64>, B: RangeBounds<u64>> From<B> for RangedU64ValueParser<T> {
|
||||
fn from(range: B) -> Self {
|
||||
Self {
|
||||
bounds: (range.start_bound().cloned(), range.end_bound().cloned()),
|
||||
|
@ -1699,7 +1659,7 @@ impl<T: std::convert::TryFrom<u64>, B: RangeBounds<u64>> From<B> for RangedU64Va
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: std::convert::TryFrom<u64>> Default for RangedU64ValueParser<T> {
|
||||
impl<T: TryFrom<u64>> Default for RangedU64ValueParser<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
|
@ -1913,7 +1873,7 @@ impl Default for FalseyValueParser {
|
|||
pub struct BoolishValueParser {}
|
||||
|
||||
impl BoolishValueParser {
|
||||
/// Parse bool-like string values, everything else is `true`
|
||||
/// Parse bool-like string values, everything else is an error.
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
@ -2158,7 +2118,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// When encountered, report [ErrorKind::UnknownArgument][crate::error::ErrorKind::UnknownArgument]
|
||||
/// When encountered, report [`ErrorKind::UnknownArgument`][crate::error::ErrorKind::UnknownArgument]
|
||||
///
|
||||
/// Useful to help users migrate, either from old versions or similar tools.
|
||||
///
|
||||
|
@ -2274,7 +2234,7 @@ impl TypedValueParser for UnknownArgumentValueParser {
|
|||
}
|
||||
}
|
||||
|
||||
/// Register a type with [value_parser!][crate::value_parser!]
|
||||
/// Register a type with [`value_parser!`][crate::value_parser!]
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -2650,10 +2610,6 @@ macro_rules! value_parser {
|
|||
mod private {
|
||||
use super::*;
|
||||
|
||||
// Prefer these so `clap_derive` defaults to optimized implementations
|
||||
pub trait _ValueParserViaSelfSealed {}
|
||||
impl<P: Into<ValueParser>> _ValueParserViaSelfSealed for &&&&&&&_AutoValueParser<P> {}
|
||||
|
||||
pub trait _ValueParserViaFactorySealed {}
|
||||
impl<P: ValueParserFactory> _ValueParserViaFactorySealed for &&&&&&_AutoValueParser<P> {}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ use std::ffi::OsString;
|
|||
///
|
||||
/// **NOTE:** Deriving requires the `derive` feature flag
|
||||
pub trait Parser: FromArgMatches + CommandFactory + Sized {
|
||||
/// Parse from `std::env::args_os()`, exit on error
|
||||
/// Parse from `std::env::args_os()`, [exit][Error::exit] on error.
|
||||
fn parse() -> Self {
|
||||
let mut matches = <Self as CommandFactory>::command().get_matches();
|
||||
let res = <Self as FromArgMatches>::from_arg_matches_mut(&mut matches)
|
||||
|
@ -43,7 +43,7 @@ pub trait Parser: FromArgMatches + CommandFactory + Sized {
|
|||
<Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>)
|
||||
}
|
||||
|
||||
/// Parse from iterator, exit on error
|
||||
/// Parse from iterator, [exit][Error::exit] on error.
|
||||
fn parse_from<I, T>(itr: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
|
@ -72,7 +72,7 @@ pub trait Parser: FromArgMatches + CommandFactory + Sized {
|
|||
<Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>)
|
||||
}
|
||||
|
||||
/// Update from iterator, exit on error
|
||||
/// Update from iterator, [exit][Error::exit] on error.
|
||||
fn update_from<I, T>(&mut self, itr: I)
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
|
@ -311,10 +311,10 @@ impl<T: Parser> Parser for Box<T> {
|
|||
}
|
||||
|
||||
impl<T: CommandFactory> CommandFactory for Box<T> {
|
||||
fn command<'help>() -> Command {
|
||||
fn command() -> Command {
|
||||
<T as CommandFactory>::command()
|
||||
}
|
||||
fn command_for_update<'help>() -> Command {
|
||||
fn command_for_update() -> Command {
|
||||
<T as CommandFactory>::command_for_update()
|
||||
}
|
||||
}
|
||||
|
@ -355,7 +355,7 @@ impl<T: Subcommand> Subcommand for Box<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn format_error<I: CommandFactory>(err: crate::Error) -> crate::Error {
|
||||
fn format_error<I: CommandFactory>(err: Error) -> Error {
|
||||
let mut cmd = I::command();
|
||||
err.format(&mut cmd)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#![cfg_attr(not(feature = "error-context"), allow(dead_code))]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(unused_imports))]
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::builder::Command;
|
||||
use crate::builder::StyledStr;
|
||||
use crate::builder::Styles;
|
||||
|
@ -12,6 +14,7 @@ use crate::error::ContextKind;
|
|||
use crate::error::ContextValue;
|
||||
use crate::error::ErrorKind;
|
||||
use crate::output::TAB;
|
||||
use crate::ArgAction;
|
||||
|
||||
/// Defines how to format an error for displaying to the user
|
||||
pub trait ErrorFormatter: Sized {
|
||||
|
@ -120,7 +123,7 @@ impl ErrorFormatter for RichFormatter {
|
|||
put_usage(&mut styled, usage);
|
||||
}
|
||||
|
||||
try_help(&mut styled, styles, error.inner.help_flag);
|
||||
try_help(&mut styled, styles, error.inner.help_flag.as_deref());
|
||||
|
||||
styled
|
||||
}
|
||||
|
@ -146,12 +149,10 @@ fn write_dynamic_context(
|
|||
|
||||
match error.kind() {
|
||||
ErrorKind::ArgumentConflict => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
let prior_arg = error.get(ContextKind::PriorArg);
|
||||
if let (Some(ContextValue::String(invalid_arg)), Some(prior_arg)) =
|
||||
(invalid_arg, prior_arg)
|
||||
{
|
||||
if ContextValue::String(invalid_arg.clone()) == *prior_arg {
|
||||
let mut prior_arg = error.get(ContextKind::PriorArg);
|
||||
if let Some(ContextValue::String(invalid_arg)) = error.get(ContextKind::InvalidArg) {
|
||||
if Some(&ContextValue::String(invalid_arg.clone())) == prior_arg {
|
||||
prior_arg = None;
|
||||
let _ = write!(
|
||||
styled,
|
||||
"the argument '{}{invalid_arg}{}' cannot be used multiple times",
|
||||
|
@ -165,36 +166,48 @@ fn write_dynamic_context(
|
|||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
}
|
||||
} else if let Some(ContextValue::String(invalid_arg)) =
|
||||
error.get(ContextKind::InvalidSubcommand)
|
||||
{
|
||||
let _ = write!(
|
||||
styled,
|
||||
"the subcommand '{}{invalid_arg}{}' cannot be used with",
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
} else {
|
||||
styled.push_str(error.kind().as_str().unwrap());
|
||||
}
|
||||
|
||||
match prior_arg {
|
||||
ContextValue::Strings(values) => {
|
||||
styled.push_str(":");
|
||||
for v in values {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"\n{TAB}{}{v}{}",
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
}
|
||||
}
|
||||
ContextValue::String(value) => {
|
||||
if let Some(prior_arg) = prior_arg {
|
||||
match prior_arg {
|
||||
ContextValue::Strings(values) => {
|
||||
styled.push_str(":");
|
||||
for v in values {
|
||||
let _ = write!(
|
||||
styled,
|
||||
" '{}{value}{}'",
|
||||
"\n{TAB}{}{v}{}",
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
styled.push_str(" one or more of the other specified arguments");
|
||||
}
|
||||
}
|
||||
ContextValue::String(value) => {
|
||||
let _ = write!(
|
||||
styled,
|
||||
" '{}{value}{}'",
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
styled.push_str(" one or more of the other specified arguments");
|
||||
}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
ErrorKind::NoEquals => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
|
@ -327,7 +340,7 @@ fn write_dynamic_context(
|
|||
let were_provided = singular_or_plural(*actual_num_values as usize);
|
||||
let _ = write!(
|
||||
styled,
|
||||
"{}{min_values}{} more values required by '{}{invalid_arg}{}'; only {}{actual_num_values}{}{were_provided}",
|
||||
"{}{min_values}{} values required by '{}{invalid_arg}{}'; only {}{actual_num_values}{}{were_provided}",
|
||||
valid.render(),
|
||||
valid.render_reset(),
|
||||
literal.render(),
|
||||
|
@ -451,7 +464,7 @@ pub(crate) fn format_error_message(
|
|||
put_usage(&mut styled, usage);
|
||||
}
|
||||
if let Some(cmd) = cmd {
|
||||
try_help(&mut styled, styles, get_help_flag(cmd));
|
||||
try_help(&mut styled, styles, get_help_flag(cmd).as_deref());
|
||||
}
|
||||
styled
|
||||
}
|
||||
|
@ -470,16 +483,34 @@ fn put_usage(styled: &mut StyledStr, usage: &StyledStr) {
|
|||
styled.push_styled(usage);
|
||||
}
|
||||
|
||||
pub(crate) fn get_help_flag(cmd: &Command) -> Option<&'static str> {
|
||||
pub(crate) fn get_help_flag(cmd: &Command) -> Option<Cow<'static, str>> {
|
||||
if !cmd.is_disable_help_flag_set() {
|
||||
Some("--help")
|
||||
Some(Cow::Borrowed("--help"))
|
||||
} else if let Some(flag) = get_user_help_flag(cmd) {
|
||||
Some(Cow::Owned(flag))
|
||||
} else if cmd.has_subcommands() && !cmd.is_disable_help_subcommand_set() {
|
||||
Some("help")
|
||||
Some(Cow::Borrowed("help"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_user_help_flag(cmd: &Command) -> Option<String> {
|
||||
let arg = cmd.get_arguments().find(|arg| match arg.get_action() {
|
||||
ArgAction::Help | ArgAction::HelpShort | ArgAction::HelpLong => true,
|
||||
ArgAction::Append
|
||||
| ArgAction::Count
|
||||
| ArgAction::SetTrue
|
||||
| ArgAction::SetFalse
|
||||
| ArgAction::Set
|
||||
| ArgAction::Version => false,
|
||||
})?;
|
||||
|
||||
arg.get_long()
|
||||
.map(|long| format!("--{long}"))
|
||||
.or_else(|| arg.get_short().map(|short| format!("-{short}")))
|
||||
}
|
||||
|
||||
fn try_help(styled: &mut StyledStr, styles: &Styles, help: Option<&str>) {
|
||||
if let Some(help) = help {
|
||||
use std::fmt::Write as _;
|
||||
|
@ -535,7 +566,7 @@ fn did_you_mean(styled: &mut StyledStr, styles: &Styles, context: &str, valid: &
|
|||
struct Escape<'s>(&'s str);
|
||||
|
||||
impl<'s> std::fmt::Display for Escape<'s> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.0.contains(char::is_whitespace) {
|
||||
std::fmt::Debug::fmt(self.0, f)
|
||||
} else {
|
||||
|
|
|
@ -12,7 +12,7 @@ use std::{
|
|||
convert::From,
|
||||
error,
|
||||
fmt::{self, Debug, Display, Formatter},
|
||||
io::{self},
|
||||
io,
|
||||
result::Result as StdResult,
|
||||
};
|
||||
|
||||
|
@ -23,7 +23,7 @@ use crate::output::fmt::Colorizer;
|
|||
use crate::output::fmt::Stream;
|
||||
use crate::parser::features::suggestions;
|
||||
use crate::util::FlatMap;
|
||||
use crate::util::{color::ColorChoice, safe_exit, SUCCESS_CODE, USAGE_CODE};
|
||||
use crate::util::{color::ColorChoice, SUCCESS_CODE, USAGE_CODE};
|
||||
use crate::Command;
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
|
@ -69,7 +69,7 @@ struct ErrorInner {
|
|||
context: FlatMap<ContextKind, ContextValue>,
|
||||
message: Option<Message>,
|
||||
source: Option<Box<dyn error::Error + Send + Sync>>,
|
||||
help_flag: Option<&'static str>,
|
||||
help_flag: Option<Cow<'static, str>>,
|
||||
styles: Styles,
|
||||
color_when: ColorChoice,
|
||||
color_help_when: ColorChoice,
|
||||
|
@ -85,7 +85,7 @@ impl<F: ErrorFormatter> Error<F> {
|
|||
/// Prefer [`Command::error`] for generating errors.
|
||||
///
|
||||
/// [`Command::error`]: crate::Command::error
|
||||
pub fn raw(kind: ErrorKind, message: impl std::fmt::Display) -> Self {
|
||||
pub fn raw(kind: ErrorKind, message: impl Display) -> Self {
|
||||
Self::new(kind).set_message(message.to_string())
|
||||
}
|
||||
|
||||
|
@ -233,7 +233,7 @@ impl<F: ErrorFormatter> Error<F> {
|
|||
pub fn exit(&self) -> ! {
|
||||
// Swallow broken pipe errors
|
||||
let _ = self.print();
|
||||
safe_exit(self.exit_code())
|
||||
std::process::exit(self.exit_code());
|
||||
}
|
||||
|
||||
/// Prints formatted and colored error to `stdout` or `stderr` according to its error kind
|
||||
|
@ -319,7 +319,7 @@ impl<F: ErrorFormatter> Error<F> {
|
|||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_help_flag(mut self, help_flag: Option<&'static str>) -> Self {
|
||||
pub(crate) fn set_help_flag(mut self, help_flag: Option<Cow<'static, str>>) -> Self {
|
||||
self.inner.help_flag = help_flag;
|
||||
self
|
||||
}
|
||||
|
@ -391,6 +391,34 @@ impl<F: ErrorFormatter> Error<F> {
|
|||
err
|
||||
}
|
||||
|
||||
pub(crate) fn subcommand_conflict(
|
||||
cmd: &Command,
|
||||
sub: String,
|
||||
mut others: Vec<String>,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::ArgumentConflict).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
let others = match others.len() {
|
||||
0 => ContextValue::None,
|
||||
1 => ContextValue::String(others.pop().unwrap()),
|
||||
_ => ContextValue::Strings(others),
|
||||
};
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidSubcommand, ContextValue::String(sub)),
|
||||
(ContextKind::PriorArg, others),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn empty_value(cmd: &Command, good_vals: &[String], arg: String) -> Self {
|
||||
Self::invalid_value(cmd, "".to_owned(), good_vals, arg)
|
||||
}
|
||||
|
@ -427,7 +455,7 @@ impl<F: ErrorFormatter> Error<F> {
|
|||
(ContextKind::InvalidValue, ContextValue::String(bad_val)),
|
||||
(
|
||||
ContextKind::ValidValue,
|
||||
ContextValue::Strings(good_vals.iter().map(|s| (*s).to_owned()).collect()),
|
||||
ContextValue::Strings(good_vals.iter().map(|s| (*s).clone()).collect()),
|
||||
),
|
||||
]);
|
||||
if let Some(suggestion) = suggestion {
|
||||
|
@ -804,8 +832,8 @@ impl<F: ErrorFormatter> From<fmt::Error> for Error<F> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> std::fmt::Debug for Error<F> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
impl<F: ErrorFormatter> Debug for Error<F> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
@ -818,7 +846,7 @@ impl<F: ErrorFormatter> error::Error for Error<F> {
|
|||
}
|
||||
|
||||
impl<F: ErrorFormatter> Display for Error<F> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
// Assuming `self.message` already has a trailing newline, from `try_help` or similar
|
||||
ok!(write!(f, "{}", self.formatted()));
|
||||
if let Some(backtrace) = self.inner.backtrace.as_ref() {
|
||||
|
@ -856,7 +884,7 @@ impl Message {
|
|||
}
|
||||
}
|
||||
|
||||
fn formatted(&self, styles: &Styles) -> Cow<StyledStr> {
|
||||
fn formatted(&self, styles: &Styles) -> Cow<'_, StyledStr> {
|
||||
match self {
|
||||
Message::Raw(s) => {
|
||||
let styled = format::format_error_message(s, styles, None, None);
|
||||
|
@ -893,7 +921,7 @@ impl Backtrace {
|
|||
|
||||
#[cfg(feature = "debug")]
|
||||
impl Display for Backtrace {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
// `backtrace::Backtrace` uses `Debug` instead of `Display`
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
|
@ -912,7 +940,7 @@ impl Backtrace {
|
|||
|
||||
#[cfg(not(feature = "debug"))]
|
||||
impl Display for Backtrace {
|
||||
fn fmt(&self, _: &mut Formatter) -> fmt::Result {
|
||||
fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,30 +3,13 @@
|
|||
// (see LICENSE or <http://opensource.org/licenses/MIT>) All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
|
||||
#![warn(
|
||||
missing_docs,
|
||||
missing_debug_implementations,
|
||||
missing_copy_implementations,
|
||||
trivial_casts,
|
||||
unused_allocation,
|
||||
trivial_numeric_casts,
|
||||
clippy::single_char_pattern
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![forbid(unsafe_code)]
|
||||
// Wanting consistency in our calls
|
||||
#![allow(clippy::write_with_newline)]
|
||||
// Gets in the way of logging
|
||||
#![allow(clippy::let_and_return)]
|
||||
// HACK https://github.com/rust-lang/rust-clippy/issues/7290
|
||||
#![allow(clippy::single_component_path_imports)]
|
||||
#![allow(clippy::branches_sharing_code)]
|
||||
// Doesn't allow for debug statements, etc to be unique
|
||||
#![allow(clippy::if_same_then_else)]
|
||||
// Breaks up parallelism that clarifies intent
|
||||
#![allow(clippy::collapsible_else_if)]
|
||||
#![warn(missing_docs)]
|
||||
#![warn(clippy::print_stderr)]
|
||||
#![warn(clippy::print_stdout)]
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
compile_error!("`std` feature is currently required to build `clap`");
|
||||
|
@ -44,7 +27,7 @@ pub use crate::util::Id;
|
|||
/// See [`Command::error`] to create an error.
|
||||
///
|
||||
/// [`Command::error`]: crate::Command::error
|
||||
pub type Error = crate::error::Error<crate::error::DefaultFormatter>;
|
||||
pub type Error = error::Error<error::DefaultFormatter>;
|
||||
|
||||
pub use crate::derive::{Args, CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum};
|
||||
|
||||
|
|
|
@ -42,14 +42,14 @@ macro_rules! crate_version {
|
|||
#[macro_export]
|
||||
macro_rules! crate_authors {
|
||||
($sep:expr) => {{
|
||||
static authors: &str = env!("CARGO_PKG_AUTHORS");
|
||||
if authors.contains(':') {
|
||||
static AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
|
||||
if AUTHORS.contains(':') {
|
||||
static CACHED: std::sync::OnceLock<String> = std::sync::OnceLock::new();
|
||||
let s = CACHED.get_or_init(|| authors.replace(':', $sep));
|
||||
let s = CACHED.get_or_init(|| AUTHORS.replace(':', $sep));
|
||||
let s: &'static str = &*s;
|
||||
s
|
||||
} else {
|
||||
authors
|
||||
AUTHORS
|
||||
}
|
||||
}};
|
||||
() => {
|
||||
|
|
|
@ -81,7 +81,7 @@ impl PartialEq<char> for KeyType {
|
|||
|
||||
impl MKeyMap {
|
||||
/// If any arg has corresponding key in this map, we can search the key with
|
||||
/// u64(for positional argument), char(for short flag), &str and OsString
|
||||
/// `u64` (for positional argument), `char` (for short flag), `&str` and `OsString`
|
||||
/// (for long flag)
|
||||
pub(crate) fn contains<K>(&self, key: K) -> bool
|
||||
where
|
||||
|
@ -96,8 +96,8 @@ impl MKeyMap {
|
|||
}
|
||||
|
||||
/// Find the arg have corresponding key in this map, we can search the key
|
||||
/// with u64(for positional argument), char(for short flag), &str and
|
||||
/// OsString (for long flag)
|
||||
/// with `u64` (for positional argument), `char` (for short flag), `&str` and
|
||||
/// `OsString` (for long flag)
|
||||
pub(crate) fn get<K: ?Sized>(&self, key: &K) -> Option<&Arg>
|
||||
where
|
||||
KeyType: PartialEq<K>,
|
||||
|
|
|
@ -77,7 +77,7 @@ impl Colorizer {
|
|||
|
||||
/// Color-unaware printing. Never uses coloring.
|
||||
impl std::fmt::Display for Colorizer {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.content.fmt(f)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
// Std
|
||||
use std::borrow::Cow;
|
||||
use std::cmp;
|
||||
use std::usize;
|
||||
|
||||
// Internal
|
||||
use crate::builder::PossibleValue;
|
||||
|
@ -74,7 +73,7 @@ const DEFAULT_NO_ARGS_TEMPLATE: &str = "\
|
|||
{usage-heading} {usage}{after-help}\
|
||||
";
|
||||
|
||||
/// `clap` HelpTemplate Writer.
|
||||
/// Help template writer
|
||||
///
|
||||
/// Wraps a writer stream providing different methods to generate help for `clap` objects.
|
||||
pub(crate) struct HelpTemplate<'cmd, 'writer> {
|
||||
|
@ -393,9 +392,11 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
|
|||
.filter_map(|arg| arg.get_help_heading())
|
||||
.collect::<FlatSet<_>>();
|
||||
|
||||
let flatten = self.cmd.is_flatten_help_set();
|
||||
|
||||
let mut first = true;
|
||||
|
||||
if subcmds {
|
||||
if subcmds && !flatten {
|
||||
if !first {
|
||||
self.writer.push_str("\n\n");
|
||||
}
|
||||
|
@ -474,6 +475,11 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
|
|||
}
|
||||
}
|
||||
}
|
||||
if subcmds && flatten {
|
||||
let mut cmd = self.cmd.clone();
|
||||
cmd.build();
|
||||
self.write_flat_subcommands(&cmd, &mut first);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sorts arguments by length and display order and write their help to the wrapped stream.
|
||||
|
@ -644,7 +650,7 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
|
|||
|
||||
let spaces = if next_line_help {
|
||||
TAB.len() + NEXT_LINE_INDENT.len()
|
||||
} else if let Some(true) = arg.map(|a| a.is_positional()) {
|
||||
} else if arg.map(|a| a.is_positional()).unwrap_or(true) {
|
||||
longest + TAB_WIDTH * 2
|
||||
} else {
|
||||
longest + TAB_WIDTH * 2 + 4 // See `fn short` for the 4
|
||||
|
@ -677,57 +683,56 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
|
|||
let help_is_empty = help.is_empty();
|
||||
self.writer.push_styled(&help);
|
||||
if let Some(arg) = arg {
|
||||
const DASH_SPACE: usize = "- ".len();
|
||||
let possible_vals = arg.get_possible_values();
|
||||
if !possible_vals.is_empty()
|
||||
&& !arg.is_hide_possible_values_set()
|
||||
&& self.use_long_pv(arg)
|
||||
{
|
||||
debug!("HelpTemplate::help: Found possible vals...{possible_vals:?}");
|
||||
let longest = possible_vals
|
||||
.iter()
|
||||
.filter(|f| !f.is_hide_set())
|
||||
.map(|f| display_width(f.get_name()))
|
||||
.max()
|
||||
.expect("Only called with possible value");
|
||||
if !arg.is_hide_possible_values_set() && self.use_long_pv(arg) {
|
||||
const DASH_SPACE: usize = "- ".len();
|
||||
let possible_vals = arg.get_possible_values();
|
||||
if !possible_vals.is_empty() {
|
||||
debug!("HelpTemplate::help: Found possible vals...{possible_vals:?}");
|
||||
let longest = possible_vals
|
||||
.iter()
|
||||
.filter(|f| !f.is_hide_set())
|
||||
.map(|f| display_width(f.get_name()))
|
||||
.max()
|
||||
.expect("Only called with possible value");
|
||||
|
||||
let spaces = spaces + TAB_WIDTH - DASH_SPACE;
|
||||
let trailing_indent = spaces + DASH_SPACE;
|
||||
let trailing_indent = self.get_spaces(trailing_indent);
|
||||
let spaces = spaces + TAB_WIDTH - DASH_SPACE;
|
||||
let trailing_indent = spaces + DASH_SPACE;
|
||||
let trailing_indent = self.get_spaces(trailing_indent);
|
||||
|
||||
if !help_is_empty {
|
||||
let _ = write!(self.writer, "\n\n{:spaces$}", "");
|
||||
}
|
||||
self.writer.push_str("Possible values:");
|
||||
for pv in possible_vals.iter().filter(|pv| !pv.is_hide_set()) {
|
||||
let name = pv.get_name();
|
||||
|
||||
let mut descr = StyledStr::new();
|
||||
let _ = write!(
|
||||
&mut descr,
|
||||
"{}{name}{}",
|
||||
literal.render(),
|
||||
literal.render_reset()
|
||||
);
|
||||
if let Some(help) = pv.get_help() {
|
||||
debug!("HelpTemplate::help: Possible Value help");
|
||||
// To align help messages
|
||||
let padding = longest - display_width(name);
|
||||
let _ = write!(&mut descr, ": {:padding$}", "");
|
||||
descr.push_styled(help);
|
||||
if !help_is_empty {
|
||||
let _ = write!(self.writer, "\n\n{:spaces$}", "");
|
||||
}
|
||||
self.writer.push_str("Possible values:");
|
||||
for pv in possible_vals.iter().filter(|pv| !pv.is_hide_set()) {
|
||||
let name = pv.get_name();
|
||||
|
||||
let avail_chars = if self.term_w > trailing_indent.len() {
|
||||
self.term_w - trailing_indent.len()
|
||||
} else {
|
||||
usize::MAX
|
||||
};
|
||||
descr.replace_newline_var();
|
||||
descr.wrap(avail_chars);
|
||||
descr.indent("", &trailing_indent);
|
||||
let mut descr = StyledStr::new();
|
||||
let _ = write!(
|
||||
&mut descr,
|
||||
"{}{name}{}",
|
||||
literal.render(),
|
||||
literal.render_reset()
|
||||
);
|
||||
if let Some(help) = pv.get_help() {
|
||||
debug!("HelpTemplate::help: Possible Value help");
|
||||
// To align help messages
|
||||
let padding = longest - display_width(name);
|
||||
let _ = write!(&mut descr, ": {:padding$}", "");
|
||||
descr.push_styled(help);
|
||||
}
|
||||
|
||||
let _ = write!(self.writer, "\n{:spaces$}- ", "",);
|
||||
self.writer.push_styled(&descr);
|
||||
let avail_chars = if self.term_w > trailing_indent.len() {
|
||||
self.term_w - trailing_indent.len()
|
||||
} else {
|
||||
usize::MAX
|
||||
};
|
||||
descr.replace_newline_var();
|
||||
descr.wrap(avail_chars);
|
||||
descr.indent("", &trailing_indent);
|
||||
|
||||
let _ = write!(self.writer, "\n{:spaces$}- ", "",);
|
||||
self.writer.push_styled(&descr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -749,7 +754,10 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
|
|||
true
|
||||
} else {
|
||||
// force_next_line
|
||||
let h = arg.get_help().unwrap_or_default();
|
||||
let h = arg
|
||||
.get_help()
|
||||
.or_else(|| arg.get_long_help())
|
||||
.unwrap_or_default();
|
||||
let h_w = h.display_width() + display_width(spec_vals);
|
||||
let taken = if arg.is_positional() {
|
||||
longest + TAB_WIDTH * 2
|
||||
|
@ -837,17 +845,19 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
|
|||
spec_vals.push(format!("[short aliases: {als}]"));
|
||||
}
|
||||
|
||||
let possible_vals = a.get_possible_values();
|
||||
if !possible_vals.is_empty() && !a.is_hide_possible_values_set() && !self.use_long_pv(a) {
|
||||
debug!("HelpTemplate::spec_vals: Found possible vals...{possible_vals:?}");
|
||||
if !a.is_hide_possible_values_set() && !self.use_long_pv(a) {
|
||||
let possible_vals = a.get_possible_values();
|
||||
if !possible_vals.is_empty() {
|
||||
debug!("HelpTemplate::spec_vals: Found possible vals...{possible_vals:?}");
|
||||
|
||||
let pvs = possible_vals
|
||||
.iter()
|
||||
.filter_map(PossibleValue::get_visible_quoted_name)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
let pvs = possible_vals
|
||||
.iter()
|
||||
.filter_map(PossibleValue::get_visible_quoted_name)
|
||||
.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)
|
||||
|
@ -873,6 +883,70 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
|
|||
|
||||
/// Subcommand handling
|
||||
impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
|
||||
/// Writes help for subcommands of a Parser Object to the wrapped stream.
|
||||
fn write_flat_subcommands(&mut self, cmd: &Command, first: &mut bool) {
|
||||
debug!(
|
||||
"HelpTemplate::write_flat_subcommands, cmd={}, first={}",
|
||||
cmd.get_name(),
|
||||
*first
|
||||
);
|
||||
use std::fmt::Write as _;
|
||||
let header = &self.styles.get_header();
|
||||
|
||||
let mut ord_v = Vec::new();
|
||||
for subcommand in cmd
|
||||
.get_subcommands()
|
||||
.filter(|subcommand| should_show_subcommand(subcommand))
|
||||
{
|
||||
ord_v.push((
|
||||
subcommand.get_display_order(),
|
||||
subcommand.get_name(),
|
||||
subcommand,
|
||||
));
|
||||
}
|
||||
ord_v.sort_by(|a, b| (a.0, &a.1).cmp(&(b.0, &b.1)));
|
||||
for (_, _, subcommand) in ord_v {
|
||||
if !*first {
|
||||
self.writer.push_str("\n\n");
|
||||
}
|
||||
*first = false;
|
||||
|
||||
let heading = subcommand.get_usage_name_fallback();
|
||||
let about = subcommand
|
||||
.get_about()
|
||||
.or_else(|| subcommand.get_long_about())
|
||||
.unwrap_or_default();
|
||||
|
||||
let _ = write!(
|
||||
self.writer,
|
||||
"{}{heading}:{}\n",
|
||||
header.render(),
|
||||
header.render_reset()
|
||||
);
|
||||
if !about.is_empty() {
|
||||
let _ = write!(self.writer, "{about}\n",);
|
||||
}
|
||||
|
||||
let mut sub_help = HelpTemplate {
|
||||
writer: self.writer,
|
||||
cmd: subcommand,
|
||||
styles: self.styles,
|
||||
usage: self.usage,
|
||||
next_line_help: self.next_line_help,
|
||||
term_w: self.term_w,
|
||||
use_long: self.use_long,
|
||||
};
|
||||
let args = subcommand
|
||||
.get_arguments()
|
||||
.filter(|arg| should_show_arg(self.use_long, arg) && !arg.is_global_set())
|
||||
.collect::<Vec<_>>();
|
||||
sub_help.write_args(&args, heading, option_sort_key);
|
||||
if subcommand.is_flatten_help_set() {
|
||||
sub_help.write_flat_subcommands(subcommand, first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes help for subcommands of a Parser Object to the wrapped stream.
|
||||
fn write_subcommands(&mut self, cmd: &Command) {
|
||||
debug!("HelpTemplate::write_subcommands");
|
||||
|
@ -959,7 +1033,7 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
|
|||
.unwrap_or_default();
|
||||
|
||||
self.subcmd(sc_str, next_line_help, longest);
|
||||
self.help(None, about, spec_vals, next_line_help, longest)
|
||||
self.help(None, about, spec_vals, next_line_help, longest);
|
||||
}
|
||||
|
||||
fn sc_spec_vals(&self, a: &Command) -> String {
|
||||
|
@ -995,7 +1069,10 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
|
|||
true
|
||||
} else {
|
||||
// force_next_line
|
||||
let h = cmd.get_about().unwrap_or_default();
|
||||
let h = cmd
|
||||
.get_about()
|
||||
.or_else(|| cmd.get_long_about())
|
||||
.unwrap_or_default();
|
||||
let h_w = h.display_width() + display_width(spec_vals);
|
||||
let taken = longest + TAB_WIDTH * 2;
|
||||
self.term_w >= taken
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//!
|
||||
//! Benefits of forking:
|
||||
//! - Pull in only what we need rather than relying on the compiler to remove what we don't need
|
||||
//! - `LineWrapper` is able to incrementally wrap which will help with `StyledStr
|
||||
//! - `LineWrapper` is able to incrementally wrap which will help with `StyledStr`
|
||||
|
||||
pub(crate) mod core;
|
||||
#[cfg(feature = "wrap_help")]
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче