chore(vendor): add anyhow crate
This commit was merged in pull request #68.
This commit is contained in:
1
third_party/crates/clap_builder-4.6.7/.cargo-checksum.json
vendored
Normal file
1
third_party/crates/clap_builder-4.6.7/.cargo-checksum.json
vendored
Normal file
File diff suppressed because one or more lines are too long
6
third_party/crates/clap_builder-4.6.7/.cargo_vcs_info.json
vendored
Normal file
6
third_party/crates/clap_builder-4.6.7/.cargo_vcs_info.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"git": {
|
||||
"sha1": "13f2db5072d600c11d8d6298e4e9ba53ffc6c1ab"
|
||||
},
|
||||
"path_in_vcs": "clap_builder"
|
||||
}
|
||||
124
third_party/crates/clap_builder-4.6.7/BUILD.bazel
vendored
Normal file
124
third_party/crates/clap_builder-4.6.7/BUILD.bazel
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
###############################################################################
|
||||
# @generated
|
||||
# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To
|
||||
# regenerate this file, run the following:
|
||||
#
|
||||
# bazel run @@//third_party:vendor_crates
|
||||
###############################################################################
|
||||
|
||||
load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars")
|
||||
load("@rules_rust//rust:defs.bzl", "rust_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
cargo_toml_env_vars(
|
||||
name = "cargo_toml_env_vars",
|
||||
src = "Cargo.toml",
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "clap_builder",
|
||||
srcs = glob(
|
||||
include = ["**/*.rs"],
|
||||
allow_empty = False,
|
||||
),
|
||||
compile_data = glob(
|
||||
include = ["**"],
|
||||
allow_empty = True,
|
||||
exclude = [
|
||||
"**/* *",
|
||||
".tmp_git_root/**/*",
|
||||
"BUILD",
|
||||
"BUILD.bazel",
|
||||
"WORKSPACE",
|
||||
"WORKSPACE.bazel",
|
||||
],
|
||||
),
|
||||
crate_features = [
|
||||
"color",
|
||||
"error-context",
|
||||
"help",
|
||||
"std",
|
||||
"suggestions",
|
||||
"usage",
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
edition = "2024",
|
||||
rustc_env_files = [
|
||||
":cargo_toml_env_vars",
|
||||
],
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-bazel",
|
||||
"crate-name=clap_builder",
|
||||
"manual",
|
||||
"noclippy",
|
||||
"norustfmt",
|
||||
],
|
||||
target_compatible_with = select({
|
||||
"@rules_rust//rust/platform:aarch64-apple-darwin": [],
|
||||
"@rules_rust//rust/platform:aarch64-apple-ios": [],
|
||||
"@rules_rust//rust/platform:aarch64-apple-ios-macabi": [],
|
||||
"@rules_rust//rust/platform:aarch64-apple-ios-sim": [],
|
||||
"@rules_rust//rust/platform:aarch64-linux-android": [],
|
||||
"@rules_rust//rust/platform:aarch64-pc-windows-msvc": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-fuchsia": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-none": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-uefi": [],
|
||||
"@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [],
|
||||
"@rules_rust//rust/platform:arm-unknown-linux-musleabi": [],
|
||||
"@rules_rust//rust/platform:armv7-linux-androideabi": [],
|
||||
"@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [],
|
||||
"@rules_rust//rust/platform:i686-apple-darwin": [],
|
||||
"@rules_rust//rust/platform:i686-linux-android": [],
|
||||
"@rules_rust//rust/platform:i686-pc-windows-msvc": [],
|
||||
"@rules_rust//rust/platform:i686-unknown-freebsd": [],
|
||||
"@rules_rust//rust/platform:i686-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:mips-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [],
|
||||
"@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [],
|
||||
"@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [],
|
||||
"@rules_rust//rust/platform:s390x-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:sparc64-unknown-netbsd": [],
|
||||
"@rules_rust//rust/platform:sparc64-unknown-openbsd": [],
|
||||
"@rules_rust//rust/platform:thumbv6m-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv7em-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv7em-none-eabihf": [],
|
||||
"@rules_rust//rust/platform:thumbv7m-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv8m.main-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [],
|
||||
"@rules_rust//rust/platform:wasm32-unknown-emscripten": [],
|
||||
"@rules_rust//rust/platform:wasm32-unknown-unknown": [],
|
||||
"@rules_rust//rust/platform:wasm32-wasip1": [],
|
||||
"@rules_rust//rust/platform:wasm32-wasip1-threads": [],
|
||||
"@rules_rust//rust/platform:wasm32-wasip2": [],
|
||||
"@rules_rust//rust/platform:x86_64-apple-darwin": [],
|
||||
"@rules_rust//rust/platform:x86_64-apple-ios": [],
|
||||
"@rules_rust//rust/platform:x86_64-apple-ios-macabi": [],
|
||||
"@rules_rust//rust/platform:x86_64-linux-android": [],
|
||||
"@rules_rust//rust/platform:x86_64-pc-windows-msvc": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-freebsd": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-fuchsia": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-none": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-uefi": [],
|
||||
"//conditions:default": ["@platforms//:incompatible"],
|
||||
}),
|
||||
version = "4.6.7",
|
||||
deps = [
|
||||
"//third_party/crates/anstream-1.0.0:anstream",
|
||||
"//third_party/crates/anstyle-1.0.14:anstyle",
|
||||
"//third_party/crates/clap_lex-1.1.1:clap_lex",
|
||||
"//third_party/crates/strsim-0.11.1:strsim",
|
||||
],
|
||||
)
|
||||
537
third_party/crates/clap_builder-4.6.7/Cargo.lock
generated
vendored
Normal file
537
third_party/crates/clap_builder-4.6.7/Cargo.lock
generated
vendored
Normal file
@@ -0,0 +1,537 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.6.7"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"backtrace",
|
||||
"clap_lex",
|
||||
"color-print",
|
||||
"snapbox",
|
||||
"static_assertions",
|
||||
"strsim",
|
||||
"terminal_size",
|
||||
"unic-emoji-char",
|
||||
"unicase",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
|
||||
|
||||
[[package]]
|
||||
name = "color-print"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3aa954171903797d5623e047d9ab69d91b493657917bdfb8c2c80ecaf9cdb6f4"
|
||||
dependencies = [
|
||||
"color-print-proc-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color-print-proc-macro"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692186b5ebe54007e45a59aea47ece9eb4108e141326c304cdc91699a7118a22"
|
||||
dependencies = [
|
||||
"nom",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.32.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.183"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "normalize-line-endings"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.37.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 3.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6505efef05804732ed8a3f2d4f279429eb485bd69d5b0cc6b19cc02005cda16"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "snapbox"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de56eb4784a2c5c1efede55a0f06fbf481bc12b42b355b9525c15db1e3581a8"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"normalize-line-endings",
|
||||
"similar",
|
||||
"snapbox-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "snapbox-macros"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed4a172e483585ebbc7c7f7d1705ca7e3f94f606ed78caa14805673189fd5455"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a207d6d6a2b7fc470b80443726053f18a2481b7e1eee970597051596567987a3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-char-property"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
|
||||
dependencies = [
|
||||
"unic-char-range",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-char-range"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
|
||||
|
||||
[[package]]
|
||||
name = "unic-common"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
|
||||
|
||||
[[package]]
|
||||
name = "unic-emoji-char"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d"
|
||||
dependencies = [
|
||||
"unic-char-property",
|
||||
"unic-char-range",
|
||||
"unic-ucd-version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-ucd-version"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
|
||||
dependencies = [
|
||||
"unic-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
231
third_party/crates/clap_builder-4.6.7/Cargo.toml
vendored
Normal file
231
third_party/crates/clap_builder-4.6.7/Cargo.toml
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2024"
|
||||
rust-version = "1.85"
|
||||
name = "clap_builder"
|
||||
version = "4.6.7"
|
||||
build = false
|
||||
include = [
|
||||
"/build.rs",
|
||||
"/src/**/*",
|
||||
"/Cargo.toml",
|
||||
"/Cargo.lock",
|
||||
"/LICENSE*",
|
||||
"/README.md",
|
||||
"/examples/**/*",
|
||||
]
|
||||
autolib = false
|
||||
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 = [
|
||||
"argument",
|
||||
"cli",
|
||||
"arg",
|
||||
"parser",
|
||||
"parse",
|
||||
]
|
||||
categories = ["command-line-interface"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/clap-rs/clap"
|
||||
resolver = "2"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["unstable-doc"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
[package.metadata.playground]
|
||||
features = ["unstable-doc"]
|
||||
|
||||
[package.metadata.release]
|
||||
shared-version = true
|
||||
dependent-version = "upgrade"
|
||||
tag-name = "v{{version}}"
|
||||
|
||||
[features]
|
||||
cargo = []
|
||||
color = ["dep:anstream"]
|
||||
debug = ["dep:backtrace"]
|
||||
default = [
|
||||
"std",
|
||||
"color",
|
||||
"help",
|
||||
"usage",
|
||||
"error-context",
|
||||
"suggestions",
|
||||
]
|
||||
deprecated = []
|
||||
env = []
|
||||
error-context = []
|
||||
help = []
|
||||
std = ["anstyle/std"]
|
||||
string = []
|
||||
suggestions = [
|
||||
"dep:strsim",
|
||||
"error-context",
|
||||
]
|
||||
unicode = [
|
||||
"dep:unicode-width",
|
||||
"dep:unicase",
|
||||
]
|
||||
unstable-doc = [
|
||||
"cargo",
|
||||
"wrap_help",
|
||||
"env",
|
||||
"unicode",
|
||||
"string",
|
||||
"unstable-ext",
|
||||
]
|
||||
unstable-ext = []
|
||||
unstable-styles = ["color"]
|
||||
unstable-v5 = ["deprecated"]
|
||||
usage = []
|
||||
wrap_help = [
|
||||
"help",
|
||||
"dep:terminal_size",
|
||||
]
|
||||
|
||||
[lib]
|
||||
name = "clap_builder"
|
||||
path = "src/lib.rs"
|
||||
bench = false
|
||||
|
||||
[dependencies.anstream]
|
||||
version = "1.0.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.anstyle]
|
||||
version = "1.0.14"
|
||||
|
||||
[dependencies.backtrace]
|
||||
version = "0.3.76"
|
||||
optional = true
|
||||
|
||||
[dependencies.clap_lex]
|
||||
version = "1.0.0"
|
||||
|
||||
[dependencies.strsim]
|
||||
version = "0.11.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.terminal_size]
|
||||
version = "0.4.4"
|
||||
optional = true
|
||||
|
||||
[dependencies.unicase]
|
||||
version = "2.9.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.unicode-width]
|
||||
version = "0.2.2"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.color-print]
|
||||
version = "0.3.7"
|
||||
|
||||
[dev-dependencies.snapbox]
|
||||
version = "1.2.0"
|
||||
|
||||
[dev-dependencies.static_assertions]
|
||||
version = "1.1.0"
|
||||
|
||||
[dev-dependencies.unic-emoji-char]
|
||||
version = "0.9.0"
|
||||
|
||||
[lints.clippy]
|
||||
assigning_clones = "allow"
|
||||
blocks_in_conditions = "allow"
|
||||
bool_assert_comparison = "allow"
|
||||
branches_sharing_code = "allow"
|
||||
byte_char_slices = "allow"
|
||||
checked_conversions = "warn"
|
||||
collapsible_else_if = "allow"
|
||||
collapsible_match = "allow"
|
||||
collection_is_never_read = "warn"
|
||||
create_dir = "warn"
|
||||
dbg_macro = "warn"
|
||||
debug_assert_with_mut_call = "warn"
|
||||
doc_markdown = "warn"
|
||||
empty_enums = "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 = "warn"
|
||||
float_cmp_const = "warn"
|
||||
fn_params_excessive_bools = "warn"
|
||||
fn_to_numeric_cast_any = "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"
|
||||
mismatching_type_param_order = "warn"
|
||||
multiple_bound_locations = "allow"
|
||||
mutex_integer = "warn"
|
||||
needless_continue = "allow"
|
||||
needless_for_each = "warn"
|
||||
negative_feature_names = "warn"
|
||||
partial_pub_fields = "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"
|
||||
result_large_err = "allow"
|
||||
same_functions_in_if_condition = "warn"
|
||||
self_named_module_files = "warn"
|
||||
semicolon_if_nothing_returned = "warn"
|
||||
str_to_string = "warn"
|
||||
string_add = "warn"
|
||||
string_add_assign = "warn"
|
||||
string_lit_as_bytes = "warn"
|
||||
todo = "warn"
|
||||
trait_duplication_in_bounds = "warn"
|
||||
uninlined_format_args = "warn"
|
||||
unnecessary_safety_comment = "warn"
|
||||
unnecessary_safety_doc = "warn"
|
||||
unseparated_literal_suffix = "warn"
|
||||
use_self = "warn"
|
||||
verbose_file_reads = "warn"
|
||||
zero_sized_map_values = "warn"
|
||||
|
||||
[lints.rust]
|
||||
non_ascii_idents = "warn"
|
||||
trivial_numeric_casts = "warn"
|
||||
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
|
||||
77
third_party/crates/clap_builder-4.6.7/Cargo.toml.orig
generated
vendored
Normal file
77
third_party/crates/clap_builder-4.6.7/Cargo.toml.orig
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
[package]
|
||||
name = "clap_builder"
|
||||
version = "4.6.7"
|
||||
description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
|
||||
categories = ["command-line-interface"]
|
||||
keywords = [
|
||||
"argument",
|
||||
"cli",
|
||||
"arg",
|
||||
"parser",
|
||||
"parse"
|
||||
]
|
||||
repository.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
include.workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["unstable-doc"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
[package.metadata.playground]
|
||||
features = ["unstable-doc"]
|
||||
|
||||
[package.metadata.release]
|
||||
shared-version = true
|
||||
dependent-version = "upgrade"
|
||||
tag-name = "v{{version}}"
|
||||
|
||||
[features]
|
||||
default = ["std", "color", "help", "usage", "error-context", "suggestions"]
|
||||
debug = ["dep:backtrace"] # Enables debug messages
|
||||
unstable-doc = ["cargo", "wrap_help", "env", "unicode", "string", "unstable-ext"] # for docs.rs
|
||||
|
||||
# Used in default
|
||||
std = ["anstyle/std"] # support for no_std in a backwards-compatible way
|
||||
color = ["dep:anstream"]
|
||||
help = []
|
||||
usage = []
|
||||
error-context = []
|
||||
suggestions = ["dep:strsim", "error-context"]
|
||||
|
||||
# Optional
|
||||
deprecated = [] # Guided experience to prepare for next breaking release (at different stages of development, this may become default)
|
||||
cargo = [] # Disable if you're not using Cargo, enables Cargo-env-var-dependent macros
|
||||
wrap_help = ["help", "dep:terminal_size"]
|
||||
env = [] # Use environment variables during arg parsing
|
||||
unicode = ["dep:unicode-width", "dep:unicase"] # Support for unicode characters in arguments and help messages
|
||||
string = [] # Allow runtime generated strings
|
||||
|
||||
# In-work features
|
||||
unstable-v5 = ["deprecated"]
|
||||
unstable-ext = []
|
||||
unstable-styles = ["color"] # deprecated
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
clap_lex = { path = "../clap_lex", version = "1.0.0" }
|
||||
unicase = { version = "2.9.0", optional = true }
|
||||
strsim = { version = "0.11.1", optional = true }
|
||||
anstream = { version = "1.0.0", optional = true }
|
||||
anstyle = "1.0.14"
|
||||
terminal_size = { version = "0.4.4", optional = true }
|
||||
backtrace = { version = "0.3.76", optional = true }
|
||||
unicode-width = { version = "0.2.2", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
static_assertions = "1.1.0"
|
||||
unic-emoji-char = "0.9.0"
|
||||
color-print = "0.3.7"
|
||||
snapbox = { version = "1.2.0" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
202
third_party/crates/clap_builder-4.6.7/LICENSE-APACHE
vendored
Normal file
202
third_party/crates/clap_builder-4.6.7/LICENSE-APACHE
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright Individual contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
19
third_party/crates/clap_builder-4.6.7/LICENSE-MIT
vendored
Normal file
19
third_party/crates/clap_builder-4.6.7/LICENSE-MIT
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) Individual contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
25
third_party/crates/clap_builder-4.6.7/README.md
vendored
Normal file
25
third_party/crates/clap_builder-4.6.7/README.md
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# `clap_builder`
|
||||
|
||||
Builder implementation for clap.
|
||||
|
||||
[docs.rs](https://docs.rs/clap)
|
||||
- [Derive Tutorial](https://docs.rs/clap/latest/clap/_derive/_tutorial/index.html)
|
||||
- [Derive Reference](https://docs.rs/clap/latest/clap/_derive/index.html)
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/license/mit>)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally
|
||||
submitted for inclusion in the work by you, as defined in the Apache-2.0
|
||||
license, shall be dual-licensed as above, without any additional terms or
|
||||
conditions.
|
||||
|
||||
See [CONTRIBUTING](CONTRIBUTING.md) for more details.
|
||||
461
third_party/crates/clap_builder-4.6.7/src/builder/action.rs
vendored
Normal file
461
third_party/crates/clap_builder-4.6.7/src/builder/action.rs
vendored
Normal file
@@ -0,0 +1,461 @@
|
||||
#[cfg(debug_assertions)]
|
||||
use crate::util::AnyValueId;
|
||||
|
||||
use crate::builder::ValueRange;
|
||||
|
||||
/// Behavior of arguments when they are encountered while parsing
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("special-help")
|
||||
/// .short('?')
|
||||
/// .action(clap::ArgAction::Help)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_copy_implementations)] // In the future, we may accept `Box<dyn ...>`
|
||||
pub enum ArgAction {
|
||||
/// When encountered, store the associated value(s) in [`ArgMatches`][crate::ArgMatches]
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** If the argument has previously been seen, it will result in a
|
||||
/// [`ArgumentConflict`][crate::error::ErrorKind::ArgumentConflict] unless
|
||||
/// [`Command::args_override_self(true)`][crate::Command::args_override_self] is set.
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::Set)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd", "--flag", "value"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_many::<String>("flag").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(),
|
||||
/// vec!["value"]
|
||||
/// );
|
||||
/// ```
|
||||
Set,
|
||||
/// When encountered, store the associated value(s) in [`ArgMatches`][crate::ArgMatches]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::Append)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd", "--flag", "value1", "--flag", "value2"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_many::<String>("flag").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(),
|
||||
/// vec!["value1", "value2"]
|
||||
/// );
|
||||
/// ```
|
||||
Append,
|
||||
/// When encountered, act as if `"true"` was encountered on the command-line
|
||||
///
|
||||
/// If no [`default_value`][super::Arg::default_value] is set, it will be `false`.
|
||||
///
|
||||
/// No value is allowed. To optionally accept a value, see
|
||||
/// [`Arg::default_missing_value`][super::Arg::default_missing_value]
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** If the argument has previously been seen, it will result in a
|
||||
/// [`ArgumentConflict`][crate::error::ErrorKind::ArgumentConflict] unless
|
||||
/// [`Command::args_override_self(true)`][crate::Command::args_override_self] is set.
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::SetTrue)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_flag("flag"),
|
||||
/// true
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_flag("flag"),
|
||||
/// false
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// You can use [`TypedValueParser::map`][crate::builder::TypedValueParser::map] to have the
|
||||
/// flag control an application-specific type:
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// # use clap::builder::TypedValueParser as _;
|
||||
/// # use clap::builder::BoolishValueParser;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::SetTrue)
|
||||
/// .value_parser(
|
||||
/// BoolishValueParser::new()
|
||||
/// .map(|b| -> usize {
|
||||
/// if b { 10 } else { 5 }
|
||||
/// })
|
||||
/// )
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_one::<usize>("flag").copied(),
|
||||
/// Some(10)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_one::<usize>("flag").copied(),
|
||||
/// Some(5)
|
||||
/// );
|
||||
/// ```
|
||||
SetTrue,
|
||||
/// When encountered, act as if `"false"` was encountered on the command-line
|
||||
///
|
||||
/// If no [`default_value`][super::Arg::default_value] is set, it will be `true`.
|
||||
///
|
||||
/// No value is allowed. To optionally accept a value, see
|
||||
/// [`Arg::default_missing_value`][super::Arg::default_missing_value]
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** If the argument has previously been seen, it will result in a
|
||||
/// [`ArgumentConflict`][crate::error::ErrorKind::ArgumentConflict] unless
|
||||
/// [`Command::args_override_self(true)`][crate::Command::args_override_self] is set.
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::SetFalse)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_flag("flag"),
|
||||
/// false
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_flag("flag"),
|
||||
/// true
|
||||
/// );
|
||||
/// ```
|
||||
SetFalse,
|
||||
/// When encountered, increment a `u8` counter starting from `0`.
|
||||
///
|
||||
/// If no [`default_value`][super::Arg::default_value] is set, it will be `0`.
|
||||
///
|
||||
/// No value is allowed. To optionally accept a value, see
|
||||
/// [`Arg::default_missing_value`][super::Arg::default_missing_value]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::Count)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_count("flag"),
|
||||
/// 2
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_count("flag"),
|
||||
/// 0
|
||||
/// );
|
||||
/// ```
|
||||
Count,
|
||||
/// When encountered, display [`Command::print_help`][super::Command::print_help]
|
||||
///
|
||||
/// Depending on the flag, [`Command::print_long_help`][super::Command::print_long_help] may be shown
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("special-help")
|
||||
/// .short('?')
|
||||
/// .action(clap::ArgAction::Help)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
Help,
|
||||
/// When encountered, display [`Command::print_help`][super::Command::print_help]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("special-help")
|
||||
/// .short('?')
|
||||
/// .action(clap::ArgAction::HelpShort)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
HelpShort,
|
||||
/// When encountered, display [`Command::print_long_help`][super::Command::print_long_help]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("special-help")
|
||||
/// .short('?')
|
||||
/// .action(clap::ArgAction::HelpLong)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
HelpLong,
|
||||
/// When encountered, display [`Command::version`][super::Command::version]
|
||||
///
|
||||
/// Depending on the flag, [`Command::long_version`][super::Command::long_version] may be shown
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .version("1.0.0")
|
||||
/// .arg(
|
||||
/// Arg::new("special-version")
|
||||
/// .long("special-version")
|
||||
/// .action(clap::ArgAction::Version)
|
||||
/// );
|
||||
///
|
||||
/// // Existing version still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "--version"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayVersion);
|
||||
///
|
||||
/// // New version available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "--special-version"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayVersion);
|
||||
/// ```
|
||||
Version,
|
||||
}
|
||||
|
||||
impl ArgAction {
|
||||
/// Returns whether this action accepts values on the command-line
|
||||
///
|
||||
/// [`default_values`][super::Arg::default_values] and [`env`][super::Arg::env] may still be
|
||||
/// processed.
|
||||
pub fn takes_values(&self) -> bool {
|
||||
match self {
|
||||
Self::Set => true,
|
||||
Self::Append => true,
|
||||
Self::SetTrue => false,
|
||||
Self::SetFalse => false,
|
||||
Self::Count => false,
|
||||
Self::Help => false,
|
||||
Self::HelpShort => false,
|
||||
Self::HelpLong => false,
|
||||
Self::Version => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) fn max_num_args(&self) -> ValueRange {
|
||||
match self {
|
||||
Self::Set => ValueRange::FULL,
|
||||
Self::Append => ValueRange::FULL,
|
||||
Self::SetTrue => ValueRange::OPTIONAL,
|
||||
Self::SetFalse => ValueRange::OPTIONAL,
|
||||
Self::Count => ValueRange::EMPTY,
|
||||
Self::Help => ValueRange::EMPTY,
|
||||
Self::HelpShort => ValueRange::EMPTY,
|
||||
Self::HelpLong => ValueRange::EMPTY,
|
||||
Self::Version => ValueRange::EMPTY,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default_num_args(&self) -> ValueRange {
|
||||
match self {
|
||||
Self::Set => ValueRange::SINGLE,
|
||||
Self::Append => ValueRange::SINGLE,
|
||||
Self::SetTrue => ValueRange::EMPTY,
|
||||
Self::SetFalse => ValueRange::EMPTY,
|
||||
Self::Count => ValueRange::EMPTY,
|
||||
Self::Help => ValueRange::EMPTY,
|
||||
Self::HelpShort => ValueRange::EMPTY,
|
||||
Self::HelpLong => ValueRange::EMPTY,
|
||||
Self::Version => ValueRange::EMPTY,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default_value(&self) -> Option<&'static std::ffi::OsStr> {
|
||||
match self {
|
||||
Self::Set => None,
|
||||
Self::Append => None,
|
||||
Self::SetTrue => Some(std::ffi::OsStr::new("false")),
|
||||
Self::SetFalse => Some(std::ffi::OsStr::new("true")),
|
||||
Self::Count => Some(std::ffi::OsStr::new("0")),
|
||||
Self::Help => None,
|
||||
Self::HelpShort => None,
|
||||
Self::HelpLong => None,
|
||||
Self::Version => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default_missing_value(&self) -> Option<&'static std::ffi::OsStr> {
|
||||
match self {
|
||||
Self::Set => None,
|
||||
Self::Append => None,
|
||||
Self::SetTrue => Some(std::ffi::OsStr::new("true")),
|
||||
Self::SetFalse => Some(std::ffi::OsStr::new("false")),
|
||||
Self::Count => None,
|
||||
Self::Help => None,
|
||||
Self::HelpShort => None,
|
||||
Self::HelpLong => None,
|
||||
Self::Version => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default_value_parser(&self) -> Option<super::ValueParser> {
|
||||
match self {
|
||||
Self::Set => None,
|
||||
Self::Append => None,
|
||||
Self::SetTrue => Some(super::ValueParser::bool()),
|
||||
Self::SetFalse => Some(super::ValueParser::bool()),
|
||||
Self::Count => Some(crate::value_parser!(u8).into()),
|
||||
Self::Help => None,
|
||||
Self::HelpShort => None,
|
||||
Self::HelpLong => None,
|
||||
Self::Version => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) fn value_type_id(&self) -> Option<AnyValueId> {
|
||||
match self {
|
||||
Self::Set => None,
|
||||
Self::Append => None,
|
||||
Self::SetTrue => None,
|
||||
Self::SetFalse => None,
|
||||
Self::Count => Some(AnyValueId::of::<CountType>()),
|
||||
Self::Help => None,
|
||||
Self::HelpShort => None,
|
||||
Self::HelpLong => None,
|
||||
Self::Version => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type CountType = u8;
|
||||
88
third_party/crates/clap_builder-4.6.7/src/builder/app_settings.rs
vendored
Normal file
88
third_party/crates/clap_builder-4.6.7/src/builder/app_settings.rs
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
#[allow(unused)]
|
||||
use crate::Arg;
|
||||
#[allow(unused)]
|
||||
use crate::Command;
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct AppFlags(u32);
|
||||
|
||||
impl AppFlags {
|
||||
pub(crate) fn set(&mut self, setting: AppSettings) {
|
||||
self.0 |= setting.bit();
|
||||
}
|
||||
|
||||
pub(crate) fn unset(&mut self, setting: AppSettings) {
|
||||
self.0 &= !setting.bit();
|
||||
}
|
||||
|
||||
pub(crate) fn is_set(&self, setting: AppSettings) -> bool {
|
||||
self.0 & setting.bit() != 0
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, other: Self) {
|
||||
self.0 |= other.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for AppFlags {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(mut self, rhs: Self) -> Self::Output {
|
||||
self.insert(rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Application level settings, which affect how [`Command`] operates
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** When these settings are used, they apply only to current command, and are *not*
|
||||
/// propagated down or up through child or parent subcommands
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// [`Command`]: crate::Command
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub(crate) enum AppSettings {
|
||||
IgnoreErrors,
|
||||
AllowHyphenValues,
|
||||
AllowNegativeNumbers,
|
||||
AllArgsOverrideSelf,
|
||||
AllowMissingPositional,
|
||||
TrailingVarArg,
|
||||
DontDelimitTrailingValues,
|
||||
InferLongArgs,
|
||||
InferSubcommands,
|
||||
SubcommandRequired,
|
||||
AllowExternalSubcommands,
|
||||
Multicall,
|
||||
SubcommandsNegateReqs,
|
||||
ArgsNegateSubcommands,
|
||||
SubcommandPrecedenceOverArg,
|
||||
FlattenHelp,
|
||||
ArgRequiredElseHelp,
|
||||
NextLineHelp,
|
||||
DisableColoredHelp,
|
||||
DisableHelpFlag,
|
||||
DisableHelpSubcommand,
|
||||
DisableVersionFlag,
|
||||
PropagateVersion,
|
||||
Hidden,
|
||||
HidePossibleValues,
|
||||
HelpExpected,
|
||||
NoBinaryName,
|
||||
#[allow(dead_code)]
|
||||
ColorAuto,
|
||||
ColorAlways,
|
||||
ColorNever,
|
||||
Built,
|
||||
BinNameBuilt,
|
||||
}
|
||||
|
||||
impl AppSettings {
|
||||
fn bit(self) -> u32 {
|
||||
1 << (self as u8)
|
||||
}
|
||||
}
|
||||
5208
third_party/crates/clap_builder-4.6.7/src/builder/arg.rs
vendored
Normal file
5208
third_party/crates/clap_builder-4.6.7/src/builder/arg.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
615
third_party/crates/clap_builder-4.6.7/src/builder/arg_group.rs
vendored
Normal file
615
third_party/crates/clap_builder-4.6.7/src/builder/arg_group.rs
vendored
Normal file
@@ -0,0 +1,615 @@
|
||||
// Internal
|
||||
use crate::builder::IntoResettable;
|
||||
use crate::util::Id;
|
||||
|
||||
/// Specifies a logical group of [arguments]
|
||||
///
|
||||
/// You can use this for
|
||||
/// - applying validation to an entire group, like [`ArgGroup::multiple`]
|
||||
/// - validate relationships between an argument and a group, like [conflicts] or [requirements]
|
||||
/// - check which argument in a group was specified on the command-line
|
||||
///
|
||||
/// For visually grouping arguments in help, see instead
|
||||
/// [`Arg::help_heading`][crate::Arg::help_heading].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The following example demonstrates using an `ArgGroup` to ensure that one, and only one, of
|
||||
/// the arguments from the specified group is present at runtime.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, arg, ArgGroup, error::ErrorKind};
|
||||
/// let result = Command::new("cmd")
|
||||
/// .arg(arg!(--"set-ver" <ver> "set the version manually"))
|
||||
/// .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))
|
||||
/// .try_get_matches_from(vec!["cmd", "--major", "--patch"]);
|
||||
/// // Because we used two args in the group it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
///
|
||||
/// This next example shows a passing parse of the same scenario
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, arg, ArgGroup, Id};
|
||||
/// let result = Command::new("cmd")
|
||||
/// .arg(arg!(--"set-ver" <ver> "set the version manually"))
|
||||
/// .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))
|
||||
/// .try_get_matches_from(vec!["cmd", "--major"]);
|
||||
/// assert!(result.is_ok());
|
||||
/// let matches = result.unwrap();
|
||||
/// // We may not know which of the args was used, so we can test for the group...
|
||||
/// assert!(matches.contains_id("vers"));
|
||||
/// // We can also ask the group which arg was used
|
||||
/// assert_eq!(matches
|
||||
/// .get_one::<Id>("vers")
|
||||
/// .expect("`vers` is required")
|
||||
/// .as_str(),
|
||||
/// "major"
|
||||
/// );
|
||||
/// // we could also alternatively check each arg individually (not shown here)
|
||||
/// ```
|
||||
/// [arguments]: crate::Arg
|
||||
/// [conflicts]: crate::Arg::conflicts_with()
|
||||
/// [requirements]: crate::Arg::requires()
|
||||
#[derive(Default, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ArgGroup {
|
||||
pub(crate) id: Id,
|
||||
pub(crate) args: Vec<Id>,
|
||||
pub(crate) required: bool,
|
||||
pub(crate) requires: Vec<Id>,
|
||||
pub(crate) conflicts: Vec<Id>,
|
||||
pub(crate) multiple: bool,
|
||||
}
|
||||
|
||||
/// # Builder
|
||||
impl ArgGroup {
|
||||
/// Create a `ArgGroup` using a unique name.
|
||||
///
|
||||
/// The name will be used to get values from the group or refer to the group inside of conflict
|
||||
/// and requirement rules.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ArgGroup};
|
||||
/// ArgGroup::new("config")
|
||||
/// # ;
|
||||
/// ```
|
||||
pub fn new(id: impl Into<Id>) -> Self {
|
||||
Self::default().id(id)
|
||||
}
|
||||
|
||||
/// Sets the group name.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ArgGroup};
|
||||
/// ArgGroup::default().id("config")
|
||||
/// # ;
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn id(mut self, id: impl Into<Id>) -> Self {
|
||||
self.id = id.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds an [argument] to this group by name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, ArgAction};
|
||||
/// let m = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .arg("flag")
|
||||
/// .arg("color"))
|
||||
/// .get_matches_from(vec!["myprog", "-f"]);
|
||||
/// // maybe we don't know which of the two flags was used...
|
||||
/// assert!(m.contains_id("req_flags"));
|
||||
/// // but we can also check individually if needed
|
||||
/// assert!(m.contains_id("flag"));
|
||||
/// ```
|
||||
/// [argument]: crate::Arg
|
||||
#[must_use]
|
||||
pub fn arg(mut self, arg_id: impl IntoResettable<Id>) -> Self {
|
||||
if let Some(arg_id) = arg_id.into_resettable().into_option() {
|
||||
self.args.push(arg_id);
|
||||
} else {
|
||||
self.args.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds multiple [arguments] to this group by name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, ArgAction};
|
||||
/// let m = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"]))
|
||||
/// .get_matches_from(vec!["myprog", "-f"]);
|
||||
/// // maybe we don't know which of the two flags was used...
|
||||
/// assert!(m.contains_id("req_flags"));
|
||||
/// // but we can also check individually if needed
|
||||
/// assert!(m.contains_id("flag"));
|
||||
/// ```
|
||||
/// [arguments]: crate::Arg
|
||||
#[must_use]
|
||||
pub fn args(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self {
|
||||
for n in ns {
|
||||
self = self.arg(n);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Getters for all args. It will return a vector of `Id`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{ArgGroup};
|
||||
/// let args: Vec<&str> = vec!["a1".into(), "a4".into()];
|
||||
/// let grp = ArgGroup::new("program").args(&args);
|
||||
///
|
||||
/// for (pos, arg) in grp.get_args().enumerate() {
|
||||
/// assert_eq!(*arg, args[pos]);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_args(&self) -> impl Iterator<Item = &Id> {
|
||||
self.args.iter()
|
||||
}
|
||||
|
||||
/// Allows more than one of the [`Arg`]s in this group to be used. (Default: `false`)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Notice in this example we use *both* the `-f` and `-c` flags which are both part of the
|
||||
/// group
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, ArgAction};
|
||||
/// let m = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .multiple(true))
|
||||
/// .get_matches_from(vec!["myprog", "-f", "-c"]);
|
||||
/// // 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
|
||||
/// an error if more than one of the args in the group was used.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"]))
|
||||
/// .try_get_matches_from(vec!["myprog", "-f", "-c"]);
|
||||
/// // Because we used both args in the group it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
///
|
||||
/// [`Arg`]: crate::Arg
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn multiple(mut self, yes: bool) -> Self {
|
||||
self.multiple = yes;
|
||||
self
|
||||
}
|
||||
|
||||
/// Return true if the group allows more than one of the arguments
|
||||
/// in this group to be used. (Default: `false`)
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{ArgGroup};
|
||||
/// let mut group = ArgGroup::new("myprog")
|
||||
/// .args(["f", "c"])
|
||||
/// .multiple(true);
|
||||
///
|
||||
/// assert!(group.is_multiple());
|
||||
/// ```
|
||||
pub fn is_multiple(&mut self) -> bool {
|
||||
self.multiple
|
||||
}
|
||||
|
||||
/// Require an argument from the group to be present when parsing.
|
||||
///
|
||||
/// This is unless conflicting with another argument. A required group will be displayed in
|
||||
/// the usage string of the application in the format `<arg|arg2|arg3>`.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** This setting only applies to the current [`Command`] / [`Subcommand`]s, and not
|
||||
/// globally.
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with
|
||||
/// `ArgGroup::required(true)` states, "One and *only one* arg must be used from this group.
|
||||
/// Use of more than one arg is an error." Vice setting `ArgGroup::multiple(true)` which
|
||||
/// states, '*At least* one arg from this group must be used. Using multiple is OK."
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .required(true))
|
||||
/// .try_get_matches_from(vec!["myprog"]);
|
||||
/// // Because we didn't use any of the args in the group, it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
|
||||
/// ```
|
||||
///
|
||||
/// [`Subcommand`]: crate::Subcommand
|
||||
/// [`ArgGroup::multiple`]: ArgGroup::multiple()
|
||||
/// [`Command`]: crate::Command
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn required(mut self, yes: bool) -> Self {
|
||||
self.required = yes;
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify an argument or group that must be present when this group is.
|
||||
///
|
||||
/// This is not to be confused with a [required group]. Requirement rules function just like
|
||||
/// [argument requirement rules], you can name other arguments or groups that must be present
|
||||
/// when any one of the arguments from this group is used.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** The name provided may be an argument or group name
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .short('d')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .requires("debug"))
|
||||
/// .try_get_matches_from(vec!["myprog", "-c"]);
|
||||
/// // because we used an arg from the group, and the group requires "-d" to be used, it's an
|
||||
/// // error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
|
||||
/// ```
|
||||
/// [required group]: ArgGroup::required()
|
||||
/// [argument requirement rules]: crate::Arg::requires()
|
||||
#[must_use]
|
||||
pub fn requires(mut self, id: impl IntoResettable<Id>) -> Self {
|
||||
if let Some(id) = id.into_resettable().into_option() {
|
||||
self.requires.push(id);
|
||||
} else {
|
||||
self.requires.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify arguments or groups that must be present when this group is.
|
||||
///
|
||||
/// This is not to be confused with a [required group]. Requirement rules function just like
|
||||
/// [argument requirement rules], you can name other arguments or groups that must be present
|
||||
/// when one of the arguments from this group is used.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** The names provided may be an argument or group name
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .short('d')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("verb")
|
||||
/// .short('v')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .requires_all(["debug", "verb"]))
|
||||
/// .try_get_matches_from(vec!["myprog", "-c", "-d"]);
|
||||
/// // because we used an arg from the group, and the group requires "-d" and "-v" to be used,
|
||||
/// // yet we only used "-d" it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
|
||||
/// ```
|
||||
/// [required group]: ArgGroup::required()
|
||||
/// [argument requirement rules]: crate::Arg::requires_ifs()
|
||||
#[must_use]
|
||||
pub fn requires_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self {
|
||||
for n in ns {
|
||||
self = self.requires(n);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify an argument or group that must **not** be present when this group is.
|
||||
///
|
||||
/// Exclusion (aka conflict) rules function just like [argument exclusion rules], you can name
|
||||
/// other arguments or groups that must *not* be present when one of the arguments from this
|
||||
/// group are used.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** The name provided may be an argument, or group name
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .short('d')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .conflicts_with("debug"))
|
||||
/// .try_get_matches_from(vec!["myprog", "-c", "-d"]);
|
||||
/// // because we used an arg from the group, and the group conflicts with "-d", it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
/// [argument exclusion rules]: crate::Arg::conflicts_with()
|
||||
#[must_use]
|
||||
pub fn conflicts_with(mut self, id: impl IntoResettable<Id>) -> Self {
|
||||
if let Some(id) = id.into_resettable().into_option() {
|
||||
self.conflicts.push(id);
|
||||
} else {
|
||||
self.conflicts.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify arguments or groups that must **not** be present when this group is.
|
||||
///
|
||||
/// Exclusion rules function just like [argument exclusion rules], you can name other arguments
|
||||
/// or groups that must *not* be present when one of the arguments from this group are used.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** The names provided may be an argument, or group name
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .short('d')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("verb")
|
||||
/// .short('v')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .conflicts_with_all(["debug", "verb"]))
|
||||
/// .try_get_matches_from(vec!["myprog", "-c", "-v"]);
|
||||
/// // because we used an arg from the group, and the group conflicts with either "-v" or "-d"
|
||||
/// // it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
///
|
||||
/// [argument exclusion rules]: crate::Arg::conflicts_with_all()
|
||||
#[must_use]
|
||||
pub fn conflicts_with_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self {
|
||||
for n in ns {
|
||||
self = self.conflicts_with(n);
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// # Reflection
|
||||
impl ArgGroup {
|
||||
/// Get the name of the group
|
||||
#[inline]
|
||||
pub fn get_id(&self) -> &Id {
|
||||
&self.id
|
||||
}
|
||||
|
||||
/// Reports whether [`ArgGroup::required`] is set
|
||||
#[inline]
|
||||
pub fn is_required_set(&self) -> bool {
|
||||
self.required
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Self> for ArgGroup {
|
||||
fn from(g: &Self) -> Self {
|
||||
g.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn groups() {
|
||||
let g = ArgGroup::new("test")
|
||||
.arg("a1")
|
||||
.arg("a4")
|
||||
.args(["a2", "a3"])
|
||||
.required(true)
|
||||
.conflicts_with("c1")
|
||||
.conflicts_with_all(["c2", "c3"])
|
||||
.conflicts_with("c4")
|
||||
.requires("r1")
|
||||
.requires_all(["r2", "r3"])
|
||||
.requires("r4");
|
||||
|
||||
let args: Vec<Id> = vec!["a1".into(), "a4".into(), "a2".into(), "a3".into()];
|
||||
let reqs: Vec<Id> = vec!["r1".into(), "r2".into(), "r3".into(), "r4".into()];
|
||||
let confs: Vec<Id> = vec!["c1".into(), "c2".into(), "c3".into(), "c4".into()];
|
||||
|
||||
assert_eq!(g.args, args);
|
||||
assert_eq!(g.requires, reqs);
|
||||
assert_eq!(g.conflicts, confs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from() {
|
||||
let g = ArgGroup::new("test")
|
||||
.arg("a1")
|
||||
.arg("a4")
|
||||
.args(["a2", "a3"])
|
||||
.required(true)
|
||||
.conflicts_with("c1")
|
||||
.conflicts_with_all(["c2", "c3"])
|
||||
.conflicts_with("c4")
|
||||
.requires("r1")
|
||||
.requires_all(["r2", "r3"])
|
||||
.requires("r4");
|
||||
|
||||
let args: Vec<Id> = vec!["a1".into(), "a4".into(), "a2".into(), "a3".into()];
|
||||
let reqs: Vec<Id> = vec!["r1".into(), "r2".into(), "r3".into(), "r4".into()];
|
||||
let confs: Vec<Id> = vec!["c1".into(), "c2".into(), "c3".into(), "c4".into()];
|
||||
|
||||
let g2 = ArgGroup::from(&g);
|
||||
assert_eq!(g2.args, args);
|
||||
assert_eq!(g2.requires, reqs);
|
||||
assert_eq!(g2.conflicts, confs);
|
||||
}
|
||||
|
||||
// This test will *fail to compile* if ArgGroup is not Send + Sync
|
||||
#[test]
|
||||
fn arg_group_send_sync() {
|
||||
fn foo<T: Send + Sync>(_: T) {}
|
||||
foo(ArgGroup::new("test"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arg_group_expose_is_multiple_helper() {
|
||||
let args: Vec<Id> = vec!["a1".into(), "a4".into()];
|
||||
|
||||
let mut grp_multiple = ArgGroup::new("test_multiple").args(&args).multiple(true);
|
||||
assert!(grp_multiple.is_multiple());
|
||||
|
||||
let mut grp_not_multiple = ArgGroup::new("test_multiple").args(&args).multiple(false);
|
||||
assert!(!grp_not_multiple.is_multiple());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arg_group_expose_get_args_helper() {
|
||||
let args: Vec<Id> = vec!["a1".into(), "a4".into()];
|
||||
let grp = ArgGroup::new("program").args(&args);
|
||||
|
||||
for (pos, arg) in grp.get_args().enumerate() {
|
||||
assert_eq!(*arg, args[pos]);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
third_party/crates/clap_builder-4.6.7/src/builder/arg_predicate.rs
vendored
Normal file
19
third_party/crates/clap_builder-4.6.7/src/builder/arg_predicate.rs
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
use crate::builder::OsStr;
|
||||
|
||||
/// Operations to perform on argument values
|
||||
///
|
||||
/// These do not apply to [`ValueSource::DefaultValue`][crate::parser::ValueSource::DefaultValue]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "unstable-v5", non_exhaustive)]
|
||||
pub enum ArgPredicate {
|
||||
/// Is the argument present?
|
||||
IsPresent,
|
||||
/// Does the argument match the specified value?
|
||||
Equals(OsStr),
|
||||
}
|
||||
|
||||
impl<S: Into<OsStr>> From<S> for ArgPredicate {
|
||||
fn from(other: S) -> Self {
|
||||
Self::Equals(other.into())
|
||||
}
|
||||
}
|
||||
91
third_party/crates/clap_builder-4.6.7/src/builder/arg_settings.rs
vendored
Normal file
91
third_party/crates/clap_builder-4.6.7/src/builder/arg_settings.rs
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
#[allow(unused)]
|
||||
use crate::Arg;
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct ArgFlags(u32);
|
||||
|
||||
impl ArgFlags {
|
||||
pub(crate) fn set(&mut self, setting: ArgSettings) {
|
||||
self.0 |= setting.bit();
|
||||
}
|
||||
|
||||
pub(crate) fn unset(&mut self, setting: ArgSettings) {
|
||||
self.0 &= !setting.bit();
|
||||
}
|
||||
|
||||
pub(crate) fn is_set(&self, setting: ArgSettings) -> bool {
|
||||
self.0 & setting.bit() != 0
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, other: Self) {
|
||||
self.0 |= other.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for ArgFlags {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(mut self, rhs: Self) -> Self::Output {
|
||||
self.insert(rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Various settings that apply to arguments and may be set, unset, and checked via getter/setter
|
||||
/// methods [`Arg::setting`], [`Arg::unset_setting`], and [`Arg::is_set`]. This is what the
|
||||
/// [`Arg`] methods which accept a `bool` use internally.
|
||||
///
|
||||
/// [`Arg`]: crate::Arg
|
||||
/// [`Arg::setting`]: crate::Arg::setting()
|
||||
/// [`Arg::unset_setting`]: crate::Arg::unset_setting()
|
||||
/// [`Arg::is_set`]: crate::Arg::is_set()
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub(crate) enum ArgSettings {
|
||||
Required,
|
||||
Global,
|
||||
Hidden,
|
||||
NextLineHelp,
|
||||
HidePossibleValues,
|
||||
AllowHyphenValues,
|
||||
AllowNegativeNumbers,
|
||||
RequireEquals,
|
||||
Last,
|
||||
TrailingVarArg,
|
||||
HideDefaultValue,
|
||||
IgnoreCase,
|
||||
#[cfg(feature = "env")]
|
||||
HideEnv,
|
||||
#[cfg(feature = "env")]
|
||||
HideEnvValues,
|
||||
HiddenShortHelp,
|
||||
HiddenLongHelp,
|
||||
Exclusive,
|
||||
}
|
||||
|
||||
impl ArgSettings {
|
||||
fn bit(self) -> u32 {
|
||||
1 << (self as u8)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::Arg;
|
||||
|
||||
#[test]
|
||||
fn setting() {
|
||||
let m = Arg::new("setting").setting(ArgSettings::Required);
|
||||
assert!(m.is_required_set());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unset_setting() {
|
||||
let m = Arg::new("unset_setting").setting(ArgSettings::Required);
|
||||
assert!(m.is_required_set());
|
||||
|
||||
let m = m.unset_setting(ArgSettings::Required);
|
||||
assert!(!m.is_required_set(), "{m:#?}");
|
||||
}
|
||||
}
|
||||
5296
third_party/crates/clap_builder-4.6.7/src/builder/command.rs
vendored
Normal file
5296
third_party/crates/clap_builder-4.6.7/src/builder/command.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
832
third_party/crates/clap_builder-4.6.7/src/builder/debug_asserts.rs
vendored
Normal file
832
third_party/crates/clap_builder-4.6.7/src/builder/debug_asserts.rs
vendored
Normal file
@@ -0,0 +1,832 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::ArgAction;
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
use crate::builder::ValueRange;
|
||||
use crate::mkeymap::KeyType;
|
||||
use crate::util::FlatSet;
|
||||
use crate::util::Id;
|
||||
use crate::{Arg, Command, ValueHint};
|
||||
|
||||
pub(crate) fn assert_app(cmd: &Command) {
|
||||
debug!("Command::_debug_asserts");
|
||||
|
||||
let mut short_flags = vec![];
|
||||
let mut long_flags = vec![];
|
||||
|
||||
// Invalid version flag settings
|
||||
if cmd.get_version().is_none() && cmd.get_long_version().is_none() {
|
||||
// PropagateVersion is meaningless if there is no version
|
||||
assert!(
|
||||
!cmd.is_propagate_version_set(),
|
||||
"Command {}: No version information via Command::version or Command::long_version to propagate",
|
||||
cmd.get_name(),
|
||||
);
|
||||
|
||||
// Used `Command::mut_arg("version", ..) but did not provide any version information to display
|
||||
let version_needed = cmd
|
||||
.get_arguments()
|
||||
.filter(|x| matches!(x.get_action(), ArgAction::Version))
|
||||
.map(|x| x.get_id())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(
|
||||
version_needed,
|
||||
Vec::<&str>::new(),
|
||||
"Command {}: `ArgAction::Version` used without providing Command::version or Command::long_version",
|
||||
cmd.get_name()
|
||||
);
|
||||
}
|
||||
|
||||
for sc in cmd.get_subcommands() {
|
||||
if let Some(s) = sc.get_short_flag().as_ref() {
|
||||
short_flags.push(Flag::Command(format!("-{s}"), sc.get_name()));
|
||||
}
|
||||
|
||||
for short_alias in sc.get_all_short_flag_aliases() {
|
||||
short_flags.push(Flag::Command(format!("-{short_alias}"), sc.get_name()));
|
||||
}
|
||||
|
||||
if let Some(l) = sc.get_long_flag().as_ref() {
|
||||
assert!(
|
||||
!l.starts_with('-'),
|
||||
"Command {}: long_flag {:?} must not start with a `-`, that will be handled by the parser",
|
||||
sc.get_name(),
|
||||
l
|
||||
);
|
||||
long_flags.push(Flag::Command(format!("--{l}"), sc.get_name()));
|
||||
}
|
||||
|
||||
for long_alias in sc.get_all_long_flag_aliases() {
|
||||
long_flags.push(Flag::Command(format!("--{long_alias}"), sc.get_name()));
|
||||
}
|
||||
}
|
||||
|
||||
for arg in cmd.get_arguments() {
|
||||
assert_arg(arg);
|
||||
|
||||
assert!(
|
||||
!cmd.is_multicall_set(),
|
||||
"Command {}: Arguments like {} cannot be set on a multicall command",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
if let Some(s) = arg.get_short() {
|
||||
short_flags.push(Flag::Arg(format!("-{s}"), arg.get_id().as_str()));
|
||||
}
|
||||
|
||||
for (short_alias, _) in &arg.short_aliases {
|
||||
short_flags.push(Flag::Arg(format!("-{short_alias}"), arg.get_id().as_str()));
|
||||
}
|
||||
|
||||
if let Some(l) = arg.get_long() {
|
||||
assert!(
|
||||
!l.starts_with('-'),
|
||||
"Argument {}: long {:?} must not start with a `-`, that will be handled by the parser",
|
||||
arg.get_id(),
|
||||
l
|
||||
);
|
||||
long_flags.push(Flag::Arg(format!("--{l}"), arg.get_id().as_str()));
|
||||
}
|
||||
|
||||
for (long_alias, _) in &arg.aliases {
|
||||
long_flags.push(Flag::Arg(format!("--{long_alias}"), arg.get_id().as_str()));
|
||||
}
|
||||
|
||||
// Name conflicts
|
||||
if let Some((first, second)) = cmd.two_args_of(|x| x.get_id() == arg.get_id()) {
|
||||
panic!(
|
||||
"Command {}: Argument names must be unique, but '{}' is in use by more than one argument or group{}",
|
||||
cmd.get_name(),
|
||||
arg.get_id(),
|
||||
duplicate_tip(cmd, first, second),
|
||||
);
|
||||
}
|
||||
|
||||
// Long conflicts
|
||||
if let Some(l) = arg.get_long() {
|
||||
if let Some((first, second)) = cmd.two_args_of(|x| x.get_long() == Some(l)) {
|
||||
panic!(
|
||||
"Command {}: Long option names must be unique for each argument, \
|
||||
but '--{}' is in use by both '{}' and '{}'{}",
|
||||
cmd.get_name(),
|
||||
l,
|
||||
first.get_id(),
|
||||
second.get_id(),
|
||||
duplicate_tip(cmd, first, second)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Short conflicts
|
||||
if let Some(s) = arg.get_short() {
|
||||
if let Some((first, second)) = cmd.two_args_of(|x| x.get_short() == Some(s)) {
|
||||
panic!(
|
||||
"Command {}: Short option names must be unique for each argument, \
|
||||
but '-{}' is in use by both '{}' and '{}'{}",
|
||||
cmd.get_name(),
|
||||
s,
|
||||
first.get_id(),
|
||||
second.get_id(),
|
||||
duplicate_tip(cmd, first, second),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Index conflicts
|
||||
if let Some(idx) = arg.index {
|
||||
if let Some((first, second)) =
|
||||
cmd.two_args_of(|x| x.is_positional() && x.get_index() == Some(idx))
|
||||
{
|
||||
panic!(
|
||||
"Command {}: Argument '{}' has the same index as '{}' \
|
||||
and they are both positional arguments\n\n\t \
|
||||
Use `Arg::num_args(1..)` to allow one \
|
||||
positional argument to take multiple values",
|
||||
cmd.get_name(),
|
||||
first.get_id(),
|
||||
second.get_id()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// requires, r_if, r_unless
|
||||
for (_predicate, req_id) in &arg.requires {
|
||||
assert!(
|
||||
&arg.id != req_id,
|
||||
"Argument {} cannot require itself",
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
assert!(
|
||||
cmd.id_exists(req_id),
|
||||
"Command {}: Argument or group '{}' specified in 'requires*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req_id,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
for req in &arg.r_ifs {
|
||||
assert!(
|
||||
!arg.is_required_set(),
|
||||
"Argument {}: `required` conflicts with `required_if_eq*`",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
cmd.id_exists(&req.0),
|
||||
"Command {}: Argument or group '{}' specified in 'required_if_eq*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req.0,
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
|
||||
for req in &arg.r_ifs_all {
|
||||
assert!(
|
||||
!arg.is_required_set(),
|
||||
"Argument {}: `required` conflicts with `required_if_eq_all`",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
cmd.id_exists(&req.0),
|
||||
"Command {}: Argument or group '{}' specified in 'required_if_eq_all' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req.0,
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
|
||||
for req in &arg.r_unless {
|
||||
assert!(
|
||||
!arg.is_required_set(),
|
||||
"Argument {}: `required` conflicts with `required_unless*`",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
cmd.id_exists(req),
|
||||
"Command {}: Argument or group '{}' specified in 'required_unless*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
for req in &arg.r_unless_all {
|
||||
assert!(
|
||||
!arg.is_required_set(),
|
||||
"Argument {}: `required` conflicts with `required_unless*`",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
cmd.id_exists(req),
|
||||
"Command {}: Argument or group '{}' specified in 'required_unless*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
// conflicts
|
||||
for req in &arg.conflicts {
|
||||
assert!(
|
||||
cmd.id_exists(req),
|
||||
"Command {}: Argument or group '{}' specified in 'conflicts_with*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
// overrides
|
||||
for req in &arg.overrides {
|
||||
assert!(
|
||||
cmd.id_exists(req),
|
||||
"Command {}: Argument or group '{}' specified in 'overrides_with*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
if arg.is_last_set() {
|
||||
assert!(
|
||||
arg.get_long().is_none(),
|
||||
"Command {}: Flags or Options cannot have last(true) set. '{}' has both a long and last(true) set.",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
arg.get_short().is_none(),
|
||||
"Command {}: Flags or Options cannot have last(true) set. '{}' has both a short and last(true) set.",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
|
||||
assert!(
|
||||
!(arg.is_required_set() && arg.is_global_set()),
|
||||
"Command {}: Global arguments cannot be required.\n\n\t'{}' is marked as both global and required",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
if arg.get_value_hint() == ValueHint::CommandWithArguments {
|
||||
assert!(
|
||||
arg.is_positional(),
|
||||
"Command {}: Argument '{}' has hint CommandWithArguments and must be positional.",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
assert!(
|
||||
arg.is_trailing_var_arg_set() || arg.is_last_set(),
|
||||
"Command {}: Positional argument '{}' has hint CommandWithArguments, so Command must have `trailing_var_arg(true)` or `last(true)` set.",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for group in cmd.get_groups() {
|
||||
// Name conflicts
|
||||
assert!(
|
||||
cmd.get_groups().filter(|x| x.id == group.id).count() < 2,
|
||||
"Command {}: Argument group name must be unique\n\n\t'{}' is already in use",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
);
|
||||
|
||||
// Groups should not have naming conflicts with Args
|
||||
assert!(
|
||||
!cmd.get_arguments().any(|x| x.get_id() == group.get_id()),
|
||||
"Command {}: Argument group name '{}' must not conflict with argument name",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
);
|
||||
|
||||
for arg in &group.args {
|
||||
// Args listed inside groups should exist
|
||||
assert!(
|
||||
cmd.get_arguments().any(|x| x.get_id() == arg),
|
||||
"Command {}: Argument group '{}' contains non-existent argument '{}'",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
arg
|
||||
);
|
||||
}
|
||||
|
||||
for arg in &group.requires {
|
||||
// Args listed inside groups should exist
|
||||
assert!(
|
||||
cmd.id_exists(arg),
|
||||
"Command {}: Argument group '{}' requires non-existent '{}' id",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
arg
|
||||
);
|
||||
}
|
||||
|
||||
for arg in &group.conflicts {
|
||||
// Args listed inside groups should exist
|
||||
assert!(
|
||||
cmd.id_exists(arg),
|
||||
"Command {}: Argument group '{}' conflicts with non-existent '{}' id",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
arg
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Conflicts between flags and subcommands
|
||||
|
||||
long_flags.sort_unstable();
|
||||
short_flags.sort_unstable();
|
||||
|
||||
detect_duplicate_flags(&long_flags, "long");
|
||||
detect_duplicate_flags(&short_flags, "short");
|
||||
|
||||
let mut subs = FlatSet::new();
|
||||
for sc in cmd.get_subcommands() {
|
||||
assert!(
|
||||
subs.insert(sc.get_name()),
|
||||
"Command {}: command name `{}` is duplicated",
|
||||
cmd.get_name(),
|
||||
sc.get_name()
|
||||
);
|
||||
for alias in sc.get_all_aliases() {
|
||||
assert!(
|
||||
subs.insert(alias),
|
||||
"Command {}: command `{}` alias `{}` is duplicated",
|
||||
cmd.get_name(),
|
||||
sc.get_name(),
|
||||
alias
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_verify_positionals(cmd);
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
if let Some(help_template) = cmd.get_help_template() {
|
||||
assert!(
|
||||
!help_template.to_string().contains("{flags}"),
|
||||
"Command {}: {}",
|
||||
cmd.get_name(),
|
||||
"`{flags}` template variable was removed in clap3, they are now included in `{options}`",
|
||||
);
|
||||
assert!(
|
||||
!help_template.to_string().contains("{unified}"),
|
||||
"Command {}: {}",
|
||||
cmd.get_name(),
|
||||
"`{unified}` template variable was removed in clap3, use `{options}` instead"
|
||||
);
|
||||
#[cfg(feature = "unstable-v5")]
|
||||
assert!(
|
||||
!help_template.to_string().contains("{bin}"),
|
||||
"Command {}: {}",
|
||||
cmd.get_name(),
|
||||
"`{bin}` template variable was removed in clap5, use `{name}` instead"
|
||||
);
|
||||
}
|
||||
|
||||
cmd._panic_on_missing_help(cmd.is_help_expected_set());
|
||||
assert_app_flags(cmd);
|
||||
}
|
||||
|
||||
fn duplicate_tip(cmd: &Command, first: &Arg, second: &Arg) -> &'static str {
|
||||
if !cmd.is_disable_help_flag_set()
|
||||
&& (first.get_id() == Id::HELP || second.get_id() == Id::HELP)
|
||||
{
|
||||
" (call `cmd.disable_help_flag(true)` to remove the auto-generated `--help`)"
|
||||
} else if !cmd.is_disable_version_flag_set()
|
||||
&& (first.get_id() == Id::VERSION || second.get_id() == Id::VERSION)
|
||||
{
|
||||
" (call `cmd.disable_version_flag(true)` to remove the auto-generated `--version`)"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq)]
|
||||
enum Flag<'a> {
|
||||
Command(String, &'a str),
|
||||
Arg(String, &'a str),
|
||||
}
|
||||
|
||||
impl PartialEq for Flag<'_> {
|
||||
fn eq(&self, other: &Flag<'_>) -> bool {
|
||||
self.cmp(other) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for 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) {
|
||||
(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 {
|
||||
Ordering::Equal
|
||||
} else {
|
||||
s1.cmp(s2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_duplicate_flags(flags: &[Flag<'_>], short_or_long: &str) {
|
||||
for (one, two) in find_duplicates(flags) {
|
||||
match (one, two) {
|
||||
(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"
|
||||
),
|
||||
|
||||
(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}'"
|
||||
),
|
||||
|
||||
(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"
|
||||
),
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Find duplicates in a sorted array.
|
||||
///
|
||||
/// The algorithm is simple: the array is sorted, duplicates
|
||||
/// must be placed next to each other, we can check only adjacent elements.
|
||||
fn find_duplicates<T: PartialEq>(slice: &[T]) -> impl Iterator<Item = (&T, &T)> {
|
||||
slice.windows(2).filter_map(|w| {
|
||||
if w[0] == w[1] {
|
||||
Some((&w[0], &w[1]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn assert_app_flags(cmd: &Command) {
|
||||
macro_rules! checker {
|
||||
($a:ident conflicts $($b:ident)|+) => {
|
||||
if cmd.$a() {
|
||||
let mut s = String::new();
|
||||
|
||||
$(
|
||||
if cmd.$b() {
|
||||
use std::fmt::Write;
|
||||
write!(&mut s, " AppSettings::{} conflicts with AppSettings::{}.\n", std::stringify!($b), std::stringify!($a)).unwrap();
|
||||
}
|
||||
)+
|
||||
|
||||
if !s.is_empty() {
|
||||
panic!("{}\n{}", cmd.get_name(), s)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
checker!(is_multicall_set conflicts is_no_binary_name_set);
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
fn _verify_positionals(cmd: &Command) -> bool {
|
||||
debug!("Command::_verify_positionals");
|
||||
// Because you must wait until all arguments have been supplied, this is the first chance
|
||||
// to make assertions on positional argument indexes
|
||||
//
|
||||
// First we verify that the index highest supplied index, is equal to the number of
|
||||
// positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
|
||||
// but no 2)
|
||||
|
||||
let highest_idx = cmd
|
||||
.get_keymap()
|
||||
.keys()
|
||||
.filter_map(|x| {
|
||||
if let KeyType::Position(n) = x {
|
||||
Some(*n)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
|
||||
let num_p = cmd.get_keymap().keys().filter(|x| x.is_position()).count();
|
||||
|
||||
assert!(
|
||||
highest_idx == num_p,
|
||||
"Found positional argument whose index is {highest_idx} but there \
|
||||
are only {num_p} positional arguments defined",
|
||||
);
|
||||
|
||||
for arg in cmd.get_arguments() {
|
||||
if arg.index.unwrap_or(0) == highest_idx {
|
||||
assert!(
|
||||
!arg.is_trailing_var_arg_set() || !arg.is_last_set(),
|
||||
"{}:{}: `Arg::trailing_var_arg` and `Arg::last` cannot be used together",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
if arg.is_trailing_var_arg_set() {
|
||||
assert!(
|
||||
arg.is_multiple(),
|
||||
"{}:{}: `Arg::trailing_var_arg` must accept multiple values",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
assert!(
|
||||
!arg.is_trailing_var_arg_set(),
|
||||
"{}:{}: `Arg::trailing_var_arg` can only apply to last positional",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Next we verify that only the highest index has takes multiple arguments (if any)
|
||||
let only_highest = |a: &Arg| a.is_multiple() && (a.get_index().unwrap_or(0) != highest_idx);
|
||||
if cmd.get_positionals().any(only_highest) {
|
||||
// First we make sure if there is a positional that allows multiple values
|
||||
// the one before it (second to last) has one of these:
|
||||
// * a value terminator
|
||||
// * ArgSettings::Last
|
||||
// * The last arg is Required
|
||||
|
||||
// We can't pass the closure (it.next()) to the macro directly because each call to
|
||||
// find() (iterator, not macro) gets called repeatedly.
|
||||
let last = &cmd.get_keymap()[&KeyType::Position(highest_idx)];
|
||||
let second_to_last = &cmd.get_keymap()[&KeyType::Position(highest_idx - 1)];
|
||||
|
||||
// Either the final positional is required
|
||||
// Or the second to last has a terminator or .last(true) set
|
||||
let ok = last.is_required_set()
|
||||
|| (second_to_last.terminator.is_some() || second_to_last.is_last_set())
|
||||
|| last.is_last_set();
|
||||
assert!(
|
||||
ok,
|
||||
"Positional argument `{last}` *must* have `required(true)` or `last(true)` set \
|
||||
because a prior positional argument (`{second_to_last}`) has `num_args(1..)`"
|
||||
);
|
||||
|
||||
// We make sure if the second to last is Multiple the last is ArgSettings::Last
|
||||
let ok = second_to_last.is_multiple() || last.is_last_set();
|
||||
assert!(
|
||||
ok,
|
||||
"Only the last positional argument, or second to last positional \
|
||||
argument may be set to `.num_args(1..)`"
|
||||
);
|
||||
|
||||
// Next we check how many have both Multiple and not a specific number of values set
|
||||
let count = cmd
|
||||
.get_positionals()
|
||||
.filter(|p| {
|
||||
p.is_multiple_values_set()
|
||||
&& p.get_value_terminator().is_none()
|
||||
&& !p.get_num_args().expect(INTERNAL_ERROR_MSG).is_fixed()
|
||||
})
|
||||
.count();
|
||||
let ok = count <= 1
|
||||
|| (last.is_last_set()
|
||||
&& last.is_multiple()
|
||||
&& second_to_last.is_multiple()
|
||||
&& count == 2);
|
||||
assert!(
|
||||
ok,
|
||||
"Only one positional argument with `.num_args(1..)` set is allowed per \
|
||||
command, unless the second one also has .last(true) set"
|
||||
);
|
||||
}
|
||||
|
||||
let mut found = false;
|
||||
|
||||
if cmd.is_allow_missing_positional_set() {
|
||||
// Check that if a required positional argument is found, all positions with a lower
|
||||
// index are also required.
|
||||
let mut foundx2 = false;
|
||||
|
||||
for p in cmd.get_positionals() {
|
||||
if foundx2 && !p.is_required_set() {
|
||||
assert!(
|
||||
p.is_required_set(),
|
||||
"Found non-required positional argument with a lower \
|
||||
index than a required positional argument by two or more: {:?} \
|
||||
index {:?}",
|
||||
p.get_id(),
|
||||
p.get_index()
|
||||
);
|
||||
} else if p.is_required_set() && !p.is_last_set() {
|
||||
// Args that .last(true) don't count since they can be required and have
|
||||
// positionals with a lower index that aren't required
|
||||
// Imagine: prog <req1> [opt1] -- <req2>
|
||||
// Both of these are valid invocations:
|
||||
// $ prog r1 -- r2
|
||||
// $ prog r1 o1 -- r2
|
||||
if found {
|
||||
foundx2 = true;
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
} else {
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check that if a required positional argument is found, all positions with a lower
|
||||
// index are also required
|
||||
for p in (1..=num_p).rev().filter_map(|n| cmd.get_keymap().get(&n)) {
|
||||
if found {
|
||||
assert!(
|
||||
p.is_required_set(),
|
||||
"Found non-required positional argument with a lower \
|
||||
index than a required positional argument: {:?} index {:?}",
|
||||
p.get_id(),
|
||||
p.get_index()
|
||||
);
|
||||
} else if p.is_required_set() && !p.is_last_set() {
|
||||
// Args that .last(true) don't count since they can be required and have
|
||||
// positionals with a lower index that aren't required
|
||||
// Imagine: prog <req1> [opt1] -- <req2>
|
||||
// Both of these are valid invocations:
|
||||
// $ prog r1 -- r2
|
||||
// $ prog r1 o1 -- r2
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
cmd.get_positionals().filter(|p| p.is_last_set()).count() < 2,
|
||||
"Only one positional argument may have last(true) set. Found two."
|
||||
);
|
||||
if cmd
|
||||
.get_positionals()
|
||||
.any(|p| p.is_last_set() && p.is_required_set())
|
||||
&& cmd.has_subcommands()
|
||||
&& !cmd.is_subcommand_negates_reqs_set()
|
||||
{
|
||||
panic!(
|
||||
"Having a required positional argument with .last(true) set *and* child \
|
||||
subcommands without setting SubcommandsNegateReqs isn't compatible."
|
||||
);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn assert_arg(arg: &Arg) {
|
||||
debug!("Arg::_debug_asserts:{}", arg.get_id());
|
||||
|
||||
// Self conflict
|
||||
// TODO: this check should be recursive
|
||||
assert!(
|
||||
!arg.conflicts.iter().any(|x| x == arg.get_id()),
|
||||
"Argument '{}' cannot conflict with itself",
|
||||
arg.get_id(),
|
||||
);
|
||||
|
||||
assert!(
|
||||
arg.get_num_args().unwrap_or(1.into()).max_values()
|
||||
<= arg.get_action().max_num_args().max_values(),
|
||||
"Argument `{}`'s action {:?} is incompatible with `num_args({:?})`",
|
||||
arg.get_id(),
|
||||
arg.get_action(),
|
||||
arg.get_num_args().unwrap_or(1.into())
|
||||
);
|
||||
if let Some(action_type_id) = arg.get_action().value_type_id() {
|
||||
assert_eq!(
|
||||
action_type_id,
|
||||
arg.get_value_parser().type_id(),
|
||||
"Argument `{}`'s selected action {:?} contradicts `value_parser` ({:?})",
|
||||
arg.get_id(),
|
||||
arg.get_action(),
|
||||
arg.get_value_parser()
|
||||
);
|
||||
}
|
||||
|
||||
if arg.get_value_hint() != ValueHint::Unknown {
|
||||
assert!(
|
||||
arg.is_takes_value_set(),
|
||||
"Argument '{}' has value hint but takes no value",
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
if arg.get_value_hint() == ValueHint::CommandWithArguments {
|
||||
assert!(
|
||||
arg.is_multiple_values_set(),
|
||||
"Argument '{}' uses hint CommandWithArguments and must accept multiple values",
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if arg.index.is_some() {
|
||||
assert!(
|
||||
arg.is_positional(),
|
||||
"Argument '{}' is a positional argument and can't have short or long name versions",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
arg.is_takes_value_set(),
|
||||
"Argument '{}' is positional and it must take a value but action is {:?}{}",
|
||||
arg.get_id(),
|
||||
arg.get_action(),
|
||||
if arg.get_id() == Id::HELP {
|
||||
" (`mut_arg` no longer works with implicit `--help`)"
|
||||
} else if arg.get_id() == Id::VERSION {
|
||||
" (`mut_arg` no longer works with implicit `--version`)"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let num_vals = arg.get_num_args().expect(INTERNAL_ERROR_MSG);
|
||||
// This can be the cause of later asserts, so put this first
|
||||
if num_vals != ValueRange::EMPTY {
|
||||
// HACK: Don't check for flags to make the derive easier
|
||||
let num_val_names = arg.get_value_names().unwrap_or(&[]).len();
|
||||
if num_vals.max_values() < num_val_names {
|
||||
panic!(
|
||||
"Argument {}: Too many value names ({}) compared to `num_args` ({})",
|
||||
arg.get_id(),
|
||||
num_val_names,
|
||||
num_vals
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
num_vals.is_multiple(),
|
||||
arg.is_multiple_values_set(),
|
||||
"Argument {}: mismatch between `num_args` ({}) and `multiple_values`",
|
||||
arg.get_id(),
|
||||
num_vals,
|
||||
);
|
||||
|
||||
if 1 < num_vals.min_values() {
|
||||
assert!(
|
||||
!arg.is_require_equals_set(),
|
||||
"Argument {}: cannot accept more than 1 arg (num_args={}) with require_equals",
|
||||
arg.get_id(),
|
||||
num_vals
|
||||
);
|
||||
}
|
||||
|
||||
if num_vals == ValueRange::SINGLE {
|
||||
assert!(
|
||||
!arg.is_multiple_values_set(),
|
||||
"Argument {}: mismatch between `num_args` and `multiple_values`",
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
|
||||
assert_arg_flags(arg);
|
||||
}
|
||||
|
||||
fn assert_arg_flags(arg: &Arg) {
|
||||
macro_rules! checker {
|
||||
($a:ident requires $($b:ident)|+) => {
|
||||
if arg.$a() {
|
||||
let mut s = String::new();
|
||||
|
||||
$(
|
||||
if !arg.$b() {
|
||||
use std::fmt::Write;
|
||||
write!(&mut s, " Arg::{} is required when Arg::{} is set.\n", std::stringify!($b), std::stringify!($a)).unwrap();
|
||||
}
|
||||
)+
|
||||
|
||||
if !s.is_empty() {
|
||||
panic!("Argument {:?}\n{}", arg.get_id(), s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checker!(is_hide_possible_values_set requires is_takes_value_set);
|
||||
checker!(is_allow_hyphen_values_set requires is_takes_value_set);
|
||||
checker!(is_allow_negative_numbers_set requires is_takes_value_set);
|
||||
checker!(is_require_equals_set requires is_takes_value_set);
|
||||
checker!(is_last_set requires is_takes_value_set);
|
||||
checker!(is_hide_default_value_set requires is_takes_value_set);
|
||||
checker!(is_multiple_values_set requires is_takes_value_set);
|
||||
checker!(is_ignore_case_set requires is_takes_value_set);
|
||||
}
|
||||
46
third_party/crates/clap_builder-4.6.7/src/builder/ext.rs
vendored
Normal file
46
third_party/crates/clap_builder-4.6.7/src/builder/ext.rs
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
use crate::util::AnyValue;
|
||||
use crate::util::AnyValueId;
|
||||
use crate::util::FlatMap;
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub(crate) struct Extensions {
|
||||
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.downcast_ref::<T>()
|
||||
.expect("`Extensions` tracks values by type")
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
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<T> {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions.remove(&id).map(|e| {
|
||||
e.downcast_into::<T>()
|
||||
.expect("`Extensions` tracks values by type")
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn update(&mut self, other: &Self) {
|
||||
for (key, value) in other.extensions.iter() {
|
||||
self.extensions.insert(*key, value.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unreachable_pub)]
|
||||
pub trait Extension: std::fmt::Debug + Clone + std::any::Any + Send + Sync + 'static {}
|
||||
|
||||
impl<T> Extension for T where T: std::fmt::Debug + Clone + std::any::Any + Send + Sync + 'static {}
|
||||
71
third_party/crates/clap_builder-4.6.7/src/builder/mod.rs
vendored
Normal file
71
third_party/crates/clap_builder-4.6.7/src/builder/mod.rs
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
//! Define [`Command`] line [arguments][`Arg`]
|
||||
|
||||
mod action;
|
||||
mod app_settings;
|
||||
mod arg;
|
||||
mod arg_group;
|
||||
mod arg_predicate;
|
||||
mod arg_settings;
|
||||
mod command;
|
||||
mod ext;
|
||||
mod os_str;
|
||||
mod possible_value;
|
||||
mod range;
|
||||
mod resettable;
|
||||
mod str;
|
||||
mod styled_str;
|
||||
mod value_hint;
|
||||
mod value_parser;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
mod debug_asserts;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
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;
|
||||
#[cfg(feature = "unstable-ext")]
|
||||
pub use command::CommandExt;
|
||||
pub use os_str::OsStr;
|
||||
pub use possible_value::PossibleValue;
|
||||
pub use range::ValueRange;
|
||||
pub use resettable::IntoResettable;
|
||||
pub use resettable::Resettable;
|
||||
pub use styled_str::StyledStr;
|
||||
pub use styling::Styles;
|
||||
pub use value_hint::ValueHint;
|
||||
pub use value_parser::_AnonymousValueParser;
|
||||
pub use value_parser::_infer_ValueParser_for;
|
||||
pub use value_parser::BoolValueParser;
|
||||
pub use value_parser::BoolishValueParser;
|
||||
pub use value_parser::EnumValueParser;
|
||||
pub use value_parser::FalseyValueParser;
|
||||
pub use value_parser::MapValueParser;
|
||||
pub use value_parser::NonEmptyStringValueParser;
|
||||
pub use value_parser::OsStringValueParser;
|
||||
pub use value_parser::PathBufValueParser;
|
||||
pub use value_parser::PossibleValuesParser;
|
||||
pub use value_parser::RangedI64ValueParser;
|
||||
pub use value_parser::RangedU64ValueParser;
|
||||
pub use value_parser::StringValueParser;
|
||||
pub use value_parser::TryMapValueParser;
|
||||
pub use value_parser::TypedValueParser;
|
||||
pub use value_parser::UnknownArgumentValueParser;
|
||||
pub use value_parser::ValueParser;
|
||||
pub use value_parser::ValueParserFactory;
|
||||
pub use value_parser::impl_prelude;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use self::str::Inner as StrInner;
|
||||
pub(crate) use action::CountType;
|
||||
pub(crate) use arg_settings::{ArgFlags, ArgSettings};
|
||||
pub(crate) use command::AppExt;
|
||||
364
third_party/crates/clap_builder-4.6.7/src/builder/os_str.rs
vendored
Normal file
364
third_party/crates/clap_builder-4.6.7/src/builder/os_str.rs
vendored
Normal file
@@ -0,0 +1,364 @@
|
||||
use crate::builder::Str;
|
||||
#[cfg(feature = "string")]
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// A UTF-8-encoded fixed string
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** To support dynamic values (i.e. `OsString`), enable the `string`
|
||||
/// feature
|
||||
///
|
||||
/// </div>
|
||||
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct OsStr {
|
||||
name: Inner,
|
||||
}
|
||||
|
||||
impl OsStr {
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_string(name: std::ffi::OsString) -> Self {
|
||||
Self {
|
||||
name: Inner::from_string(name),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_ref(name: &std::ffi::OsStr) -> Self {
|
||||
Self {
|
||||
name: Inner::from_ref(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
|
||||
Self {
|
||||
name: Inner::from_static_ref(name),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the raw string as an `std::ffi::OsStr`
|
||||
pub fn as_os_str(&self) -> &std::ffi::OsStr {
|
||||
self.name.as_os_str()
|
||||
}
|
||||
|
||||
/// Get the raw string as an `OsString`
|
||||
pub fn to_os_string(&self) -> std::ffi::OsString {
|
||||
self.as_os_str().to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Self> for OsStr {
|
||||
fn from(id: &'_ Self) -> Self {
|
||||
id.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<Str> for OsStr {
|
||||
fn from(id: Str) -> Self {
|
||||
match id.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())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "string"))]
|
||||
impl From<Str> for OsStr {
|
||||
fn from(id: Str) -> Self {
|
||||
Self::from_static_ref(std::ffi::OsStr::new(id.into_inner().0))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Str> for OsStr {
|
||||
fn from(id: &'_ Str) -> Self {
|
||||
id.clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<std::ffi::OsString> for OsStr {
|
||||
fn from(name: std::ffi::OsString) -> Self {
|
||||
Self::from_string(name)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ std::ffi::OsString> for OsStr {
|
||||
fn from(name: &'_ std::ffi::OsString) -> Self {
|
||||
Self::from_ref(name.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<String> for OsStr {
|
||||
fn from(name: String) -> Self {
|
||||
Self::from_string(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ String> for OsStr {
|
||||
fn from(name: &'_ String) -> Self {
|
||||
Self::from_ref(name.as_str().as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static std::ffi::OsStr> for OsStr {
|
||||
fn from(name: &'static std::ffi::OsStr) -> Self {
|
||||
Self::from_static_ref(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static std::ffi::OsStr> for OsStr {
|
||||
fn from(name: &'_ &'static std::ffi::OsStr) -> Self {
|
||||
Self::from_static_ref(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for OsStr {
|
||||
fn from(name: &'static str) -> Self {
|
||||
Self::from_static_ref(name.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static str> for OsStr {
|
||||
fn from(name: &'_ &'static str) -> Self {
|
||||
Self::from_static_ref((*name).as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<Cow<'static, str>> for OsStr {
|
||||
fn from(cow: Cow<'static, str>) -> Self {
|
||||
match cow {
|
||||
Cow::Borrowed(s) => Self::from(s),
|
||||
Cow::Owned(s) => Self::from(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OsStr> for std::ffi::OsString {
|
||||
fn from(name: OsStr) -> Self {
|
||||
name.name.into_os_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OsStr> for std::path::PathBuf {
|
||||
fn from(name: OsStr) -> Self {
|
||||
std::ffi::OsString::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for OsStr {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self.as_os_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for OsStr {
|
||||
type Target = std::ffi::OsStr;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &std::ffi::OsStr {
|
||||
self.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<std::ffi::OsStr> for OsStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &std::ffi::OsStr {
|
||||
self.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<std::path::Path> for OsStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &std::path::Path {
|
||||
std::path::Path::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::borrow::Borrow<std::ffi::OsStr> for OsStr {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &std::ffi::OsStr {
|
||||
self.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(self, other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ str> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for &'_ str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(*self, other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ std::ffi::OsStr> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&std::ffi::OsStr) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for &'_ std::ffi::OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(*self, other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<String> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &String) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::ffi::OsString> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::ffi::OsString) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other.as_os_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for std::ffi::OsString {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) mod inner {
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum Inner {
|
||||
Static(&'static std::ffi::OsStr),
|
||||
Owned(Box<std::ffi::OsStr>),
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_string(name: std::ffi::OsString) -> Self {
|
||||
Self::Owned(name.into_boxed_os_str())
|
||||
}
|
||||
|
||||
pub(crate) fn from_ref(name: &std::ffi::OsStr) -> Self {
|
||||
Self::Owned(Box::from(name))
|
||||
}
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
|
||||
Self::Static(name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_os_str(&self) -> &std::ffi::OsStr {
|
||||
match self {
|
||||
Self::Static(s) => s,
|
||||
Self::Owned(s) => s.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_os_string(self) -> std::ffi::OsString {
|
||||
self.as_os_str().to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "string"))]
|
||||
pub(crate) mod inner {
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Inner(&'static std::ffi::OsStr);
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
|
||||
Self(name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_os_str(&self) -> &std::ffi::OsStr {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub(crate) fn into_os_string(self) -> std::ffi::OsString {
|
||||
self.as_os_str().to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use inner::Inner;
|
||||
|
||||
impl Default for Inner {
|
||||
fn default() -> Self {
|
||||
Self::from_static_ref(std::ffi::OsStr::new(""))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Inner {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_os_str() == other.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Inner {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Inner {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.as_os_str().cmp(other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Inner {}
|
||||
|
||||
impl std::hash::Hash for Inner {
|
||||
#[inline]
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.as_os_str().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "string")]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "string")]
|
||||
fn from_cow_borrowed() {
|
||||
let cow = Cow::Borrowed("hello");
|
||||
let osstr = OsStr::from(cow);
|
||||
assert_eq!(osstr, OsStr::from("hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "string")]
|
||||
fn from_cow_owned() {
|
||||
let cow = Cow::Owned("world".to_owned());
|
||||
let osstr = OsStr::from(cow);
|
||||
assert_eq!(osstr, OsStr::from("world"));
|
||||
}
|
||||
}
|
||||
235
third_party/crates/clap_builder-4.6.7/src/builder/possible_value.rs
vendored
Normal file
235
third_party/crates/clap_builder-4.6.7/src/builder/possible_value.rs
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
use crate::builder::IntoResettable;
|
||||
use crate::builder::Str;
|
||||
use crate::builder::StyledStr;
|
||||
#[cfg(feature = "help")]
|
||||
use crate::util::Escape;
|
||||
use crate::util::eq_ignore_case;
|
||||
|
||||
/// A possible value of an argument.
|
||||
///
|
||||
/// This is used for specifying [possible values] of [Args].
|
||||
///
|
||||
/// See also [`PossibleValuesParser`][crate::builder::PossibleValuesParser]
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** Most likely you can use strings, rather than `PossibleValue` as it is only required
|
||||
/// to [hide] single values from help messages and shell completions or to attach [help] to
|
||||
/// possible values.
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Arg, builder::PossibleValue, ArgAction};
|
||||
/// let cfg = Arg::new("config")
|
||||
/// .action(ArgAction::Set)
|
||||
/// .value_name("FILE")
|
||||
/// .value_parser([
|
||||
/// PossibleValue::new("fast"),
|
||||
/// PossibleValue::new("slow").help("slower than fast"),
|
||||
/// PossibleValue::new("secret speed").hide(true)
|
||||
/// ]);
|
||||
/// ```
|
||||
///
|
||||
/// [Args]: crate::Arg
|
||||
/// [possible values]: crate::builder::ValueParser::possible_values
|
||||
/// [hide]: PossibleValue::hide()
|
||||
/// [help]: PossibleValue::help()
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct PossibleValue {
|
||||
name: Str,
|
||||
help: Option<StyledStr>,
|
||||
aliases: Vec<Str>, // (name, visible)
|
||||
hide: bool,
|
||||
}
|
||||
|
||||
impl PossibleValue {
|
||||
/// Create a [`PossibleValue`] with its name.
|
||||
///
|
||||
/// The name will be used to decide whether this value was provided by the user to an argument.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** In case it is not [hidden] it will also be shown in help messages for arguments
|
||||
/// that use it as a [possible value] and have not hidden them through [`Arg::hide_possible_values(true)`].
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("fast")
|
||||
/// # ;
|
||||
/// ```
|
||||
/// [hidden]: PossibleValue::hide
|
||||
/// [possible value]: crate::builder::PossibleValuesParser
|
||||
/// [`Arg::hide_possible_values(true)`]: crate::Arg::hide_possible_values()
|
||||
pub fn new(name: impl Into<Str>) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the help description of the value.
|
||||
///
|
||||
/// This is typically displayed in completions (where supported) and should be a short, one-line
|
||||
/// description.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("slow")
|
||||
/// .help("not fast")
|
||||
/// # ;
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn help(mut self, help: impl IntoResettable<StyledStr>) -> Self {
|
||||
self.help = help.into_resettable().into_option();
|
||||
self
|
||||
}
|
||||
|
||||
/// Hides this value from help and shell completions.
|
||||
///
|
||||
/// This is an alternative to hiding through [`Arg::hide_possible_values(true)`], if you only
|
||||
/// want to hide some values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("secret")
|
||||
/// .hide(true)
|
||||
/// # ;
|
||||
/// ```
|
||||
/// [`Arg::hide_possible_values(true)`]: crate::Arg::hide_possible_values()
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn hide(mut self, yes: bool) -> Self {
|
||||
self.hide = yes;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a *hidden* alias for this argument value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("slow")
|
||||
/// .alias("not-fast")
|
||||
/// # ;
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn alias(mut self, name: impl IntoResettable<Str>) -> Self {
|
||||
if let Some(name) = name.into_resettable().into_option() {
|
||||
self.aliases.push(name);
|
||||
} else {
|
||||
self.aliases.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets multiple *hidden* aliases for this argument value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("slow")
|
||||
/// .aliases(["not-fast", "snake-like"])
|
||||
/// # ;
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn aliases(mut self, names: impl IntoIterator<Item = impl Into<Str>>) -> Self {
|
||||
self.aliases.extend(names.into_iter().map(|a| a.into()));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Reflection
|
||||
impl PossibleValue {
|
||||
/// Get the name of the argument value
|
||||
#[inline]
|
||||
pub fn get_name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
/// Get the help specified for this argument, if any
|
||||
#[inline]
|
||||
pub fn get_help(&self) -> Option<&StyledStr> {
|
||||
self.help.as_ref()
|
||||
}
|
||||
|
||||
/// Report if [`PossibleValue::hide`] is set
|
||||
#[inline]
|
||||
pub fn is_hide_set(&self) -> bool {
|
||||
self.hide
|
||||
}
|
||||
|
||||
/// 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()
|
||||
}
|
||||
|
||||
/// Get the name if argument value is not hidden, `None` otherwise,
|
||||
/// but wrapped in quotes if it contains whitespace
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn get_visible_quoted_name(&self) -> Option<std::borrow::Cow<'_, str>> {
|
||||
if !self.hide {
|
||||
Some(Escape(self.name.as_str()).to_cow())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns all valid values of the argument value.
|
||||
///
|
||||
/// Namely the name and all aliases.
|
||||
pub fn get_name_and_aliases(&self) -> impl Iterator<Item = &str> + '_ {
|
||||
std::iter::once(self.get_name()).chain(self.aliases.iter().map(|s| s.as_str()))
|
||||
}
|
||||
|
||||
/// Tests if the value is valid for this argument value
|
||||
///
|
||||
/// The value is valid if it is either the name or one of the aliases.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// let arg_value = PossibleValue::new("fast").alias("not-slow");
|
||||
///
|
||||
/// assert!(arg_value.matches("fast", false));
|
||||
/// assert!(arg_value.matches("not-slow", false));
|
||||
///
|
||||
/// assert!(arg_value.matches("FAST", true));
|
||||
/// assert!(!arg_value.matches("FAST", false));
|
||||
/// ```
|
||||
pub fn matches(&self, value: &str, ignore_case: bool) -> bool {
|
||||
if ignore_case {
|
||||
self.get_name_and_aliases()
|
||||
.any(|name| eq_ignore_case(name, value))
|
||||
} else {
|
||||
self.get_name_and_aliases().any(|name| name == value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Into<Str>> From<S> for PossibleValue {
|
||||
fn from(s: S) -> Self {
|
||||
Self::new(s)
|
||||
}
|
||||
}
|
||||
305
third_party/crates/clap_builder-4.6.7/src/builder/range.rs
vendored
Normal file
305
third_party/crates/clap_builder-4.6.7/src/builder/range.rs
vendored
Normal file
@@ -0,0 +1,305 @@
|
||||
/// Values per occurrence for an argument
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ValueRange {
|
||||
start_inclusive: usize,
|
||||
end_inclusive: usize,
|
||||
}
|
||||
|
||||
impl ValueRange {
|
||||
/// Nor argument values, or a flag
|
||||
pub const EMPTY: Self = Self {
|
||||
start_inclusive: 0,
|
||||
end_inclusive: 0,
|
||||
};
|
||||
|
||||
/// A single argument value, the most common case for options
|
||||
pub const SINGLE: Self = Self {
|
||||
start_inclusive: 1,
|
||||
end_inclusive: 1,
|
||||
};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) const OPTIONAL: Self = Self {
|
||||
start_inclusive: 0,
|
||||
end_inclusive: 1,
|
||||
};
|
||||
|
||||
pub(crate) const FULL: Self = Self {
|
||||
start_inclusive: 0,
|
||||
end_inclusive: usize::MAX,
|
||||
};
|
||||
|
||||
/// Create a range
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// In debug builds, if the range accepts no values. For an exclusive range
|
||||
/// (`start..end`) that means `end` must be greater than `start`, so both
|
||||
/// reversed ranges like `10..5` and empty ranges like `5..5` panic.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::ValueRange;
|
||||
/// let range = ValueRange::new(5);
|
||||
/// let range = ValueRange::new(5..10);
|
||||
/// let range = ValueRange::new(5..=10);
|
||||
/// let range = ValueRange::new(5..);
|
||||
/// let range = ValueRange::new(..10);
|
||||
/// let range = ValueRange::new(..=10);
|
||||
/// ```
|
||||
///
|
||||
/// While these will panic:
|
||||
/// ```should_panic
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::ValueRange;
|
||||
/// let range = ValueRange::new(10..5); // Panics! (reversed)
|
||||
/// ```
|
||||
/// ```should_panic
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::ValueRange;
|
||||
/// let range = ValueRange::new(5..5); // Panics! (empty)
|
||||
/// ```
|
||||
pub fn new(range: impl Into<Self>) -> Self {
|
||||
range.into()
|
||||
}
|
||||
|
||||
pub(crate) fn raw(start_inclusive: usize, end_inclusive: usize) -> Self {
|
||||
debug_assert!(start_inclusive <= end_inclusive);
|
||||
Self {
|
||||
start_inclusive,
|
||||
end_inclusive,
|
||||
}
|
||||
}
|
||||
|
||||
/// Fewest number of values the argument accepts
|
||||
pub fn min_values(&self) -> usize {
|
||||
self.start_inclusive
|
||||
}
|
||||
|
||||
/// Most number of values the argument accepts
|
||||
pub fn max_values(&self) -> usize {
|
||||
self.end_inclusive
|
||||
}
|
||||
|
||||
/// Report whether the argument takes any values (ie is a flag)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::ValueRange;
|
||||
/// let range = ValueRange::new(5);
|
||||
/// assert!(range.takes_values());
|
||||
///
|
||||
/// let range = ValueRange::new(0);
|
||||
/// assert!(!range.takes_values());
|
||||
/// ```
|
||||
pub fn takes_values(&self) -> bool {
|
||||
self.end_inclusive != 0
|
||||
}
|
||||
|
||||
pub(crate) fn is_unbounded(&self) -> bool {
|
||||
self.end_inclusive == usize::MAX
|
||||
}
|
||||
|
||||
pub(crate) fn is_fixed(&self) -> bool {
|
||||
self.start_inclusive == self.end_inclusive
|
||||
}
|
||||
|
||||
pub(crate) fn is_multiple(&self) -> bool {
|
||||
self.start_inclusive != self.end_inclusive || 1 < self.start_inclusive
|
||||
}
|
||||
|
||||
pub(crate) fn num_values(&self) -> Option<usize> {
|
||||
self.is_fixed().then_some(self.start_inclusive)
|
||||
}
|
||||
|
||||
pub(crate) fn accepts_more(&self, current: usize) -> bool {
|
||||
current < self.end_inclusive
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::RangeBounds<usize> for ValueRange {
|
||||
fn start_bound(&self) -> std::ops::Bound<&usize> {
|
||||
std::ops::Bound::Included(&self.start_inclusive)
|
||||
}
|
||||
|
||||
fn end_bound(&self) -> std::ops::Bound<&usize> {
|
||||
std::ops::Bound::Included(&self.end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ValueRange {
|
||||
fn default() -> Self {
|
||||
Self::SINGLE
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for ValueRange {
|
||||
fn from(fixed: usize) -> Self {
|
||||
(fixed..=fixed).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::Range<usize>> for ValueRange {
|
||||
fn from(range: std::ops::Range<usize>) -> Self {
|
||||
let start_inclusive = range.start;
|
||||
let end_inclusive = range.end.saturating_sub(1);
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeFull> for ValueRange {
|
||||
fn from(_: std::ops::RangeFull) -> Self {
|
||||
Self::FULL
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeFrom<usize>> for ValueRange {
|
||||
fn from(range: std::ops::RangeFrom<usize>) -> Self {
|
||||
let start_inclusive = range.start;
|
||||
let end_inclusive = usize::MAX;
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeTo<usize>> for ValueRange {
|
||||
fn from(range: std::ops::RangeTo<usize>) -> Self {
|
||||
let start_inclusive = 0;
|
||||
let end_inclusive = range.end.saturating_sub(1);
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeInclusive<usize>> for ValueRange {
|
||||
fn from(range: std::ops::RangeInclusive<usize>) -> Self {
|
||||
let start_inclusive = *range.start();
|
||||
let end_inclusive = *range.end();
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeToInclusive<usize>> for ValueRange {
|
||||
fn from(range: std::ops::RangeToInclusive<usize>) -> Self {
|
||||
let start_inclusive = 0;
|
||||
let end_inclusive = range.end;
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ValueRange {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
ok!(self.start_inclusive.fmt(f));
|
||||
if self.is_fixed() {
|
||||
} else if self.end_inclusive == usize::MAX {
|
||||
ok!("..".fmt(f));
|
||||
} else {
|
||||
ok!("..=".fmt(f));
|
||||
ok!(self.end_inclusive.fmt(f));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ValueRange {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{self}")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
use std::ops::RangeBounds;
|
||||
|
||||
#[test]
|
||||
fn from_fixed() {
|
||||
let range: ValueRange = 5.into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&5));
|
||||
assert!(range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), Some(5));
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_fixed_empty() {
|
||||
let range: ValueRange = 0.into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&0));
|
||||
assert!(range.is_fixed());
|
||||
assert!(!range.is_multiple());
|
||||
assert_eq!(range.num_values(), Some(0));
|
||||
assert!(!range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range() {
|
||||
let range: ValueRange = (5..10).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&9));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_inclusive() {
|
||||
let range: ValueRange = (5..=10).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&10));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_full() {
|
||||
let range: ValueRange = (..).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&usize::MAX));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_from() {
|
||||
let range: ValueRange = (5..).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&usize::MAX));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_to() {
|
||||
let range: ValueRange = (..10).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&9));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_to_inclusive() {
|
||||
let range: ValueRange = (..=10).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&10));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
}
|
||||
212
third_party/crates/clap_builder-4.6.7/src/builder/resettable.rs
vendored
Normal file
212
third_party/crates/clap_builder-4.6.7/src/builder/resettable.rs
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
// Unlike `impl Into<Option<T>>` or `Option<impl Into<T>>`, this isn't ambiguous for the `None`
|
||||
// case.
|
||||
|
||||
use crate::builder::ArgAction;
|
||||
use crate::builder::OsStr;
|
||||
use crate::builder::Str;
|
||||
use crate::builder::StyledStr;
|
||||
use crate::builder::ValueHint;
|
||||
use crate::builder::ValueParser;
|
||||
use crate::builder::ValueRange;
|
||||
|
||||
/// Clearable builder value
|
||||
///
|
||||
/// This allows a builder function to both accept any value that can [`Into::into`] `T` (like
|
||||
/// `&str` into `OsStr`) as well as `None` to reset it to the default. This is needed to
|
||||
/// workaround a limitation where you can't have a function argument that is `impl Into<Option<T>>`
|
||||
/// where `T` is `impl Into<S>` accept `None` as its type is ambiguous.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// fn common() -> Command {
|
||||
/// Command::new("cli")
|
||||
/// .arg(Arg::new("input").short('i').long("input"))
|
||||
/// }
|
||||
/// let mut command = common();
|
||||
/// command.mut_arg("input", |arg| arg.short(None));
|
||||
/// ```
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Resettable<T> {
|
||||
/// Overwrite builder value
|
||||
Value(T),
|
||||
/// Reset builder value
|
||||
Reset,
|
||||
}
|
||||
|
||||
impl<T> Resettable<T> {
|
||||
pub(crate) fn into_option(self) -> Option<T> {
|
||||
match self {
|
||||
Self::Value(t) => Some(t),
|
||||
Self::Reset => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Resettable<T> {
|
||||
fn from(other: T) -> Self {
|
||||
Self::Value(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Option<T>> for Resettable<T> {
|
||||
fn from(other: Option<T>) -> Self {
|
||||
match other {
|
||||
Some(inner) => Self::Value(inner),
|
||||
None => Self::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert to the intended resettable type
|
||||
pub trait IntoResettable<T> {
|
||||
/// Convert to the intended resettable type
|
||||
fn into_resettable(self) -> Resettable<T>;
|
||||
}
|
||||
|
||||
impl IntoResettable<char> for Option<char> {
|
||||
fn into_resettable(self) -> Resettable<char> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<usize> for Option<usize> {
|
||||
fn into_resettable(self) -> Resettable<usize> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ArgAction> for Option<ArgAction> {
|
||||
fn into_resettable(self) -> Resettable<ArgAction> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ValueHint> for Option<ValueHint> {
|
||||
fn into_resettable(self) -> Resettable<ValueHint> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ValueParser> for Option<ValueParser> {
|
||||
fn into_resettable(self) -> Resettable<ValueParser> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<StyledStr> for Option<&'static str> {
|
||||
fn into_resettable(self) -> Resettable<StyledStr> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s.into()),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<OsStr> for Option<&'static str> {
|
||||
fn into_resettable(self) -> Resettable<OsStr> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s.into()),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<Str> for Option<&'static str> {
|
||||
fn into_resettable(self) -> Resettable<Str> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s.into()),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoResettable<T> for Resettable<T> {
|
||||
fn into_resettable(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<Self> for char {
|
||||
fn into_resettable(self) -> Resettable<Self> {
|
||||
Resettable::Value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<Self> for usize {
|
||||
fn into_resettable(self) -> Resettable<Self> {
|
||||
Resettable::Value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<Self> for ArgAction {
|
||||
fn into_resettable(self) -> Resettable<Self> {
|
||||
Resettable::Value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<Self> for ValueHint {
|
||||
fn into_resettable(self) -> Resettable<Self> {
|
||||
Resettable::Value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<ValueRange>> IntoResettable<ValueRange> for I {
|
||||
fn into_resettable(self) -> Resettable<ValueRange> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<ValueParser>> IntoResettable<ValueParser> for I {
|
||||
fn into_resettable(self) -> Resettable<ValueParser> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<String>> IntoResettable<String> for I {
|
||||
fn into_resettable(self) -> Resettable<String> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<StyledStr>> IntoResettable<StyledStr> for I {
|
||||
fn into_resettable(self) -> Resettable<StyledStr> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<OsStr>> IntoResettable<OsStr> for I {
|
||||
fn into_resettable(self) -> Resettable<OsStr> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<Str>> IntoResettable<Str> for I {
|
||||
fn into_resettable(self) -> Resettable<Str> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<crate::Id>> IntoResettable<crate::Id> for I {
|
||||
fn into_resettable(self) -> Resettable<crate::Id> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
349
third_party/crates/clap_builder-4.6.7/src/builder/str.rs
vendored
Normal file
349
third_party/crates/clap_builder-4.6.7/src/builder/str.rs
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
#[cfg(feature = "string")]
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// A UTF-8-encoded fixed string
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** To support dynamic values (i.e. `String`), enable the `string`
|
||||
/// feature
|
||||
///
|
||||
/// </div>
|
||||
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct Str {
|
||||
name: Inner,
|
||||
}
|
||||
|
||||
impl Str {
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_string(name: String) -> Self {
|
||||
Self {
|
||||
name: Inner::from_string(name),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_ref(name: &str) -> Self {
|
||||
Self {
|
||||
name: Inner::from_ref(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static str) -> Self {
|
||||
Self {
|
||||
name: Inner::from_static_ref(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_inner(self) -> Inner {
|
||||
self.name
|
||||
}
|
||||
|
||||
/// Get the raw string of the `Str`
|
||||
pub fn as_str(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Self> for Str {
|
||||
fn from(id: &'_ Self) -> Self {
|
||||
id.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<String> for Str {
|
||||
fn from(name: String) -> Self {
|
||||
Self::from_string(name)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ String> for Str {
|
||||
fn from(name: &'_ String) -> Self {
|
||||
Self::from_ref(name.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Str {
|
||||
fn from(name: &'static str) -> Self {
|
||||
Self::from_static_ref(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static str> for Str {
|
||||
fn from(name: &'_ &'static str) -> Self {
|
||||
Self::from_static_ref(name)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<Cow<'static, str>> for Str {
|
||||
fn from(cow: Cow<'static, str>) -> Self {
|
||||
match cow {
|
||||
Cow::Borrowed(s) => Self::from(s),
|
||||
Cow::Owned(s) => Self::from(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for String {
|
||||
fn from(name: Str) -> Self {
|
||||
name.name.into_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for Vec<u8> {
|
||||
fn from(name: Str) -> Self {
|
||||
String::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for std::ffi::OsString {
|
||||
fn from(name: Str) -> Self {
|
||||
String::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for std::path::PathBuf {
|
||||
fn from(name: Str) -> Self {
|
||||
String::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Str {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Str {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Str {
|
||||
type Target = str;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<std::ffi::OsStr> for Str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &std::ffi::OsStr {
|
||||
(**self).as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<std::path::Path> for Str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &std::path::Path {
|
||||
std::path::Path::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::borrow::Borrow<str> for Str {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
PartialEq::eq(self.as_str(), other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ str> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
PartialEq::eq(self.as_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for &'_ str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(*self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::ffi::OsStr> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::ffi::OsStr) -> bool {
|
||||
PartialEq::eq(self.as_str(), other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for std::ffi::OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ std::ffi::OsStr> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&std::ffi::OsStr) -> bool {
|
||||
PartialEq::eq(self.as_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for &'_ std::ffi::OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(*self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<String> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &String) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) mod inner {
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum Inner {
|
||||
Static(&'static str),
|
||||
Owned(Box<str>),
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_string(name: String) -> Self {
|
||||
Self::Owned(name.into_boxed_str())
|
||||
}
|
||||
|
||||
pub(crate) fn from_ref(name: &str) -> Self {
|
||||
Self::Owned(Box::from(name))
|
||||
}
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static str) -> Self {
|
||||
Self::Static(name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_str(&self) -> &str {
|
||||
match self {
|
||||
Self::Static(s) => s,
|
||||
Self::Owned(s) => s.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_string(self) -> String {
|
||||
match self {
|
||||
Self::Static(s) => s.to_owned(),
|
||||
Self::Owned(s) => s.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "string"))]
|
||||
pub(crate) mod inner {
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Inner(pub(crate) &'static str);
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_static_ref(name: &'static str) -> Self {
|
||||
Self(name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_str(&self) -> &str {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub(crate) fn into_string(self) -> String {
|
||||
self.as_str().to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use inner::Inner;
|
||||
|
||||
impl Default for Inner {
|
||||
fn default() -> Self {
|
||||
Self::from_static_ref("")
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Inner {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Inner {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Inner {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.as_str().cmp(other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Inner {}
|
||||
|
||||
impl std::hash::Hash for Inner {
|
||||
#[inline]
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.as_str().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "string")]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "string")]
|
||||
fn from_cow_borrowed() {
|
||||
let cow = Cow::Borrowed("hello");
|
||||
let str = Str::from(cow);
|
||||
assert_eq!(str, Str::from("hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "string")]
|
||||
fn from_cow_owned() {
|
||||
let cow = Cow::Owned("world".to_owned());
|
||||
let str = Str::from(cow);
|
||||
assert_eq!(str, Str::from("world"));
|
||||
}
|
||||
}
|
||||
287
third_party/crates/clap_builder-4.6.7/src/builder/styled_str.rs
vendored
Normal file
287
third_party/crates/clap_builder-4.6.7/src/builder/styled_str.rs
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
#![cfg_attr(not(feature = "usage"), allow(dead_code))]
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// Terminal-styling container
|
||||
///
|
||||
/// Styling may be encoded as [ANSI Escape Code](https://en.wikipedia.org/wiki/ANSI_escape_code)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// // `cstr!` converts tags to ANSI codes
|
||||
/// let after_help: &'static str = color_print::cstr!(
|
||||
/// r#"<bold><underline>Examples</underline></bold>
|
||||
///
|
||||
/// <dim>$</dim> <bold>mybin --input file.toml</bold>
|
||||
/// "#);
|
||||
///
|
||||
/// let cmd = clap::Command::new("mybin")
|
||||
/// .after_help(after_help) // The `&str` gets converted into a `StyledStr`
|
||||
/// // ...
|
||||
/// # ;
|
||||
/// ```
|
||||
#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct StyledStr(String);
|
||||
|
||||
impl StyledStr {
|
||||
/// Create an empty buffer
|
||||
pub const fn new() -> Self {
|
||||
Self(String::new())
|
||||
}
|
||||
|
||||
/// Display using [ANSI Escape Code](https://en.wikipedia.org/wiki/ANSI_escape_code) styling
|
||||
#[cfg(feature = "color")]
|
||||
pub fn ansi(&self) -> impl std::fmt::Display + '_ {
|
||||
self.0.as_str()
|
||||
}
|
||||
|
||||
/// May allow the compiler to consolidate the `Drop`s for `msg`, reducing code size compared to
|
||||
/// `styled.push_str(&msg)`
|
||||
pub(crate) fn push_string(&mut self, msg: String) {
|
||||
self.0.push_str(&msg);
|
||||
}
|
||||
|
||||
/// Appends a given string slice onto the end of this `StyledStr`.
|
||||
pub fn push_str(&mut self, msg: &str) {
|
||||
self.0.push_str(msg);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn trim_end(&mut self) {
|
||||
self.0 = self.0.trim_end().to_owned();
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn replace_newline_var(&mut self) {
|
||||
self.0 = self.0.replace("{n}", "\n");
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn indent(&mut self, initial: &str, trailing: &str) {
|
||||
self.0.insert_str(0, initial);
|
||||
|
||||
let mut line_sep = "\n".to_owned();
|
||||
line_sep.push_str(trailing);
|
||||
self.0 = self.0.replace('\n', &line_sep);
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "wrap_help"), feature = "help"))]
|
||||
pub(crate) fn wrap(&mut self, _hard_width: usize) {}
|
||||
|
||||
#[cfg(feature = "wrap_help")]
|
||||
pub(crate) fn wrap(&mut self, hard_width: usize) {
|
||||
let mut new = String::with_capacity(self.0.len());
|
||||
|
||||
let mut last = 0;
|
||||
let mut wrapper = crate::output::textwrap::wrap_algorithms::LineWrapper::new(hard_width);
|
||||
for content in self.iter_text() {
|
||||
// Preserve styling
|
||||
let current = content.as_ptr() as usize - self.0.as_str().as_ptr() as usize;
|
||||
if last != current {
|
||||
new.push_str(&self.0.as_str()[last..current]);
|
||||
}
|
||||
last = current + content.len();
|
||||
|
||||
for (i, line) in content.split_inclusive('\n').enumerate() {
|
||||
if 0 < i {
|
||||
// reset char count on newline, skipping the start as we might have carried
|
||||
// over from a prior block of styled text
|
||||
wrapper.reset();
|
||||
}
|
||||
let line = crate::output::textwrap::word_separators::find_words_ascii_space(line)
|
||||
.collect::<Vec<_>>();
|
||||
new.extend(wrapper.wrap(line));
|
||||
}
|
||||
}
|
||||
if last != self.0.len() {
|
||||
new.push_str(&self.0.as_str()[last..]);
|
||||
}
|
||||
new = new.trim_end().to_owned();
|
||||
|
||||
self.0 = new;
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn display_width(&self) -> usize {
|
||||
let mut width = 0;
|
||||
for c in self.iter_text() {
|
||||
width += crate::output::display_width(c);
|
||||
}
|
||||
width
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn as_styled_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
pub(crate) fn iter_text(&self) -> impl Iterator<Item = &str> {
|
||||
anstream::adapter::strip_str(&self.0)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "color"))]
|
||||
pub(crate) fn iter_text(&self) -> impl Iterator<Item = &str> {
|
||||
[self.0.as_str()].into_iter()
|
||||
}
|
||||
|
||||
pub(crate) fn push_styled(&mut self, other: &Self) {
|
||||
self.0.push_str(&other.0);
|
||||
}
|
||||
|
||||
pub(crate) fn write_to(&self, buffer: &mut dyn std::io::Write) -> std::io::Result<()> {
|
||||
ok!(buffer.write_all(self.0.as_bytes()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for &'_ StyledStr {
|
||||
fn default() -> Self {
|
||||
static DEFAULT: StyledStr = StyledStr::new();
|
||||
&DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for StyledStr {
|
||||
fn from(name: String) -> Self {
|
||||
Self(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ String> for StyledStr {
|
||||
fn from(name: &'_ String) -> Self {
|
||||
let mut styled = Self::new();
|
||||
styled.push_str(name);
|
||||
styled
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for StyledStr {
|
||||
fn from(name: &'static str) -> Self {
|
||||
let mut styled = Self::new();
|
||||
styled.push_str(name);
|
||||
styled
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static str> for StyledStr {
|
||||
fn from(name: &'_ &'static str) -> Self {
|
||||
Self::from(*name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cow<'static, str>> for StyledStr {
|
||||
fn from(cow: Cow<'static, str>) -> Self {
|
||||
match cow {
|
||||
Cow::Borrowed(s) => Self::from(s),
|
||||
Cow::Owned(s) => Self::from(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Write for StyledStr {
|
||||
#[inline]
|
||||
fn write_str(&mut self, s: &str) -> Result<(), std::fmt::Error> {
|
||||
self.0.push_str(s);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_char(&mut self, c: char) -> Result<(), std::fmt::Error> {
|
||||
self.0.push(c);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Color-unaware printing. Never uses coloring.
|
||||
impl std::fmt::Display for StyledStr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for part in self.iter_text() {
|
||||
part.fmt(f)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "wrap_help")]
|
||||
mod wrap_tests {
|
||||
use super::*;
|
||||
|
||||
use snapbox::assert_data_eq;
|
||||
use snapbox::str;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "wrap_help")]
|
||||
fn wrap_unstyled() {
|
||||
let style = anstyle::Style::new();
|
||||
let input = format!(
|
||||
"{style}12345{style:#} {style}12345{style:#} {style}12345{style:#} {style}12345{style:#}"
|
||||
);
|
||||
let mut actual = StyledStr::new();
|
||||
actual.push_string(input);
|
||||
actual.wrap(20);
|
||||
assert_data_eq!(
|
||||
actual.ansi().to_string(),
|
||||
str![[r#"
|
||||
12345 12345 12345
|
||||
12345
|
||||
"#]]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "wrap_help")]
|
||||
fn wrap_styled() {
|
||||
let style = anstyle::Style::new().bold();
|
||||
let input = format!(
|
||||
"{style}12345{style:#} {style}12345{style:#} {style}12345{style:#} {style}12345{style:#}"
|
||||
);
|
||||
let mut actual = StyledStr::new();
|
||||
actual.push_string(input);
|
||||
actual.wrap(20);
|
||||
assert_data_eq!(
|
||||
actual.ansi().to_string(),
|
||||
str![[r#"
|
||||
[1m12345[0m [1m12345[0m [1m12345[0m [1m
|
||||
12345[0m
|
||||
"#]]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn from_cow_borrowed() {
|
||||
let cow = Cow::Borrowed("hello");
|
||||
let styled = StyledStr::from(cow);
|
||||
assert_eq!(styled, StyledStr::from("hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_cow_owned() {
|
||||
let cow = Cow::Owned("world".to_owned());
|
||||
let styled = StyledStr::from(cow);
|
||||
assert_eq!(styled, StyledStr::from("world"));
|
||||
}
|
||||
}
|
||||
220
third_party/crates/clap_builder-4.6.7/src/builder/styling.rs
vendored
Normal file
220
third_party/crates/clap_builder-4.6.7/src/builder/styling.rs
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
//! Terminal [`Styles`] for help and error output
|
||||
|
||||
pub use anstyle::*;
|
||||
|
||||
/// Terminal styling definitions
|
||||
///
|
||||
/// See also [`Command::styles`][crate::Command::styles].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// clap v3 styling
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::styling::*;
|
||||
/// let styles = Styles::styled()
|
||||
/// .header(AnsiColor::Yellow.on_default())
|
||||
/// .usage(AnsiColor::Green.on_default())
|
||||
/// .literal(AnsiColor::Green.on_default())
|
||||
/// .placeholder(AnsiColor::Green.on_default());
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(missing_copy_implementations)] // Large enough type that I want an explicit `clone()` for now
|
||||
pub struct Styles {
|
||||
header: Style,
|
||||
error: Style,
|
||||
usage: Style,
|
||||
literal: Style,
|
||||
placeholder: Style,
|
||||
valid: Style,
|
||||
invalid: Style,
|
||||
context: Style,
|
||||
context_value: Option<Style>,
|
||||
}
|
||||
|
||||
impl Styles {
|
||||
/// No terminal styling
|
||||
pub const fn plain() -> Self {
|
||||
Self {
|
||||
header: Style::new(),
|
||||
error: Style::new(),
|
||||
usage: Style::new(),
|
||||
literal: Style::new(),
|
||||
placeholder: Style::new(),
|
||||
valid: Style::new(),
|
||||
invalid: Style::new(),
|
||||
context: Style::new(),
|
||||
context_value: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Default terminal styling
|
||||
pub const fn styled() -> Self {
|
||||
#[cfg(feature = "color")]
|
||||
{
|
||||
Self {
|
||||
header: Style::new().bold().underline(),
|
||||
error: Style::new()
|
||||
.fg_color(Some(Color::Ansi(AnsiColor::Red)))
|
||||
.bold(),
|
||||
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))),
|
||||
context: Style::new(),
|
||||
context_value: None,
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "color"))]
|
||||
{
|
||||
Self::plain()
|
||||
}
|
||||
}
|
||||
|
||||
/// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading]
|
||||
#[inline]
|
||||
pub const fn header(mut self, style: Style) -> Self {
|
||||
self.header = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Error heading
|
||||
#[inline]
|
||||
pub const fn error(mut self, style: Style) -> Self {
|
||||
self.error = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Usage heading
|
||||
#[inline]
|
||||
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: 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: Style) -> Self {
|
||||
self.placeholder = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Highlight suggested usage
|
||||
#[inline]
|
||||
pub const fn valid(mut self, style: Style) -> Self {
|
||||
self.valid = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Highlight invalid usage
|
||||
#[inline]
|
||||
pub const fn invalid(mut self, style: Style) -> Self {
|
||||
self.invalid = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Highlight all specified contexts, e.g. `[default: false]`
|
||||
///
|
||||
/// To specialize the style of the value within the context, see [`Styles::context_value`]
|
||||
#[inline]
|
||||
pub const fn context(mut self, style: Style) -> Self {
|
||||
self.context = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Highlight values within all of the context, e.g. the `false` in `[default: false]`
|
||||
///
|
||||
/// If not explicitly set, falls back to `context`'s style.
|
||||
#[inline]
|
||||
pub const fn context_value(mut self, style: Style) -> Self {
|
||||
self.context_value = Some(style);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Reflection
|
||||
impl Styles {
|
||||
/// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading]
|
||||
#[inline(always)]
|
||||
pub const fn get_header(&self) -> &Style {
|
||||
&self.header
|
||||
}
|
||||
|
||||
/// Error heading
|
||||
#[inline(always)]
|
||||
pub const fn get_error(&self) -> &Style {
|
||||
&self.error
|
||||
}
|
||||
|
||||
/// Usage heading
|
||||
#[inline(always)]
|
||||
pub const fn get_usage(&self) -> &Style {
|
||||
&self.usage
|
||||
}
|
||||
|
||||
/// Literal command-line syntax, e.g. `--help`
|
||||
#[inline(always)]
|
||||
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) -> &Style {
|
||||
&self.placeholder
|
||||
}
|
||||
|
||||
/// Highlight suggested usage
|
||||
#[inline(always)]
|
||||
pub const fn get_valid(&self) -> &Style {
|
||||
&self.valid
|
||||
}
|
||||
|
||||
/// Highlight invalid usage
|
||||
#[inline(always)]
|
||||
pub const fn get_invalid(&self) -> &Style {
|
||||
&self.invalid
|
||||
}
|
||||
|
||||
/// Highlight all specified contexts, e.g. `[default: false]`
|
||||
///
|
||||
/// To specialize the style of the value within the context, see [`Styles::context_value`]
|
||||
#[inline(always)]
|
||||
pub const fn get_context(&self) -> &Style {
|
||||
&self.context
|
||||
}
|
||||
|
||||
/// Highlight values within all of the context, e.g. the `false` in `[default: false]`
|
||||
///
|
||||
/// If not explicitly set, falls back to `context`'s style.
|
||||
#[inline(always)]
|
||||
pub const fn get_context_value(&self) -> &Style {
|
||||
match &self.context_value {
|
||||
Some(s) => s,
|
||||
None => &self.context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl super::AppExt for Styles {}
|
||||
|
||||
impl Default for Styles {
|
||||
fn default() -> Self {
|
||||
Self::styled()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for &'_ Styles {
|
||||
fn default() -> Self {
|
||||
const STYLES: Styles = Styles::styled();
|
||||
&STYLES
|
||||
}
|
||||
}
|
||||
58
third_party/crates/clap_builder-4.6.7/src/builder/tests.rs
vendored
Normal file
58
third_party/crates/clap_builder-4.6.7/src/builder/tests.rs
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
use crate::Arg;
|
||||
use crate::Command;
|
||||
|
||||
#[test]
|
||||
fn propagate_version() {
|
||||
let mut cmd = Command::new("test")
|
||||
.propagate_version(true)
|
||||
.version("1.1")
|
||||
.subcommand(Command::new("sub1"));
|
||||
cmd._propagate();
|
||||
assert_eq!(
|
||||
cmd.get_subcommands().next().unwrap().get_version(),
|
||||
Some("1.1")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn global_setting() {
|
||||
let mut cmd = Command::new("test")
|
||||
.disable_version_flag(true)
|
||||
.subcommand(Command::new("subcmd"));
|
||||
cmd._propagate();
|
||||
assert!(
|
||||
cmd.get_subcommands()
|
||||
.find(|s| s.get_name() == "subcmd")
|
||||
.unwrap()
|
||||
.is_disable_version_flag_set()
|
||||
);
|
||||
}
|
||||
|
||||
// This test will *fail to compile* if Command is not Send + Sync
|
||||
#[test]
|
||||
fn app_send_sync() {
|
||||
fn foo<T: Send + Sync>(_: T) {}
|
||||
foo(Command::new("test"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_2090() {
|
||||
let mut cmd = Command::new("cmd")
|
||||
.disable_version_flag(true)
|
||||
.subcommand(Command::new("sub"));
|
||||
cmd._build_self(false);
|
||||
|
||||
assert!(
|
||||
cmd.get_subcommands()
|
||||
.next()
|
||||
.unwrap()
|
||||
.is_disable_version_flag_set()
|
||||
);
|
||||
}
|
||||
|
||||
// This test will *fail to compile* if Arg is not Send + Sync
|
||||
#[test]
|
||||
fn arg_send_sync() {
|
||||
fn foo<T: Send + Sync>(_: T) {}
|
||||
foo(Arg::new("test"));
|
||||
}
|
||||
93
third_party/crates/clap_builder-4.6.7/src/builder/value_hint.rs
vendored
Normal file
93
third_party/crates/clap_builder-4.6.7/src/builder/value_hint.rs
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
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 the `clap_complete` crate for completion script generation.
|
||||
///
|
||||
/// Overview of which hints are supported by which shell:
|
||||
///
|
||||
/// | 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.
|
||||
#[derive(Debug, Default, PartialEq, Eq, Hash, Copy, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub enum ValueHint {
|
||||
/// Default value if hint is not specified. Follows shell default behavior, which is usually
|
||||
/// auto-completing filenames.
|
||||
#[default]
|
||||
Unknown,
|
||||
/// None of the hints below apply. Disables shell completion for this argument.
|
||||
Other,
|
||||
/// Any existing path.
|
||||
AnyPath,
|
||||
/// Path to a file.
|
||||
FilePath,
|
||||
/// Path to a directory.
|
||||
DirPath,
|
||||
/// Path to an executable file.
|
||||
ExecutablePath,
|
||||
/// Name of a command, without arguments. May be relative to PATH, or full path to executable.
|
||||
CommandName,
|
||||
/// A single string containing a command and its arguments.
|
||||
CommandString,
|
||||
/// Capture the remaining arguments as a command name and arguments for that command. This is
|
||||
/// common when writing shell wrappers that execute another command, for example `sudo` or `env`.
|
||||
///
|
||||
/// This hint is special, the argument must be a positional argument and have
|
||||
/// [`.num_args(1..)`] and Command must use [`Command::trailing_var_arg(true)`]. The result is that the
|
||||
/// command line `my_app ls -la /` will be parsed as `["ls", "-la", "/"]` and clap won't try to
|
||||
/// parse the `-la` argument itself.
|
||||
///
|
||||
/// [`Command::trailing_var_arg(true)`]: crate::Command::trailing_var_arg
|
||||
/// [`.num_args(1..)`]: crate::Arg::num_args()
|
||||
CommandWithArguments,
|
||||
/// Name of a local operating system user.
|
||||
Username,
|
||||
/// Host name of a computer.
|
||||
/// Shells usually parse `/etc/hosts` and `.ssh/known_hosts` to complete hostnames.
|
||||
Hostname,
|
||||
/// Complete web address.
|
||||
Url,
|
||||
/// Email address.
|
||||
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> {
|
||||
Ok(match &*s.to_ascii_lowercase() {
|
||||
"unknown" => Self::Unknown,
|
||||
"other" => Self::Other,
|
||||
"anypath" => Self::AnyPath,
|
||||
"filepath" => Self::FilePath,
|
||||
"dirpath" => Self::DirPath,
|
||||
"executablepath" => Self::ExecutablePath,
|
||||
"commandname" => Self::CommandName,
|
||||
"commandstring" => Self::CommandString,
|
||||
"commandwitharguments" => Self::CommandWithArguments,
|
||||
"username" => Self::Username,
|
||||
"hostname" => Self::Hostname,
|
||||
"url" => Self::Url,
|
||||
"emailaddress" => Self::EmailAddress,
|
||||
_ => return Err(format!("unknown ValueHint: `{s}`")),
|
||||
})
|
||||
}
|
||||
}
|
||||
2696
third_party/crates/clap_builder-4.6.7/src/builder/value_parser.rs
vendored
Normal file
2696
third_party/crates/clap_builder-4.6.7/src/builder/value_parser.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
453
third_party/crates/clap_builder-4.6.7/src/derive.rs
vendored
Normal file
453
third_party/crates/clap_builder-4.6.7/src/derive.rs
vendored
Normal file
@@ -0,0 +1,453 @@
|
||||
//! This module contains traits that are usable with the `#[derive(...)]`
|
||||
//! macros in `clap_derive`.
|
||||
|
||||
use crate::builder::PossibleValue;
|
||||
use crate::{ArgMatches, Command, Error};
|
||||
use std::convert::Infallible;
|
||||
|
||||
use std::ffi::OsString;
|
||||
|
||||
/// Parse command-line arguments into `Self`.
|
||||
///
|
||||
/// The primary one-stop-shop trait used to create an instance of a `clap`
|
||||
/// [`Command`], conduct the parsing, and turn the resulting [`ArgMatches`] back
|
||||
/// into concrete instance of the user struct.
|
||||
///
|
||||
/// This trait is primarily a convenience on top of [`FromArgMatches`] +
|
||||
/// [`CommandFactory`] which uses those two underlying traits to build the two
|
||||
/// fundamental functions `parse` which uses the `std::env::args_os` iterator,
|
||||
/// and `parse_from` which allows the consumer to supply the iterator (along
|
||||
/// with fallible options for each).
|
||||
///
|
||||
/// See also [`Subcommand`] and [`Args`].
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** Deriving requires the `derive` feature flag
|
||||
///
|
||||
/// </div>
|
||||
pub trait Parser: FromArgMatches + CommandFactory + Sized {
|
||||
/// 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)
|
||||
.map_err(format_error::<Self>);
|
||||
match res {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
// Since this is more of a development-time error, we aren't doing as fancy of a quit
|
||||
// as `get_matches`
|
||||
e.exit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse from `std::env::args_os()`, return Err on error.
|
||||
fn try_parse() -> Result<Self, Error> {
|
||||
let mut matches = ok!(<Self as CommandFactory>::command().try_get_matches());
|
||||
<Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>)
|
||||
}
|
||||
|
||||
/// Parse from iterator, [exit][Error::exit] on error.
|
||||
fn parse_from<I, T>(itr: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<OsString> + Clone,
|
||||
{
|
||||
let mut matches = <Self as CommandFactory>::command().get_matches_from(itr);
|
||||
let res = <Self as FromArgMatches>::from_arg_matches_mut(&mut matches)
|
||||
.map_err(format_error::<Self>);
|
||||
match res {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
// Since this is more of a development-time error, we aren't doing as fancy of a quit
|
||||
// as `get_matches_from`
|
||||
e.exit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse from iterator, return Err on error.
|
||||
fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<OsString> + Clone,
|
||||
{
|
||||
let mut matches = ok!(<Self as CommandFactory>::command().try_get_matches_from(itr));
|
||||
<Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>)
|
||||
}
|
||||
|
||||
/// Update from iterator, [exit][Error::exit] on error.
|
||||
///
|
||||
/// Unlike [`Parser::parse`], this works with an existing instance of `self`.
|
||||
/// The assumption is that all required fields are already provided and any [`Args`] or
|
||||
/// [`Subcommand`]s provided by the user will modify only what is specified.
|
||||
fn update_from<I, T>(&mut self, itr: I)
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<OsString> + Clone,
|
||||
{
|
||||
let mut matches = <Self as CommandFactory>::command_for_update().get_matches_from(itr);
|
||||
let res = <Self as FromArgMatches>::update_from_arg_matches_mut(self, &mut matches)
|
||||
.map_err(format_error::<Self>);
|
||||
if let Err(e) = res {
|
||||
// Since this is more of a development-time error, we aren't doing as fancy of a quit
|
||||
// as `get_matches_from`
|
||||
e.exit()
|
||||
}
|
||||
}
|
||||
|
||||
/// Update from iterator, return Err on error.
|
||||
fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<OsString> + Clone,
|
||||
{
|
||||
let mut matches =
|
||||
ok!(<Self as CommandFactory>::command_for_update().try_get_matches_from(itr));
|
||||
<Self as FromArgMatches>::update_from_arg_matches_mut(self, &mut matches)
|
||||
.map_err(format_error::<Self>)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a [`Command`] relevant for a user-defined container.
|
||||
///
|
||||
/// Derived as part of [`Parser`].
|
||||
pub trait CommandFactory: Sized {
|
||||
/// Build a [`Command`] that can instantiate `Self`.
|
||||
///
|
||||
/// See [`FromArgMatches::from_arg_matches_mut`] for instantiating `Self`.
|
||||
fn command() -> Command;
|
||||
/// Build a [`Command`] that can update `self`.
|
||||
///
|
||||
/// See [`FromArgMatches::update_from_arg_matches_mut`] for updating `self`.
|
||||
fn command_for_update() -> Command;
|
||||
}
|
||||
|
||||
/// Converts an instance of [`ArgMatches`] to a user-defined container.
|
||||
///
|
||||
/// Derived as part of [`Parser`], [`Args`], and [`Subcommand`].
|
||||
pub trait FromArgMatches: Sized {
|
||||
/// Instantiate `Self` from [`ArgMatches`], parsing the arguments as needed.
|
||||
///
|
||||
/// Motivation: If our application had two CLI options, `--name
|
||||
/// <STRING>` and the flag `--debug`, we may create a struct as follows:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "derive")] {
|
||||
/// struct Context {
|
||||
/// name: String,
|
||||
/// debug: bool
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// We then need to convert the `ArgMatches` that `clap` generated into our struct.
|
||||
/// `from_arg_matches` serves as the equivalent of:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "derive")] {
|
||||
/// # use clap::ArgMatches;
|
||||
/// # struct Context {
|
||||
/// # name: String,
|
||||
/// # debug: bool
|
||||
/// # }
|
||||
/// impl From<ArgMatches> for Context {
|
||||
/// fn from(m: ArgMatches) -> Self {
|
||||
/// Context {
|
||||
/// name: m.get_one::<String>("name").unwrap().clone(),
|
||||
/// debug: m.get_flag("debug"),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error>;
|
||||
|
||||
/// Instantiate `Self` from [`ArgMatches`], parsing the arguments as needed.
|
||||
///
|
||||
/// Motivation: If our application had two CLI options, `--name
|
||||
/// <STRING>` and the flag `--debug`, we may create a struct as follows:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "derive")] {
|
||||
/// struct Context {
|
||||
/// name: String,
|
||||
/// debug: bool
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// We then need to convert the `ArgMatches` that `clap` generated into our struct.
|
||||
/// `from_arg_matches_mut` serves as the equivalent of:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "derive")] {
|
||||
/// # use clap::ArgMatches;
|
||||
/// # struct Context {
|
||||
/// # name: String,
|
||||
/// # debug: bool
|
||||
/// # }
|
||||
/// impl From<ArgMatches> for Context {
|
||||
/// fn from(m: ArgMatches) -> Self {
|
||||
/// Context {
|
||||
/// name: m.get_one::<String>("name").unwrap().to_string(),
|
||||
/// debug: m.get_flag("debug"),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
|
||||
Self::from_arg_matches(matches)
|
||||
}
|
||||
|
||||
/// Assign values from `ArgMatches` to `self`.
|
||||
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error>;
|
||||
|
||||
/// Assign values from `ArgMatches` to `self`.
|
||||
fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
|
||||
self.update_from_arg_matches(matches)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a set of arguments into a user-defined container.
|
||||
///
|
||||
/// Implementing this trait lets a parent container delegate argument parsing behavior to `Self`.
|
||||
/// with:
|
||||
/// - `#[command(flatten)] args: ChildArgs`: Attribute can only be used with struct fields that impl
|
||||
/// `Args`.
|
||||
/// - `Variant(ChildArgs)`: No attribute is used with enum variants that impl `Args`.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** Deriving requires the `derive` feature flag
|
||||
///
|
||||
/// </div>
|
||||
pub trait Args: FromArgMatches + Sized {
|
||||
/// Report the [`ArgGroup::id`][crate::ArgGroup::id] for this set of arguments
|
||||
fn group_id() -> Option<crate::Id> {
|
||||
None
|
||||
}
|
||||
/// Append to [`Command`] so it can instantiate `Self` via
|
||||
/// [`FromArgMatches::from_arg_matches_mut`]
|
||||
///
|
||||
/// This is used to implement `#[command(flatten)]`
|
||||
///
|
||||
/// See also [`CommandFactory::command`].
|
||||
fn augment_args(cmd: Command) -> Command;
|
||||
/// Append to [`Command`] so it can instantiate `self` via
|
||||
/// [`FromArgMatches::update_from_arg_matches_mut`]
|
||||
///
|
||||
/// This is used to implement `#[command(flatten)]`
|
||||
///
|
||||
/// See also [`CommandFactory::command_for_update`].
|
||||
fn augment_args_for_update(cmd: Command) -> Command;
|
||||
}
|
||||
|
||||
/// Parse a sub-command into a user-defined enum.
|
||||
///
|
||||
/// Implementing this trait lets a parent container delegate subcommand behavior to `Self`.
|
||||
/// with:
|
||||
/// - `#[command(subcommand)] field: SubCmd`: Attribute can be used with either struct fields or enum
|
||||
/// variants that impl `Subcommand`.
|
||||
/// - `#[command(flatten)] Variant(SubCmd)`: Attribute can only be used with enum variants that impl
|
||||
/// `Subcommand`.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** Deriving requires the `derive` feature flag
|
||||
///
|
||||
/// </div>
|
||||
pub trait Subcommand: FromArgMatches + Sized {
|
||||
/// Append to [`Command`] so it can instantiate `Self` via
|
||||
/// [`FromArgMatches::from_arg_matches_mut`]
|
||||
///
|
||||
/// This is used to implement `#[command(flatten)]`
|
||||
///
|
||||
/// See also [`CommandFactory::command`].
|
||||
fn augment_subcommands(cmd: Command) -> Command;
|
||||
/// Append to [`Command`] so it can instantiate `self` via
|
||||
/// [`FromArgMatches::update_from_arg_matches_mut`]
|
||||
///
|
||||
/// This is used to implement `#[command(flatten)]`
|
||||
///
|
||||
/// See also [`CommandFactory::command_for_update`].
|
||||
fn augment_subcommands_for_update(cmd: Command) -> Command;
|
||||
/// Test whether `Self` can parse a specific subcommand
|
||||
fn has_subcommand(name: &str) -> bool;
|
||||
}
|
||||
|
||||
/// Parse arguments into enums.
|
||||
///
|
||||
/// When deriving [`Parser`], a field whose type implements `ValueEnum` can have the attribute
|
||||
/// `#[arg(value_enum)]` which will
|
||||
/// - Call [`EnumValueParser`][crate::builder::EnumValueParser]
|
||||
/// - Allowing using the `#[arg(default_value_t)]` attribute without implementing `Display`.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** Deriving requires the `derive` feature flag
|
||||
///
|
||||
/// </div>
|
||||
pub trait ValueEnum: Sized + Clone {
|
||||
/// All possible argument values, in display order.
|
||||
fn value_variants<'a>() -> &'a [Self];
|
||||
|
||||
/// Parse an argument into `Self`.
|
||||
fn from_str(input: &str, ignore_case: bool) -> Result<Self, String> {
|
||||
Self::value_variants()
|
||||
.iter()
|
||||
.find(|v| {
|
||||
v.to_possible_value()
|
||||
.expect("ValueEnum::value_variants contains only values with a corresponding ValueEnum::to_possible_value")
|
||||
.matches(input, ignore_case)
|
||||
})
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("invalid variant: {input}"))
|
||||
}
|
||||
|
||||
/// The canonical argument value.
|
||||
///
|
||||
/// The value is `None` for skipped variants.
|
||||
fn to_possible_value(&self) -> Option<PossibleValue>;
|
||||
}
|
||||
|
||||
impl<T: Parser> Parser for Box<T> {
|
||||
fn parse() -> Self {
|
||||
Self::new(<T as Parser>::parse())
|
||||
}
|
||||
|
||||
fn try_parse() -> Result<Self, Error> {
|
||||
<T as Parser>::try_parse().map(Self::new)
|
||||
}
|
||||
|
||||
fn parse_from<I, It>(itr: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = It>,
|
||||
It: Into<OsString> + Clone,
|
||||
{
|
||||
Self::new(<T as Parser>::parse_from(itr))
|
||||
}
|
||||
|
||||
fn try_parse_from<I, It>(itr: I) -> Result<Self, Error>
|
||||
where
|
||||
I: IntoIterator<Item = It>,
|
||||
It: Into<OsString> + Clone,
|
||||
{
|
||||
<T as Parser>::try_parse_from(itr).map(Self::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CommandFactory> CommandFactory for Box<T> {
|
||||
fn command() -> Command {
|
||||
<T as CommandFactory>::command()
|
||||
}
|
||||
fn command_for_update() -> Command {
|
||||
<T as CommandFactory>::command_for_update()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromArgMatches> FromArgMatches for Box<T> {
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
|
||||
<T as FromArgMatches>::from_arg_matches(matches).map(Self::new)
|
||||
}
|
||||
fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
|
||||
<T as FromArgMatches>::from_arg_matches_mut(matches).map(Self::new)
|
||||
}
|
||||
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
|
||||
<T as FromArgMatches>::update_from_arg_matches(self, matches)
|
||||
}
|
||||
fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
|
||||
<T as FromArgMatches>::update_from_arg_matches_mut(self, matches)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Args> Args for Box<T> {
|
||||
fn augment_args(cmd: Command) -> Command {
|
||||
<T as Args>::augment_args(cmd)
|
||||
}
|
||||
fn augment_args_for_update(cmd: Command) -> Command {
|
||||
<T as Args>::augment_args_for_update(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Subcommand> Subcommand for Box<T> {
|
||||
fn augment_subcommands(cmd: Command) -> Command {
|
||||
<T as Subcommand>::augment_subcommands(cmd)
|
||||
}
|
||||
fn augment_subcommands_for_update(cmd: Command) -> Command {
|
||||
<T as Subcommand>::augment_subcommands_for_update(cmd)
|
||||
}
|
||||
fn has_subcommand(name: &str) -> bool {
|
||||
<T as Subcommand>::has_subcommand(name)
|
||||
}
|
||||
}
|
||||
|
||||
fn format_error<I: CommandFactory>(err: Error) -> Error {
|
||||
let mut cmd = I::command();
|
||||
err.format(&mut cmd)
|
||||
}
|
||||
|
||||
impl FromArgMatches for () {
|
||||
fn from_arg_matches(_matches: &ArgMatches) -> Result<Self, Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_from_arg_matches(&mut self, _matches: &ArgMatches) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Args for () {
|
||||
fn augment_args(cmd: Command) -> Command {
|
||||
cmd
|
||||
}
|
||||
|
||||
fn augment_args_for_update(cmd: Command) -> Command {
|
||||
cmd
|
||||
}
|
||||
}
|
||||
|
||||
impl Subcommand for () {
|
||||
fn augment_subcommands(cmd: Command) -> Command {
|
||||
cmd
|
||||
}
|
||||
|
||||
fn augment_subcommands_for_update(cmd: Command) -> Command {
|
||||
cmd
|
||||
}
|
||||
|
||||
fn has_subcommand(_name: &str) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArgMatches for Infallible {
|
||||
fn from_arg_matches(_matches: &ArgMatches) -> Result<Self, Error> {
|
||||
Err(Error::raw(
|
||||
crate::error::ErrorKind::MissingSubcommand,
|
||||
"a subcommand is required but one was not provided",
|
||||
))
|
||||
}
|
||||
|
||||
fn update_from_arg_matches(&mut self, _matches: &ArgMatches) -> Result<(), Error> {
|
||||
unreachable!(
|
||||
"there will never be an instance of Infallible and thus &mut self can never be called"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Subcommand for Infallible {
|
||||
fn augment_subcommands(cmd: Command) -> Command {
|
||||
cmd
|
||||
}
|
||||
|
||||
fn augment_subcommands_for_update(cmd: Command) -> Command {
|
||||
cmd
|
||||
}
|
||||
|
||||
fn has_subcommand(_name: &str) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
114
third_party/crates/clap_builder-4.6.7/src/error/context.rs
vendored
Normal file
114
third_party/crates/clap_builder-4.6.7/src/error/context.rs
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
/// Semantics for a piece of error information
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[non_exhaustive]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub enum ContextKind {
|
||||
/// The cause of the error
|
||||
InvalidSubcommand,
|
||||
/// The cause of the error
|
||||
InvalidArg,
|
||||
/// Existing arguments
|
||||
PriorArg,
|
||||
/// Accepted subcommands
|
||||
ValidSubcommand,
|
||||
/// Accepted values
|
||||
ValidValue,
|
||||
/// Rejected values
|
||||
InvalidValue,
|
||||
/// Number of values present
|
||||
ActualNumValues,
|
||||
/// Number of allowed values
|
||||
ExpectedNumValues,
|
||||
/// Minimum number of allowed values
|
||||
MinValues,
|
||||
/// Potential fix for the user
|
||||
SuggestedCommand,
|
||||
/// Potential fix for the user
|
||||
SuggestedSubcommand,
|
||||
/// Potential fix for the user
|
||||
SuggestedArg,
|
||||
/// Potential fix for the user
|
||||
SuggestedValue,
|
||||
/// Trailing argument
|
||||
TrailingArg,
|
||||
/// Potential fix for the user
|
||||
Suggested,
|
||||
/// A usage string
|
||||
Usage,
|
||||
/// An opaque message to the user
|
||||
Custom,
|
||||
}
|
||||
|
||||
impl ContextKind {
|
||||
/// End-user description of the error case, where relevant
|
||||
pub fn as_str(self) -> Option<&'static str> {
|
||||
match self {
|
||||
Self::InvalidSubcommand => Some("Invalid Subcommand"),
|
||||
Self::InvalidArg => Some("Invalid Argument"),
|
||||
Self::PriorArg => Some("Prior Argument"),
|
||||
Self::ValidSubcommand => Some("Valid Subcommand"),
|
||||
Self::ValidValue => Some("Valid Value"),
|
||||
Self::InvalidValue => Some("Invalid Value"),
|
||||
Self::ActualNumValues => Some("Actual Number of Values"),
|
||||
Self::ExpectedNumValues => Some("Expected Number of Values"),
|
||||
Self::MinValues => Some("Minimum Number of Values"),
|
||||
Self::SuggestedCommand => Some("Suggested Command"),
|
||||
Self::SuggestedSubcommand => Some("Suggested Subcommand"),
|
||||
Self::SuggestedArg => Some("Suggested Argument"),
|
||||
Self::SuggestedValue => Some("Suggested Value"),
|
||||
Self::TrailingArg => Some("Trailing Argument"),
|
||||
Self::Suggested => Some("Suggested"),
|
||||
Self::Usage => None,
|
||||
Self::Custom => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ContextKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.as_str().unwrap_or_default().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// A piece of error information
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub enum ContextValue {
|
||||
/// [`ContextKind`] is self-sufficient, no additional information needed
|
||||
None,
|
||||
/// A single value
|
||||
Bool(bool),
|
||||
/// A single value
|
||||
String(String),
|
||||
/// Many values
|
||||
Strings(Vec<String>),
|
||||
/// A single value
|
||||
StyledStr(crate::builder::StyledStr),
|
||||
/// many value
|
||||
StyledStrs(Vec<crate::builder::StyledStr>),
|
||||
/// A single value
|
||||
Number(isize),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ContextValue {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::None => "".fmt(f),
|
||||
Self::Bool(v) => v.fmt(f),
|
||||
Self::String(v) => v.fmt(f),
|
||||
Self::Strings(v) => v.join(", ").fmt(f),
|
||||
Self::StyledStr(v) => v.fmt(f),
|
||||
Self::StyledStrs(v) => {
|
||||
for (i, v) in v.iter().enumerate() {
|
||||
if i != 0 {
|
||||
", ".fmt(f)?;
|
||||
}
|
||||
v.fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Self::Number(v) => v.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
494
third_party/crates/clap_builder-4.6.7/src/error/format.rs
vendored
Normal file
494
third_party/crates/clap_builder-4.6.7/src/error/format.rs
vendored
Normal file
@@ -0,0 +1,494 @@
|
||||
#![allow(missing_copy_implementations)]
|
||||
#![allow(missing_debug_implementations)]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(dead_code))]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(unused_imports))]
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::ArgAction;
|
||||
use crate::builder::Command;
|
||||
use crate::builder::StyledStr;
|
||||
use crate::builder::Styles;
|
||||
#[cfg(feature = "error-context")]
|
||||
use crate::error::ContextKind;
|
||||
#[cfg(feature = "error-context")]
|
||||
use crate::error::ContextValue;
|
||||
use crate::error::ErrorKind;
|
||||
use crate::output::TAB;
|
||||
use crate::util::Escape;
|
||||
|
||||
/// Defines how to format an error for displaying to the user
|
||||
pub trait ErrorFormatter: Sized {
|
||||
/// Stylize the error for the terminal
|
||||
fn format_error(error: &crate::error::Error<Self>) -> StyledStr;
|
||||
}
|
||||
|
||||
/// Report [`ErrorKind`]
|
||||
///
|
||||
/// No context is included.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** Consider removing the `error-context` default feature if using this to remove all
|
||||
/// overhead for [`RichFormatter`].
|
||||
///
|
||||
/// </div>
|
||||
#[non_exhaustive]
|
||||
pub struct KindFormatter;
|
||||
|
||||
impl ErrorFormatter for KindFormatter {
|
||||
fn format_error(error: &crate::error::Error<Self>) -> StyledStr {
|
||||
use std::fmt::Write as _;
|
||||
let styles = &error.inner.styles;
|
||||
|
||||
let mut styled = StyledStr::new();
|
||||
start_error(&mut styled, styles);
|
||||
if let Some(msg) = error.kind().as_str() {
|
||||
styled.push_str(msg);
|
||||
} else if let Some(source) = error.inner.source.as_ref() {
|
||||
let _ = write!(styled, "{source}");
|
||||
} else {
|
||||
styled.push_str("unknown cause");
|
||||
}
|
||||
styled.push_str("\n");
|
||||
styled
|
||||
}
|
||||
}
|
||||
|
||||
/// Richly formatted error context
|
||||
///
|
||||
/// This follows the [rustc diagnostic style guide](https://rustc-dev-guide.rust-lang.org/diagnostics.html#suggestion-style-guide).
|
||||
#[non_exhaustive]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub struct RichFormatter;
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
impl ErrorFormatter for RichFormatter {
|
||||
fn format_error(error: &crate::error::Error<Self>) -> StyledStr {
|
||||
use std::fmt::Write as _;
|
||||
let styles = &error.inner.styles;
|
||||
let valid = &styles.get_valid();
|
||||
|
||||
let mut styled = StyledStr::new();
|
||||
start_error(&mut styled, styles);
|
||||
|
||||
if !write_dynamic_context(error, &mut styled, styles) {
|
||||
if let Some(msg) = error.kind().as_str() {
|
||||
styled.push_str(msg);
|
||||
} else if let Some(source) = error.inner.source.as_ref() {
|
||||
let _ = write!(styled, "{source}");
|
||||
} else {
|
||||
styled.push_str("unknown cause");
|
||||
}
|
||||
}
|
||||
|
||||
let mut suggested = false;
|
||||
if let Some(valid) = error.get(ContextKind::SuggestedSubcommand) {
|
||||
styled.push_str("\n");
|
||||
if !suggested {
|
||||
styled.push_str("\n");
|
||||
suggested = true;
|
||||
}
|
||||
did_you_mean(&mut styled, styles, "subcommand", valid);
|
||||
}
|
||||
if let Some(valid) = error.get(ContextKind::SuggestedArg) {
|
||||
styled.push_str("\n");
|
||||
if !suggested {
|
||||
styled.push_str("\n");
|
||||
suggested = true;
|
||||
}
|
||||
did_you_mean(&mut styled, styles, "argument", valid);
|
||||
}
|
||||
if let Some(valid) = error.get(ContextKind::SuggestedValue) {
|
||||
styled.push_str("\n");
|
||||
if !suggested {
|
||||
styled.push_str("\n");
|
||||
suggested = true;
|
||||
}
|
||||
did_you_mean(&mut styled, styles, "value", valid);
|
||||
}
|
||||
let suggestions = error.get(ContextKind::Suggested);
|
||||
if let Some(ContextValue::StyledStrs(suggestions)) = suggestions {
|
||||
if !suggested {
|
||||
styled.push_str("\n");
|
||||
}
|
||||
for suggestion in suggestions {
|
||||
let _ = write!(styled, "\n{TAB}{valid}tip:{valid:#} ",);
|
||||
styled.push_styled(suggestion);
|
||||
}
|
||||
}
|
||||
|
||||
let usage = error.get(ContextKind::Usage);
|
||||
if let Some(ContextValue::StyledStr(usage)) = usage {
|
||||
put_usage(&mut styled, usage);
|
||||
}
|
||||
|
||||
try_help(&mut styled, styles, error.inner.help_flag.as_deref());
|
||||
|
||||
styled
|
||||
}
|
||||
}
|
||||
|
||||
fn start_error(styled: &mut StyledStr, styles: &Styles) {
|
||||
use std::fmt::Write as _;
|
||||
let error = &styles.get_error();
|
||||
let _ = write!(styled, "{error}error:{error:#} ");
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[cfg(feature = "error-context")]
|
||||
fn write_dynamic_context(
|
||||
error: &crate::error::Error,
|
||||
styled: &mut StyledStr,
|
||||
styles: &Styles,
|
||||
) -> bool {
|
||||
use std::fmt::Write as _;
|
||||
let valid = styles.get_valid();
|
||||
let invalid = styles.get_invalid();
|
||||
let literal = styles.get_literal();
|
||||
|
||||
match error.kind() {
|
||||
ErrorKind::ArgumentConflict => {
|
||||
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}{invalid_arg}{invalid:#}' cannot be used multiple times",
|
||||
);
|
||||
} else {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"the argument '{invalid}{invalid_arg}{invalid:#}' cannot be used with",
|
||||
);
|
||||
}
|
||||
} else if let Some(ContextValue::String(invalid_arg)) =
|
||||
error.get(ContextKind::InvalidSubcommand)
|
||||
{
|
||||
let _ = write!(
|
||||
styled,
|
||||
"the subcommand '{invalid}{invalid_arg}{invalid:#}' cannot be used with",
|
||||
);
|
||||
} else {
|
||||
styled.push_str(error.kind().as_str().unwrap());
|
||||
}
|
||||
|
||||
if let Some(prior_arg) = prior_arg {
|
||||
match prior_arg {
|
||||
ContextValue::Strings(values) => {
|
||||
styled.push_str(":");
|
||||
for v in values {
|
||||
let _ = write!(styled, "\n{TAB}{invalid}{v}{invalid:#}",);
|
||||
}
|
||||
}
|
||||
ContextValue::String(value) => {
|
||||
let _ = write!(styled, " '{invalid}{value}{invalid:#}'",);
|
||||
}
|
||||
_ => {
|
||||
styled.push_str(" one or more of the other specified arguments");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
ErrorKind::NoEquals => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
if let Some(ContextValue::String(invalid_arg)) = invalid_arg {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"equal sign is needed when assigning values to '{invalid}{invalid_arg}{invalid:#}'",
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::InvalidValue => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
let invalid_value = error.get(ContextKind::InvalidValue);
|
||||
if let (
|
||||
Some(ContextValue::String(invalid_arg)),
|
||||
Some(ContextValue::String(invalid_value)),
|
||||
) = (invalid_arg, invalid_value)
|
||||
{
|
||||
if invalid_value.is_empty() {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"a value is required for '{invalid}{invalid_arg}{invalid:#}' but none was supplied",
|
||||
);
|
||||
} else {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"invalid value '{invalid}{invalid_value}{invalid:#}' for '{literal}{invalid_arg}{literal:#}'",
|
||||
);
|
||||
}
|
||||
|
||||
let values = error.get(ContextKind::ValidValue);
|
||||
write_values_list("possible values", styled, valid, values);
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::InvalidSubcommand => {
|
||||
let invalid_sub = error.get(ContextKind::InvalidSubcommand);
|
||||
if let Some(ContextValue::String(invalid_sub)) = invalid_sub {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"unrecognized subcommand '{invalid}{invalid_sub}{invalid:#}'",
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::MissingRequiredArgument => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
if let Some(ContextValue::Strings(invalid_arg)) = invalid_arg {
|
||||
styled.push_str("the following required arguments were not provided:");
|
||||
for v in invalid_arg {
|
||||
let _ = write!(styled, "\n{TAB}{valid}{v}{valid:#}",);
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::MissingSubcommand => {
|
||||
let invalid_sub = error.get(ContextKind::InvalidSubcommand);
|
||||
if let Some(ContextValue::String(invalid_sub)) = invalid_sub {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"'{invalid}{invalid_sub}{invalid:#}' requires a subcommand but one was not provided",
|
||||
);
|
||||
let values = error.get(ContextKind::ValidSubcommand);
|
||||
write_values_list("subcommands", styled, valid, values);
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::InvalidUtf8 => false,
|
||||
ErrorKind::TooManyValues => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
let invalid_value = error.get(ContextKind::InvalidValue);
|
||||
if let (
|
||||
Some(ContextValue::String(invalid_arg)),
|
||||
Some(ContextValue::String(invalid_value)),
|
||||
) = (invalid_arg, invalid_value)
|
||||
{
|
||||
let _ = write!(
|
||||
styled,
|
||||
"unexpected value '{invalid}{invalid_value}{invalid:#}' for '{literal}{invalid_arg}{literal:#}' found; no more were expected",
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::TooFewValues => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
let actual_num_values = error.get(ContextKind::ActualNumValues);
|
||||
let min_values = error.get(ContextKind::MinValues);
|
||||
if let (
|
||||
Some(ContextValue::String(invalid_arg)),
|
||||
Some(ContextValue::Number(actual_num_values)),
|
||||
Some(ContextValue::Number(min_values)),
|
||||
) = (invalid_arg, actual_num_values, min_values)
|
||||
{
|
||||
let were_provided = singular_or_plural(*actual_num_values as usize);
|
||||
let _ = write!(
|
||||
styled,
|
||||
"{valid}{min_values}{valid:#} values required by '{literal}{invalid_arg}{literal:#}'; only {invalid}{actual_num_values}{invalid:#}{were_provided}",
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::ValueValidation => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
let invalid_value = error.get(ContextKind::InvalidValue);
|
||||
if let (
|
||||
Some(ContextValue::String(invalid_arg)),
|
||||
Some(ContextValue::String(invalid_value)),
|
||||
) = (invalid_arg, invalid_value)
|
||||
{
|
||||
let _ = write!(
|
||||
styled,
|
||||
"invalid value '{invalid}{invalid_value}{invalid:#}' for '{literal}{invalid_arg}{literal:#}'",
|
||||
);
|
||||
if let Some(source) = error.inner.source.as_deref() {
|
||||
let _ = write!(styled, ": {source}");
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::WrongNumberOfValues => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
let actual_num_values = error.get(ContextKind::ActualNumValues);
|
||||
let num_values = error.get(ContextKind::ExpectedNumValues);
|
||||
if let (
|
||||
Some(ContextValue::String(invalid_arg)),
|
||||
Some(ContextValue::Number(actual_num_values)),
|
||||
Some(ContextValue::Number(num_values)),
|
||||
) = (invalid_arg, actual_num_values, num_values)
|
||||
{
|
||||
let were_provided = singular_or_plural(*actual_num_values as usize);
|
||||
let _ = write!(
|
||||
styled,
|
||||
"{valid}{num_values}{valid:#} values required for '{literal}{invalid_arg}{literal:#}' but {invalid}{actual_num_values}{invalid:#}{were_provided}",
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::UnknownArgument => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
if let Some(ContextValue::String(invalid_arg)) = invalid_arg {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"unexpected argument '{invalid}{invalid_arg}{invalid:#}' found",
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::DisplayHelp
|
||||
| ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
|
||||
| ErrorKind::DisplayVersion
|
||||
| ErrorKind::Io
|
||||
| ErrorKind::Format => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
fn write_values_list(
|
||||
list_name: &'static str,
|
||||
styled: &mut StyledStr,
|
||||
valid: &anstyle::Style,
|
||||
possible_values: Option<&ContextValue>,
|
||||
) {
|
||||
use std::fmt::Write as _;
|
||||
if let Some(ContextValue::Strings(possible_values)) = possible_values {
|
||||
if !possible_values.is_empty() {
|
||||
let _ = write!(styled, "\n{TAB}[{list_name}: ");
|
||||
|
||||
for (idx, val) in possible_values.iter().enumerate() {
|
||||
if idx > 0 {
|
||||
styled.push_str(", ");
|
||||
}
|
||||
let _ = write!(styled, "{valid}{}{valid:#}", Escape(val));
|
||||
}
|
||||
|
||||
styled.push_str("]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn format_error_message(
|
||||
message: &str,
|
||||
styles: &Styles,
|
||||
cmd: Option<&Command>,
|
||||
usage: Option<&StyledStr>,
|
||||
) -> StyledStr {
|
||||
let mut styled = StyledStr::new();
|
||||
start_error(&mut styled, styles);
|
||||
styled.push_str(message);
|
||||
if let Some(usage) = usage {
|
||||
put_usage(&mut styled, usage);
|
||||
}
|
||||
if let Some(cmd) = cmd {
|
||||
try_help(&mut styled, styles, get_help_flag(cmd).as_deref());
|
||||
}
|
||||
styled
|
||||
}
|
||||
|
||||
/// Returns the singular or plural form on the verb to be based on the argument's value.
|
||||
fn singular_or_plural(n: usize) -> &'static str {
|
||||
if n > 1 {
|
||||
" were provided"
|
||||
} else {
|
||||
" was provided"
|
||||
}
|
||||
}
|
||||
|
||||
fn put_usage(styled: &mut StyledStr, usage: &StyledStr) {
|
||||
styled.push_str("\n\n");
|
||||
styled.push_styled(usage);
|
||||
}
|
||||
|
||||
pub(crate) fn get_help_flag(cmd: &Command) -> Option<Cow<'static, str>> {
|
||||
if !cmd.is_disable_help_flag_set() {
|
||||
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(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 _;
|
||||
let literal = &styles.get_literal();
|
||||
let _ = write!(
|
||||
styled,
|
||||
"\n\nFor more information, try '{literal}{help}{literal:#}'.\n",
|
||||
);
|
||||
} else {
|
||||
styled.push_str("\n");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
fn did_you_mean(styled: &mut StyledStr, styles: &Styles, context: &str, possibles: &ContextValue) {
|
||||
use std::fmt::Write as _;
|
||||
|
||||
let valid = &styles.get_valid();
|
||||
let _ = write!(styled, "{TAB}{valid}tip:{valid:#}",);
|
||||
if let ContextValue::String(possible) = possibles {
|
||||
let _ = write!(
|
||||
styled,
|
||||
" a similar {context} exists: '{valid}{possible}{valid:#}'",
|
||||
);
|
||||
} else if let ContextValue::Strings(possibles) = possibles {
|
||||
if possibles.len() == 1 {
|
||||
let _ = write!(styled, " a similar {context} exists: ",);
|
||||
} else {
|
||||
let _ = write!(styled, " some similar {context}s exist: ",);
|
||||
}
|
||||
for (i, possible) in possibles.iter().enumerate() {
|
||||
if i != 0 {
|
||||
styled.push_str(", ");
|
||||
}
|
||||
let _ = write!(styled, "'{valid}{possible}{valid:#}'",);
|
||||
}
|
||||
}
|
||||
}
|
||||
365
third_party/crates/clap_builder-4.6.7/src/error/kind.rs
vendored
Normal file
365
third_party/crates/clap_builder-4.6.7/src/error/kind.rs
vendored
Normal file
@@ -0,0 +1,365 @@
|
||||
/// Command line argument parser kind of error
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[non_exhaustive]
|
||||
pub enum ErrorKind {
|
||||
/// Occurs when an [`Arg`][crate::Arg] has a set of possible values,
|
||||
/// and the user provides a value which isn't in that set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("speed")
|
||||
/// .value_parser(["fast", "slow"]))
|
||||
/// .try_get_matches_from(vec!["prog", "other"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||
/// ```
|
||||
InvalidValue,
|
||||
|
||||
/// Occurs when a user provides a flag, option, argument or subcommand which isn't defined.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(arg!(--flag "some flag"))
|
||||
/// .try_get_matches_from(vec!["prog", "--other"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::UnknownArgument);
|
||||
/// ```
|
||||
UnknownArgument,
|
||||
|
||||
/// Occurs when the user provides an unrecognized [`Subcommand`] which meets the threshold for
|
||||
/// being similar enough to an existing subcommand.
|
||||
/// If it doesn't meet the threshold, or the 'suggestions' feature is disabled,
|
||||
/// the more general [`UnknownArgument`] error is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "suggestions")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, };
|
||||
/// let result = Command::new("prog")
|
||||
/// .subcommand(Command::new("config")
|
||||
/// .about("Used for configuration")
|
||||
/// .arg(Arg::new("config_file")
|
||||
/// .help("The configuration file to use")))
|
||||
/// .try_get_matches_from(vec!["prog", "confi"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidSubcommand);
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`Subcommand`]: crate::Subcommand
|
||||
/// [`UnknownArgument`]: ErrorKind::UnknownArgument
|
||||
InvalidSubcommand,
|
||||
|
||||
/// Occurs when the user doesn't use equals for an option that requires equal
|
||||
/// sign to provide values.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
|
||||
/// let res = Command::new("prog")
|
||||
/// .arg(Arg::new("color")
|
||||
/// .action(ArgAction::Set)
|
||||
/// .require_equals(true)
|
||||
/// .long("color"))
|
||||
/// .try_get_matches_from(vec!["prog", "--color", "red"]);
|
||||
/// assert!(res.is_err());
|
||||
/// assert_eq!(res.unwrap_err().kind(), ErrorKind::NoEquals);
|
||||
/// ```
|
||||
NoEquals,
|
||||
|
||||
/// Occurs when the user provides a value for an argument with a custom validation and the
|
||||
/// value fails that validation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, value_parser};
|
||||
/// fn is_numeric(val: &str) -> Result<(), String> {
|
||||
/// match val.parse::<i64>() {
|
||||
/// Ok(..) => Ok(()),
|
||||
/// Err(..) => Err(String::from("value wasn't a number!")),
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("num")
|
||||
/// .value_parser(value_parser!(u8)))
|
||||
/// .try_get_matches_from(vec!["prog", "NotANumber"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::ValueValidation);
|
||||
/// ```
|
||||
ValueValidation,
|
||||
|
||||
/// Occurs when a user provides more values for an argument than were defined by setting
|
||||
/// [`Arg::num_args`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("arg")
|
||||
/// .num_args(1..=2))
|
||||
/// .try_get_matches_from(vec!["prog", "too", "many", "values"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooManyValues);
|
||||
/// ```
|
||||
/// [`Arg::num_args`]: crate::Arg::num_args()
|
||||
TooManyValues,
|
||||
|
||||
/// Occurs when the user provides fewer values for an argument than were defined by setting
|
||||
/// [`Arg::num_args`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("some_opt")
|
||||
/// .long("opt")
|
||||
/// .num_args(3..))
|
||||
/// .try_get_matches_from(vec!["prog", "--opt", "too", "few"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooFewValues);
|
||||
/// ```
|
||||
/// [`Arg::num_args`]: crate::Arg::num_args()
|
||||
TooFewValues,
|
||||
|
||||
/// Occurs when the user provides a different number of values for an argument than what's
|
||||
/// been defined by setting [`Arg::num_args`] or than was implicitly set by
|
||||
/// [`Arg::value_names`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("some_opt")
|
||||
/// .long("opt")
|
||||
/// .action(ArgAction::Set)
|
||||
/// .num_args(2))
|
||||
/// .try_get_matches_from(vec!["prog", "--opt", "wrong"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::WrongNumberOfValues);
|
||||
/// ```
|
||||
///
|
||||
/// [`Arg::num_args`]: crate::Arg::num_args()
|
||||
/// [`Arg::value_names`]: crate::Arg::value_names()
|
||||
WrongNumberOfValues,
|
||||
|
||||
/// Occurs when the user provides two values which conflict with each other and can't be used
|
||||
/// together.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .long("debug")
|
||||
/// .action(ArgAction::SetTrue)
|
||||
/// .conflicts_with("color"))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .long("color")
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .try_get_matches_from(vec!["prog", "--debug", "--color"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
ArgumentConflict,
|
||||
|
||||
/// Occurs when the user does not provide one or more required arguments.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .required(true))
|
||||
/// .try_get_matches_from(vec!["prog"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
|
||||
/// ```
|
||||
MissingRequiredArgument,
|
||||
|
||||
/// Occurs when a subcommand is required (as defined by [`Command::subcommand_required`]),
|
||||
/// but the user does not provide one.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, error::ErrorKind};
|
||||
/// let err = Command::new("prog")
|
||||
/// .subcommand_required(true)
|
||||
/// .subcommand(Command::new("test"))
|
||||
/// .try_get_matches_from(vec![
|
||||
/// "myprog",
|
||||
/// ]);
|
||||
/// assert!(err.is_err());
|
||||
/// assert_eq!(err.unwrap_err().kind(), ErrorKind::MissingSubcommand);
|
||||
/// # ;
|
||||
/// ```
|
||||
///
|
||||
/// [`Command::subcommand_required`]: crate::Command::subcommand_required
|
||||
MissingSubcommand,
|
||||
|
||||
/// Occurs when the user provides a value containing invalid UTF-8.
|
||||
///
|
||||
/// To allow arbitrary data
|
||||
/// - Set [`Arg::value_parser(value_parser!(OsString))`][crate::Arg::value_parser] for argument values
|
||||
/// - Set [`Command::external_subcommand_value_parser`] for external-subcommand
|
||||
/// values
|
||||
///
|
||||
/// # Platform Specific
|
||||
///
|
||||
/// Non-Windows platforms only (such as Linux, Unix, OSX, etc.)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(unix)] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
|
||||
/// # use std::os::unix::ffi::OsStringExt;
|
||||
/// # use std::ffi::OsString;
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("utf8")
|
||||
/// .short('u')
|
||||
/// .action(ArgAction::Set))
|
||||
/// .try_get_matches_from(vec![OsString::from("myprog"),
|
||||
/// OsString::from("-u"),
|
||||
/// OsString::from_vec(vec![0xE9])]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidUtf8);
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`Command::external_subcommand_value_parser`]: crate::Command::external_subcommand_value_parser
|
||||
InvalidUtf8,
|
||||
|
||||
/// Not a true "error" as it means `--help` or similar was used.
|
||||
/// The help message will be sent to `stdout`.
|
||||
///
|
||||
/// **Note**: If the help is displayed due to an error (such as missing subcommands) it will
|
||||
/// be sent to `stderr` instead of `stdout`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .try_get_matches_from(vec!["prog", "--help"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
DisplayHelp,
|
||||
|
||||
/// Occurs when either an argument or a [`Subcommand`] is required, as defined by
|
||||
/// [`Command::arg_required_else_help`] , but the user did not provide
|
||||
/// one.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, };
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg_required_else_help(true)
|
||||
/// .subcommand(Command::new("config")
|
||||
/// .about("Used for configuration")
|
||||
/// .arg(Arg::new("config_file")
|
||||
/// .help("The configuration file to use")))
|
||||
/// .try_get_matches_from(vec!["prog"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand);
|
||||
/// ```
|
||||
///
|
||||
/// [`Subcommand`]: crate::Subcommand
|
||||
/// [`Command::arg_required_else_help`]: crate::Command::arg_required_else_help
|
||||
DisplayHelpOnMissingArgumentOrSubcommand,
|
||||
|
||||
/// Not a true "error" as it means `--version` or similar was used.
|
||||
/// The message will be sent to `stdout`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .version("3.0")
|
||||
/// .try_get_matches_from(vec!["prog", "--version"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::DisplayVersion);
|
||||
/// ```
|
||||
DisplayVersion,
|
||||
|
||||
/// Represents an [I/O error].
|
||||
/// Can occur when writing to `stderr` or `stdout` or reading a configuration file.
|
||||
///
|
||||
/// [I/O error]: std::io::Error
|
||||
Io,
|
||||
|
||||
/// Represents a [Format error] (which is a part of [`Display`]).
|
||||
/// Typically caused by writing to `stderr` or `stdout`.
|
||||
///
|
||||
/// [`Display`]: std::fmt::Display
|
||||
/// [Format error]: std::fmt::Error
|
||||
Format,
|
||||
}
|
||||
|
||||
impl ErrorKind {
|
||||
/// End-user description of the error case, where relevant
|
||||
pub fn as_str(self) -> Option<&'static str> {
|
||||
match self {
|
||||
Self::InvalidValue => Some("one of the values isn't valid for an argument"),
|
||||
Self::UnknownArgument => Some("unexpected argument found"),
|
||||
Self::InvalidSubcommand => Some("unrecognized subcommand"),
|
||||
Self::NoEquals => Some("equal is needed when assigning values to one of the arguments"),
|
||||
Self::ValueValidation => Some("invalid value for one of the arguments"),
|
||||
Self::TooManyValues => Some("unexpected value for an argument found"),
|
||||
Self::TooFewValues => Some("more values required for an argument"),
|
||||
Self::WrongNumberOfValues => Some("too many or too few values for an argument"),
|
||||
Self::ArgumentConflict => {
|
||||
Some("an argument cannot be used with one or more of the other specified arguments")
|
||||
}
|
||||
Self::MissingRequiredArgument => {
|
||||
Some("one or more required arguments were not provided")
|
||||
}
|
||||
Self::MissingSubcommand => Some("a subcommand is required but one was not provided"),
|
||||
Self::InvalidUtf8 => Some("invalid UTF-8 was detected in one or more arguments"),
|
||||
Self::DisplayHelp => None,
|
||||
Self::DisplayHelpOnMissingArgumentOrSubcommand => None,
|
||||
Self::DisplayVersion => None,
|
||||
Self::Io => None,
|
||||
Self::Format => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ErrorKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.as_str().unwrap_or_default().fmt(f)
|
||||
}
|
||||
}
|
||||
946
third_party/crates/clap_builder-4.6.7/src/error/mod.rs
vendored
Normal file
946
third_party/crates/clap_builder-4.6.7/src/error/mod.rs
vendored
Normal file
@@ -0,0 +1,946 @@
|
||||
//! Error reporting
|
||||
|
||||
#![cfg_attr(not(feature = "error-context"), allow(dead_code))]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(unused_imports))]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(unused_variables))]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(unused_mut))]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(clippy::let_and_return))]
|
||||
|
||||
// Std
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
convert::From,
|
||||
error,
|
||||
fmt::{self, Debug, Display, Formatter},
|
||||
io,
|
||||
result::Result as StdResult,
|
||||
};
|
||||
|
||||
// Internal
|
||||
use crate::Command;
|
||||
use crate::builder::StyledStr;
|
||||
use crate::builder::Styles;
|
||||
use crate::output::fmt::Colorizer;
|
||||
use crate::output::fmt::Stream;
|
||||
use crate::parser::features::suggestions;
|
||||
use crate::util::FlatMap;
|
||||
use crate::util::{SUCCESS_CODE, USAGE_CODE, color::ColorChoice};
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
mod context;
|
||||
mod format;
|
||||
mod kind;
|
||||
|
||||
pub use format::ErrorFormatter;
|
||||
pub use format::KindFormatter;
|
||||
pub use kind::ErrorKind;
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
pub use context::ContextKind;
|
||||
#[cfg(feature = "error-context")]
|
||||
pub use context::ContextValue;
|
||||
#[cfg(feature = "error-context")]
|
||||
pub use format::RichFormatter;
|
||||
|
||||
#[cfg(not(feature = "error-context"))]
|
||||
pub use KindFormatter as DefaultFormatter;
|
||||
#[cfg(feature = "error-context")]
|
||||
pub use RichFormatter as DefaultFormatter;
|
||||
|
||||
/// Short hand for [`Result`] type
|
||||
///
|
||||
/// [`Result`]: std::result::Result
|
||||
pub type Result<T, E = Error> = StdResult<T, E>;
|
||||
|
||||
/// Command Line Argument Parser Error
|
||||
///
|
||||
/// See [`Command::error`] to create an error.
|
||||
///
|
||||
/// [`Command::error`]: crate::Command::error
|
||||
pub struct Error<F: ErrorFormatter = DefaultFormatter> {
|
||||
inner: Box<ErrorInner>,
|
||||
phantom: std::marker::PhantomData<F>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ErrorInner {
|
||||
kind: ErrorKind,
|
||||
#[cfg(feature = "error-context")]
|
||||
context: FlatMap<ContextKind, ContextValue>,
|
||||
message: Option<Message>,
|
||||
source: Option<Box<dyn error::Error + Send + Sync>>,
|
||||
help_flag: Option<Cow<'static, str>>,
|
||||
styles: Styles,
|
||||
color_when: ColorChoice,
|
||||
color_help_when: ColorChoice,
|
||||
backtrace: Option<Backtrace>,
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> Error<F> {
|
||||
/// Create an unformatted error
|
||||
///
|
||||
/// This is for you need to pass the error up to
|
||||
/// a place that has access to the `Command` at which point you can call [`Error::format`].
|
||||
///
|
||||
/// Prefer [`Command::error`] for generating errors.
|
||||
///
|
||||
/// [`Command::error`]: crate::Command::error
|
||||
pub fn raw(kind: ErrorKind, message: impl Display) -> Self {
|
||||
Self::new(kind).set_message(message.to_string())
|
||||
}
|
||||
|
||||
/// Format the existing message with the Command's context
|
||||
#[must_use]
|
||||
pub fn format(mut self, cmd: &mut Command) -> Self {
|
||||
cmd._build_self(false);
|
||||
let usage = cmd.render_usage_();
|
||||
if let Some(message) = self.inner.message.as_mut() {
|
||||
message.format(cmd, usage);
|
||||
}
|
||||
self.with_cmd(cmd)
|
||||
}
|
||||
|
||||
/// Create an error with a pre-defined message
|
||||
///
|
||||
/// See also
|
||||
/// - [`Error::insert`]
|
||||
/// - [`Error::with_cmd`]
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "error-context")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::error::ErrorKind;
|
||||
/// # use clap::error::ContextKind;
|
||||
/// # use clap::error::ContextValue;
|
||||
///
|
||||
/// let cmd = clap::Command::new("prog");
|
||||
///
|
||||
/// let mut err = clap::Error::new(ErrorKind::ValueValidation)
|
||||
/// .with_cmd(&cmd);
|
||||
/// err.insert(ContextKind::InvalidArg, ContextValue::String("--foo".to_owned()));
|
||||
/// err.insert(ContextKind::InvalidValue, ContextValue::String("bar".to_owned()));
|
||||
///
|
||||
/// err.print();
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn new(kind: ErrorKind) -> Self {
|
||||
Self {
|
||||
inner: Box::new(ErrorInner {
|
||||
kind,
|
||||
#[cfg(feature = "error-context")]
|
||||
context: FlatMap::new(),
|
||||
message: None,
|
||||
source: None,
|
||||
help_flag: None,
|
||||
styles: Styles::plain(),
|
||||
color_when: ColorChoice::Never,
|
||||
color_help_when: ColorChoice::Never,
|
||||
backtrace: Backtrace::new(),
|
||||
}),
|
||||
phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply [`Command`]'s formatting to the error
|
||||
///
|
||||
/// Generally, this is used with [`Error::new`]
|
||||
pub fn with_cmd(self, cmd: &Command) -> Self {
|
||||
self.set_styles(cmd.get_styles().clone())
|
||||
.set_color(cmd.get_color())
|
||||
.set_colored_help(cmd.color_help())
|
||||
.set_help_flag(format::get_help_flag(cmd))
|
||||
}
|
||||
|
||||
/// Apply an alternative formatter to the error
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// # use clap::error::KindFormatter;
|
||||
/// let cmd = Command::new("foo")
|
||||
/// .arg(Arg::new("input").required(true));
|
||||
/// let matches = cmd
|
||||
/// .try_get_matches_from(["foo", "input.txt"])
|
||||
/// .map_err(|e| e.apply::<KindFormatter>())
|
||||
/// .unwrap_or_else(|e| e.exit());
|
||||
/// ```
|
||||
pub fn apply<EF: ErrorFormatter>(self) -> Error<EF> {
|
||||
Error {
|
||||
inner: self.inner,
|
||||
phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of error for programmatic processing
|
||||
pub fn kind(&self) -> ErrorKind {
|
||||
self.inner.kind
|
||||
}
|
||||
|
||||
/// Additional information to further qualify the error
|
||||
#[cfg(feature = "error-context")]
|
||||
pub fn context(&self) -> impl Iterator<Item = (ContextKind, &ContextValue)> {
|
||||
self.inner.context.iter().map(|(k, v)| (*k, v))
|
||||
}
|
||||
|
||||
/// Lookup a piece of context
|
||||
#[inline(never)]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub fn get(&self, kind: ContextKind) -> Option<&ContextValue> {
|
||||
self.inner.context.get(&kind)
|
||||
}
|
||||
|
||||
/// Insert a piece of context
|
||||
///
|
||||
/// If this `ContextKind` is already present, its value is replaced and the old value is returned.
|
||||
#[inline(never)]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub fn insert(&mut self, kind: ContextKind, value: ContextValue) -> Option<ContextValue> {
|
||||
self.inner.context.insert(kind, value)
|
||||
}
|
||||
|
||||
/// Remove a piece of context, return the old value if any
|
||||
///
|
||||
/// The context is currently implemented in a vector, so `remove` takes
|
||||
/// linear time.
|
||||
#[inline(never)]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub fn remove(&mut self, kind: ContextKind) -> Option<ContextValue> {
|
||||
self.inner.context.remove(&kind)
|
||||
}
|
||||
|
||||
/// Should the message be written to `stdout` or not?
|
||||
#[inline]
|
||||
pub fn use_stderr(&self) -> bool {
|
||||
self.stream() == Stream::Stderr
|
||||
}
|
||||
|
||||
pub(crate) fn stream(&self) -> Stream {
|
||||
match self.kind() {
|
||||
ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => Stream::Stdout,
|
||||
_ => Stream::Stderr,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the exit code that `.exit` will exit the process with.
|
||||
///
|
||||
/// When the error's kind would print to `stderr` this returns `2`,
|
||||
/// else it returns `0`.
|
||||
pub fn exit_code(&self) -> i32 {
|
||||
if self.use_stderr() {
|
||||
USAGE_CODE
|
||||
} else {
|
||||
SUCCESS_CODE
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the error and exits.
|
||||
///
|
||||
/// Depending on the error kind, this either prints to `stderr` and exits with a status of `2`
|
||||
/// or prints to `stdout` and exits with a status of `0`.
|
||||
pub fn exit(&self) -> ! {
|
||||
// Swallow broken pipe errors
|
||||
let _ = self.print();
|
||||
std::process::exit(self.exit_code());
|
||||
}
|
||||
|
||||
/// Prints formatted and colored error to `stdout` or `stderr` according to its error kind
|
||||
///
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// use clap::Command;
|
||||
///
|
||||
/// match Command::new("Command").try_get_matches() {
|
||||
/// Ok(matches) => {
|
||||
/// // do_something
|
||||
/// },
|
||||
/// Err(err) => {
|
||||
/// err.print().expect("Error writing Error");
|
||||
/// // do_something
|
||||
/// },
|
||||
/// };
|
||||
/// ```
|
||||
pub fn print(&self) -> io::Result<()> {
|
||||
let style = self.formatted();
|
||||
let color_when = if matches!(
|
||||
self.kind(),
|
||||
ErrorKind::DisplayHelp | ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
|
||||
) {
|
||||
self.inner.color_help_when
|
||||
} else {
|
||||
self.inner.color_when
|
||||
};
|
||||
let c = Colorizer::new(self.stream(), color_when).with_content(style.into_owned());
|
||||
c.print()
|
||||
}
|
||||
|
||||
/// Render the error message to a [`StyledStr`].
|
||||
///
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// use clap::Command;
|
||||
///
|
||||
/// match Command::new("Command").try_get_matches() {
|
||||
/// Ok(matches) => {
|
||||
/// // do_something
|
||||
/// },
|
||||
/// Err(err) => {
|
||||
/// let err = err.render();
|
||||
/// println!("{err}");
|
||||
/// // do_something
|
||||
/// },
|
||||
/// };
|
||||
/// ```
|
||||
pub fn render(&self) -> StyledStr {
|
||||
self.formatted().into_owned()
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn for_app(kind: ErrorKind, cmd: &Command, styled: StyledStr) -> Self {
|
||||
Self::new(kind).set_message(styled).with_cmd(cmd)
|
||||
}
|
||||
|
||||
pub(crate) fn set_message(mut self, message: impl Into<Message>) -> Self {
|
||||
self.inner.message = Some(message.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_source(mut self, source: Box<dyn error::Error + Send + Sync>) -> Self {
|
||||
self.inner.source = Some(source);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_styles(mut self, styles: Styles) -> Self {
|
||||
self.inner.styles = styles;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_color(mut self, color_when: ColorChoice) -> Self {
|
||||
self.inner.color_when = color_when;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_colored_help(mut self, color_help_when: ColorChoice) -> Self {
|
||||
self.inner.color_help_when = color_help_when;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_help_flag(mut self, help_flag: Option<Cow<'static, str>>) -> Self {
|
||||
self.inner.help_flag = help_flag;
|
||||
self
|
||||
}
|
||||
|
||||
/// Does not verify if `ContextKind` is already present
|
||||
#[inline(never)]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub(crate) fn insert_context_unchecked(
|
||||
mut self,
|
||||
kind: ContextKind,
|
||||
value: ContextValue,
|
||||
) -> Self {
|
||||
self.inner.context.insert_unchecked(kind, value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Does not verify if `ContextKind` is already present
|
||||
#[inline(never)]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub(crate) fn extend_context_unchecked<const N: usize>(
|
||||
mut self,
|
||||
context: [(ContextKind, ContextValue); N],
|
||||
) -> Self {
|
||||
self.inner.context.extend_unchecked(context);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn display_help(cmd: &Command, styled: StyledStr) -> Self {
|
||||
Self::for_app(ErrorKind::DisplayHelp, cmd, styled)
|
||||
}
|
||||
|
||||
pub(crate) fn display_help_error(cmd: &Command, styled: StyledStr) -> Self {
|
||||
Self::for_app(
|
||||
ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
|
||||
cmd,
|
||||
styled,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn display_version(cmd: &Command, styled: StyledStr) -> Self {
|
||||
Self::for_app(ErrorKind::DisplayVersion, cmd, styled)
|
||||
}
|
||||
|
||||
pub(crate) fn argument_conflict(
|
||||
cmd: &Command,
|
||||
arg: 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::InvalidArg, ContextValue::String(arg)),
|
||||
(ContextKind::PriorArg, others),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
pub(crate) fn no_equals(cmd: &Command, arg: String, usage: Option<StyledStr>) -> Self {
|
||||
let mut err = Self::new(ErrorKind::NoEquals).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err
|
||||
.extend_context_unchecked([(ContextKind::InvalidArg, ContextValue::String(arg))]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn invalid_value(
|
||||
cmd: &Command,
|
||||
bad_val: String,
|
||||
good_vals: &[String],
|
||||
arg: String,
|
||||
) -> Self {
|
||||
let suggestion = suggestions::did_you_mean(&bad_val, good_vals.iter()).pop();
|
||||
let mut err = Self::new(ErrorKind::InvalidValue).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(ContextKind::InvalidValue, ContextValue::String(bad_val)),
|
||||
(
|
||||
ContextKind::ValidValue,
|
||||
ContextValue::Strings(good_vals.iter().map(|s| (*s).clone()).collect()),
|
||||
),
|
||||
]);
|
||||
if let Some(suggestion) = suggestion {
|
||||
err = err.insert_context_unchecked(
|
||||
ContextKind::SuggestedValue,
|
||||
ContextValue::String(suggestion),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn invalid_subcommand(
|
||||
cmd: &Command,
|
||||
subcmd: String,
|
||||
did_you_mean: Vec<String>,
|
||||
name: String,
|
||||
suggested_trailing_arg: bool,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
use std::fmt::Write as _;
|
||||
let styles = cmd.get_styles();
|
||||
let invalid = &styles.get_invalid();
|
||||
let valid = &styles.get_valid();
|
||||
let mut err = Self::new(ErrorKind::InvalidSubcommand).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
let mut suggestions = vec![];
|
||||
if suggested_trailing_arg {
|
||||
let mut styled_suggestion = StyledStr::new();
|
||||
let _ = write!(
|
||||
styled_suggestion,
|
||||
"to pass '{invalid}{subcmd}{invalid:#}' as a value, use '{valid}{name} -- {subcmd}{valid:#}'",
|
||||
);
|
||||
suggestions.push(styled_suggestion);
|
||||
}
|
||||
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidSubcommand, ContextValue::String(subcmd)),
|
||||
(
|
||||
ContextKind::SuggestedSubcommand,
|
||||
ContextValue::Strings(did_you_mean),
|
||||
),
|
||||
(
|
||||
ContextKind::Suggested,
|
||||
ContextValue::StyledStrs(suggestions),
|
||||
),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn unrecognized_subcommand(
|
||||
cmd: &Command,
|
||||
subcmd: String,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::InvalidSubcommand).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([(
|
||||
ContextKind::InvalidSubcommand,
|
||||
ContextValue::String(subcmd),
|
||||
)]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn missing_required_argument(
|
||||
cmd: &Command,
|
||||
required: Vec<String>,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::MissingRequiredArgument).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([(
|
||||
ContextKind::InvalidArg,
|
||||
ContextValue::Strings(required),
|
||||
)]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn missing_subcommand(
|
||||
cmd: &Command,
|
||||
parent: String,
|
||||
available: Vec<String>,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::MissingSubcommand).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidSubcommand, ContextValue::String(parent)),
|
||||
(
|
||||
ContextKind::ValidSubcommand,
|
||||
ContextValue::Strings(available),
|
||||
),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn invalid_utf8(cmd: &Command, usage: Option<StyledStr>) -> Self {
|
||||
let mut err = Self::new(ErrorKind::InvalidUtf8).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn too_many_values(
|
||||
cmd: &Command,
|
||||
val: String,
|
||||
arg: String,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::TooManyValues).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(ContextKind::InvalidValue, ContextValue::String(val)),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn too_few_values(
|
||||
cmd: &Command,
|
||||
arg: String,
|
||||
min_vals: usize,
|
||||
curr_vals: usize,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::TooFewValues).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(
|
||||
ContextKind::MinValues,
|
||||
ContextValue::Number(min_vals as isize),
|
||||
),
|
||||
(
|
||||
ContextKind::ActualNumValues,
|
||||
ContextValue::Number(curr_vals as isize),
|
||||
),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn value_validation(
|
||||
arg: String,
|
||||
val: String,
|
||||
err: Box<dyn error::Error + Send + Sync>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::ValueValidation).set_source(err);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(ContextKind::InvalidValue, ContextValue::String(val)),
|
||||
]);
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn wrong_number_of_values(
|
||||
cmd: &Command,
|
||||
arg: String,
|
||||
num_vals: usize,
|
||||
curr_vals: usize,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::WrongNumberOfValues).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(
|
||||
ContextKind::ExpectedNumValues,
|
||||
ContextValue::Number(num_vals as isize),
|
||||
),
|
||||
(
|
||||
ContextKind::ActualNumValues,
|
||||
ContextValue::Number(curr_vals as isize),
|
||||
),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn unknown_argument(
|
||||
cmd: &Command,
|
||||
arg: String,
|
||||
did_you_mean: Option<(String, Option<String>)>,
|
||||
suggested_trailing_arg: bool,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
use std::fmt::Write as _;
|
||||
let styles = cmd.get_styles();
|
||||
let invalid = &styles.get_invalid();
|
||||
let valid = &styles.get_valid();
|
||||
let mut err = Self::new(ErrorKind::UnknownArgument).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
let mut suggestions = vec![];
|
||||
if suggested_trailing_arg {
|
||||
let mut styled_suggestion = StyledStr::new();
|
||||
let _ = write!(
|
||||
styled_suggestion,
|
||||
"to pass '{invalid}{arg}{invalid:#}' as a value, use '{valid}-- {arg}{valid:#}'",
|
||||
);
|
||||
suggestions.push(styled_suggestion);
|
||||
}
|
||||
|
||||
err = err
|
||||
.extend_context_unchecked([(ContextKind::InvalidArg, ContextValue::String(arg))]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
match did_you_mean {
|
||||
Some((flag, Some(sub))) => {
|
||||
let mut styled_suggestion = StyledStr::new();
|
||||
let _ = write!(styled_suggestion, "'{valid}{sub} {flag}{valid:#}' exists",);
|
||||
suggestions.push(styled_suggestion);
|
||||
}
|
||||
Some((flag, None)) => {
|
||||
err = err.insert_context_unchecked(
|
||||
ContextKind::SuggestedArg,
|
||||
ContextValue::String(flag),
|
||||
);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
if !suggestions.is_empty() {
|
||||
err = err.insert_context_unchecked(
|
||||
ContextKind::Suggested,
|
||||
ContextValue::StyledStrs(suggestions),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn unnecessary_double_dash(
|
||||
cmd: &Command,
|
||||
arg: String,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
use std::fmt::Write as _;
|
||||
let styles = cmd.get_styles();
|
||||
let invalid = &styles.get_invalid();
|
||||
let valid = &styles.get_valid();
|
||||
let mut err = Self::new(ErrorKind::UnknownArgument).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
let mut styled_suggestion = StyledStr::new();
|
||||
let _ = write!(
|
||||
styled_suggestion,
|
||||
"subcommand '{valid}{arg}{valid:#}' exists; to use it, remove the '{invalid}--{invalid:#}' before it",
|
||||
);
|
||||
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(
|
||||
ContextKind::Suggested,
|
||||
ContextValue::StyledStrs(vec![styled_suggestion]),
|
||||
),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
fn formatted(&self) -> Cow<'_, StyledStr> {
|
||||
if let Some(message) = self.inner.message.as_ref() {
|
||||
message.formatted(&self.inner.styles)
|
||||
} else {
|
||||
let styled = F::format_error(self);
|
||||
Cow::Owned(styled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> From<io::Error> for Error<F> {
|
||||
fn from(e: io::Error) -> Self {
|
||||
Self::raw(ErrorKind::Io, e)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> From<fmt::Error> for Error<F> {
|
||||
fn from(e: fmt::Error) -> Self {
|
||||
Self::raw(ErrorKind::Format, e)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> Debug for Error<F> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> error::Error for Error<F> {
|
||||
#[allow(trivial_casts)]
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
self.inner.source.as_ref().map(|e| e.as_ref() as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> Display for Error<F> {
|
||||
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() {
|
||||
ok!(writeln!(f));
|
||||
ok!(writeln!(f, "Backtrace:"));
|
||||
ok!(writeln!(f, "{backtrace}"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum Message {
|
||||
Raw(String),
|
||||
Formatted(StyledStr),
|
||||
}
|
||||
|
||||
impl Message {
|
||||
fn format(&mut self, cmd: &Command, usage: Option<StyledStr>) {
|
||||
match self {
|
||||
Self::Raw(s) => {
|
||||
let mut message = String::new();
|
||||
std::mem::swap(s, &mut message);
|
||||
|
||||
let styled = format::format_error_message(
|
||||
&message,
|
||||
cmd.get_styles(),
|
||||
Some(cmd),
|
||||
usage.as_ref(),
|
||||
);
|
||||
|
||||
*self = Self::Formatted(styled);
|
||||
}
|
||||
Self::Formatted(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn formatted(&self, styles: &Styles) -> Cow<'_, StyledStr> {
|
||||
match self {
|
||||
Self::Raw(s) => {
|
||||
let styled = format::format_error_message(s, styles, None, None);
|
||||
|
||||
Cow::Owned(styled)
|
||||
}
|
||||
Self::Formatted(s) => Cow::Borrowed(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Message {
|
||||
fn from(inner: String) -> Self {
|
||||
Self::Raw(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StyledStr> for Message {
|
||||
fn from(inner: StyledStr) -> Self {
|
||||
Self::Formatted(inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
#[derive(Debug)]
|
||||
struct Backtrace(backtrace::Backtrace);
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
impl Backtrace {
|
||||
fn new() -> Option<Self> {
|
||||
Some(Self(backtrace::Backtrace::new()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
impl Display for Backtrace {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
// `backtrace::Backtrace` uses `Debug` instead of `Display`
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "debug"))]
|
||||
#[derive(Debug)]
|
||||
struct Backtrace;
|
||||
|
||||
#[cfg(not(feature = "debug"))]
|
||||
impl Backtrace {
|
||||
fn new() -> Option<Self> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "debug"))]
|
||||
impl Display for Backtrace {
|
||||
fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_auto_traits() {
|
||||
static_assertions::assert_impl_all!(Error: Send, Sync, Unpin);
|
||||
}
|
||||
53
third_party/crates/clap_builder-4.6.7/src/lib.rs
vendored
Normal file
53
third_party/crates/clap_builder-4.6.7/src/lib.rs
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright ⓒ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/graphs/contributors).
|
||||
// Licensed under the MIT license
|
||||
// (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.
|
||||
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![forbid(unsafe_code)]
|
||||
#![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`");
|
||||
|
||||
pub use crate::builder::ArgAction;
|
||||
pub use crate::builder::Command;
|
||||
pub use crate::builder::ValueHint;
|
||||
pub use crate::builder::{Arg, ArgGroup};
|
||||
pub use crate::parser::ArgMatches;
|
||||
pub use crate::util::Id;
|
||||
pub use crate::util::color::ColorChoice;
|
||||
|
||||
/// Command Line Argument Parser Error
|
||||
///
|
||||
/// See [`Command::error`] to create an error.
|
||||
///
|
||||
/// [`Command::error`]: crate::Command::error
|
||||
pub type Error = error::Error<error::DefaultFormatter>;
|
||||
|
||||
pub use crate::derive::{Args, CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum};
|
||||
|
||||
#[macro_use]
|
||||
#[allow(missing_docs)]
|
||||
mod macros;
|
||||
|
||||
mod derive;
|
||||
|
||||
pub mod builder;
|
||||
pub mod error;
|
||||
pub mod parser;
|
||||
|
||||
mod mkeymap;
|
||||
mod output;
|
||||
mod util;
|
||||
|
||||
const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
|
||||
report at https://github.com/clap-rs/clap/issues";
|
||||
|
||||
#[doc = include_str!("../README.md")]
|
||||
#[cfg(doctest)]
|
||||
pub struct ReadmeDoctests;
|
||||
603
third_party/crates/clap_builder-4.6.7/src/macros.rs
vendored
Normal file
603
third_party/crates/clap_builder-4.6.7/src/macros.rs
vendored
Normal file
@@ -0,0 +1,603 @@
|
||||
/// Allows you to pull the version from your Cargo.toml at compile time as
|
||||
/// `MAJOR.MINOR.PATCH_PKGVERSION_PRE`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::crate_version;
|
||||
/// # use clap::Command;
|
||||
/// let m = Command::new("cmd")
|
||||
/// .version(crate_version!())
|
||||
/// .get_matches();
|
||||
/// ```
|
||||
#[cfg(feature = "cargo")]
|
||||
#[macro_export]
|
||||
macro_rules! crate_version {
|
||||
() => {
|
||||
env!("CARGO_PKG_VERSION")
|
||||
};
|
||||
}
|
||||
|
||||
/// Allows you to pull the authors for the command from your Cargo.toml at
|
||||
/// compile time in the form:
|
||||
/// `"author1 lastname <author1@example.com>:author2 lastname <author2@example.com>"`
|
||||
///
|
||||
/// You can replace the colons with a custom separator by supplying a
|
||||
/// replacement string, so, for example,
|
||||
/// `crate_authors!(",\n")` would become
|
||||
/// `"author1 lastname <author1@example.com>,\nauthor2 lastname <author2@example.com>,\nauthor3 lastname <author3@example.com>"`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::crate_authors;
|
||||
/// # use clap::Command;
|
||||
/// let m = Command::new("cmd")
|
||||
/// .author(crate_authors!("\n"))
|
||||
/// .get_matches();
|
||||
/// ```
|
||||
#[cfg(feature = "cargo")]
|
||||
#[macro_export]
|
||||
macro_rules! crate_authors {
|
||||
($sep:expr) => {{
|
||||
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: &'static str = &*s;
|
||||
s
|
||||
} else {
|
||||
AUTHORS
|
||||
}
|
||||
}};
|
||||
() => {
|
||||
env!("CARGO_PKG_AUTHORS")
|
||||
};
|
||||
}
|
||||
|
||||
/// Allows you to pull the description from your Cargo.toml at compile time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::crate_description;
|
||||
/// # use clap::Command;
|
||||
/// let m = Command::new("cmd")
|
||||
/// .about(crate_description!())
|
||||
/// .get_matches();
|
||||
/// ```
|
||||
#[cfg(feature = "cargo")]
|
||||
#[macro_export]
|
||||
macro_rules! crate_description {
|
||||
() => {
|
||||
env!("CARGO_PKG_DESCRIPTION")
|
||||
};
|
||||
}
|
||||
|
||||
/// Allows you to pull the name from your Cargo.toml at compile time.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** This macro extracts the name from an environment variable `CARGO_PKG_NAME`.
|
||||
/// When the crate name is set to something different from the package name,
|
||||
/// use environment variables `CARGO_CRATE_NAME` or `CARGO_BIN_NAME`.
|
||||
/// See [the Cargo Book](https://doc.rust-lang.org/cargo/reference/environment-variables.html)
|
||||
/// for more information.
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::crate_name;
|
||||
/// # use clap::Command;
|
||||
/// let m = Command::new(crate_name!())
|
||||
/// .get_matches();
|
||||
/// ```
|
||||
#[cfg(feature = "cargo")]
|
||||
#[macro_export]
|
||||
macro_rules! crate_name {
|
||||
() => {
|
||||
env!("CARGO_PKG_NAME")
|
||||
};
|
||||
}
|
||||
|
||||
/// Allows you to build the `Command` instance from your Cargo.toml at compile time.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** Changing the values in your `Cargo.toml` does not trigger a re-build automatically,
|
||||
/// and therefore won't change the generated output until you recompile.
|
||||
///
|
||||
/// In some cases you can "trick" the compiler into triggering a rebuild when your
|
||||
/// `Cargo.toml` is changed by including this in your `src/main.rs` file
|
||||
/// `include_str!("../Cargo.toml");`
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::command;
|
||||
/// let m = command!().get_matches();
|
||||
/// ```
|
||||
#[cfg(feature = "cargo")]
|
||||
#[macro_export]
|
||||
macro_rules! command {
|
||||
() => {{ $crate::command!($crate::crate_name!()) }};
|
||||
($name:expr) => {{
|
||||
let mut cmd = $crate::Command::new($name).version($crate::crate_version!());
|
||||
|
||||
let author = $crate::crate_authors!();
|
||||
if !author.is_empty() {
|
||||
cmd = cmd.author(author)
|
||||
}
|
||||
|
||||
let about = $crate::crate_description!();
|
||||
if !about.is_empty() {
|
||||
cmd = cmd.about(about)
|
||||
}
|
||||
|
||||
cmd
|
||||
}};
|
||||
}
|
||||
|
||||
/// Requires `cargo` feature flag to be enabled.
|
||||
#[cfg(not(feature = "cargo"))]
|
||||
#[macro_export]
|
||||
macro_rules! command {
|
||||
() => {{
|
||||
compile_error!("`cargo` feature flag is required");
|
||||
}};
|
||||
($name:expr) => {{
|
||||
compile_error!("`cargo` feature flag is required");
|
||||
}};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! arg_impl {
|
||||
( @string $val:ident ) => {
|
||||
stringify!($val)
|
||||
};
|
||||
( @string $val:literal ) => {{
|
||||
let ident_or_string_literal: &str = $val;
|
||||
ident_or_string_literal
|
||||
}};
|
||||
( @string $val:tt ) => {
|
||||
::std::compile_error!("Only identifiers or string literals supported");
|
||||
};
|
||||
( @string ) => {
|
||||
None
|
||||
};
|
||||
|
||||
( @char $val:ident ) => {{
|
||||
let ident_or_char_literal = stringify!($val);
|
||||
debug_assert_eq!(
|
||||
ident_or_char_literal.len(),
|
||||
1,
|
||||
"Single-letter identifier expected, got {ident_or_char_literal}",
|
||||
);
|
||||
ident_or_char_literal.chars().next().unwrap()
|
||||
}};
|
||||
( @char $val:literal ) => {{
|
||||
let ident_or_char_literal: char = $val;
|
||||
ident_or_char_literal
|
||||
}};
|
||||
( @char ) => {{
|
||||
None
|
||||
}};
|
||||
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
--$long:ident
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
|
||||
let mut arg = $arg;
|
||||
let long = $crate::arg_impl! { @string $long };
|
||||
if arg.get_id() == "" {
|
||||
arg = arg.id(long);
|
||||
}
|
||||
let action = $crate::ArgAction::SetTrue;
|
||||
let arg = arg
|
||||
.long(long)
|
||||
.action(action);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
--$long:literal
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
|
||||
let mut arg = $arg;
|
||||
let long = $crate::arg_impl! { @string $long };
|
||||
if arg.get_id() == "" {
|
||||
arg = arg.id(long);
|
||||
}
|
||||
let action = $crate::ArgAction::SetTrue;
|
||||
let arg = arg
|
||||
.long(long)
|
||||
.action(action);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
-$short:ident
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert_eq!($arg.get_long(), None, "Short flags should precede long flags");
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
|
||||
let action = $crate::ArgAction::SetTrue;
|
||||
let arg = $arg
|
||||
.short($crate::arg_impl! { @char $short })
|
||||
.action(action);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
-$short:literal
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert_eq!($arg.get_long(), None, "Short flags should precede long flags");
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
|
||||
let action = $crate::ArgAction::SetTrue;
|
||||
let arg = $arg
|
||||
.short($crate::arg_impl! { @char $short })
|
||||
.action(action);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
<$value_name:ident>
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
|
||||
|
||||
let mut arg = $arg;
|
||||
|
||||
if arg.get_long().is_none() && arg.get_short().is_none() {
|
||||
arg = arg.required(true);
|
||||
}
|
||||
|
||||
let value_name = $crate::arg_impl! { @string $value_name };
|
||||
if arg.get_id() == "" {
|
||||
arg = arg.id(value_name);
|
||||
}
|
||||
let arg = arg
|
||||
.value_name(value_name)
|
||||
.action($crate::ArgAction::Set);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
<$value_name:literal>
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
|
||||
|
||||
let mut arg = $arg;
|
||||
|
||||
if arg.get_long().is_none() && arg.get_short().is_none() {
|
||||
arg = arg.required(true);
|
||||
}
|
||||
|
||||
let value_name = $crate::arg_impl! { @string $value_name };
|
||||
if arg.get_id() == "" {
|
||||
arg = arg.id(value_name);
|
||||
}
|
||||
let arg = arg
|
||||
.value_name(value_name)
|
||||
.action($crate::ArgAction::Set);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
[$value_name:ident]
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
|
||||
|
||||
let mut arg = $arg;
|
||||
|
||||
if arg.get_long().is_none() && arg.get_short().is_none() {
|
||||
arg = arg.required(false);
|
||||
} else {
|
||||
arg = arg.num_args(0..=1);
|
||||
}
|
||||
|
||||
let value_name = $crate::arg_impl! { @string $value_name };
|
||||
if arg.get_id() == "" {
|
||||
arg = arg.id(value_name);
|
||||
}
|
||||
let arg = arg
|
||||
.value_name(value_name)
|
||||
.action($crate::ArgAction::Set);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
[$value_name:literal]
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
|
||||
|
||||
let mut arg = $arg;
|
||||
|
||||
if arg.get_long().is_none() && arg.get_short().is_none() {
|
||||
arg = arg.required(false);
|
||||
} else {
|
||||
arg = arg.num_args(0..=1);
|
||||
}
|
||||
|
||||
let value_name = $crate::arg_impl! { @string $value_name };
|
||||
if arg.get_id() == "" {
|
||||
arg = arg.id(value_name);
|
||||
}
|
||||
let arg = arg
|
||||
.value_name(value_name)
|
||||
.action($crate::ArgAction::Set);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
...
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
let arg = match $arg.get_action() {
|
||||
$crate::ArgAction::Set => {
|
||||
if $arg.get_long().is_none() && $arg.get_short().is_none() {
|
||||
$arg.num_args(1..)
|
||||
// Allow collecting arguments interleaved with flags
|
||||
.action($crate::ArgAction::Append)
|
||||
} else {
|
||||
$arg.action($crate::ArgAction::Append)
|
||||
}
|
||||
},
|
||||
$crate::ArgAction::SetTrue | $crate::ArgAction::Help | $crate::ArgAction::Version => {
|
||||
$arg.action($crate::ArgAction::Count)
|
||||
}
|
||||
action => {
|
||||
panic!("Unexpected action {action:?}")
|
||||
}
|
||||
};
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
$help:literal
|
||||
) => {{
|
||||
$arg.help($help)
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
) => {{
|
||||
$arg
|
||||
}};
|
||||
}
|
||||
|
||||
/// Create an [`Arg`] from a usage string.
|
||||
///
|
||||
/// Allows creation of basic settings for the [`Arg`].
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE**: Not all settings may be set using the usage string method. Some properties are
|
||||
/// only available via the builder pattern.
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Syntax
|
||||
///
|
||||
/// Usage strings typically following the form:
|
||||
///
|
||||
/// ```notrust
|
||||
/// [explicit name] [short] [long] [value names] [...] [help string]
|
||||
/// ```
|
||||
///
|
||||
/// ### Explicit Name
|
||||
///
|
||||
/// The name may be either a bare-word or a string, followed by a `:`, like `name:` or
|
||||
/// `"name":`.
|
||||
///
|
||||
/// *Note:* This is an optional field, if it's omitted the argument will use one of the additional
|
||||
/// fields as the name using the following priority order:
|
||||
///
|
||||
/// 1. Explicit Name
|
||||
/// 2. Long
|
||||
/// 3. Value Name
|
||||
///
|
||||
/// See [`Arg::id`][crate::Arg::id].
|
||||
///
|
||||
/// ### Short
|
||||
///
|
||||
/// A short flag is a `-` followed by either a bare-character or quoted character, like `-f` or
|
||||
/// `-'f'`.
|
||||
///
|
||||
/// See [`Arg::short`][crate::Arg::short].
|
||||
///
|
||||
/// ### Long
|
||||
///
|
||||
/// A long flag is a `--` followed by either a bare-word or a string, like `--foo` or
|
||||
/// `--"foo"`.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** Dashes in the long name (e.g. `--foo-bar`) is not supported and quoting is required
|
||||
/// (e.g. `--"foo-bar"`).
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// See [`Arg::long`][crate::Arg::long].
|
||||
///
|
||||
/// ### Values (Value Notation)
|
||||
///
|
||||
/// This is set by placing bare-word between:
|
||||
/// - `[]` like `[FOO]`
|
||||
/// - Positional argument: optional
|
||||
/// - Named argument: optional value
|
||||
/// - `<>` like `<FOO>`: required
|
||||
///
|
||||
/// See [`Arg::value_name`][crate::Arg::value_name].
|
||||
///
|
||||
/// ### `...`
|
||||
///
|
||||
/// `...` (three consecutive dots/periods) specifies that this argument may occur multiple
|
||||
/// times (not to be confused with multiple values per occurrence).
|
||||
///
|
||||
/// See [`ArgAction::Count`][crate::ArgAction::Count] and [`ArgAction::Append`][crate::ArgAction::Append].
|
||||
///
|
||||
/// ### Help String
|
||||
///
|
||||
/// The help string is denoted between a pair of double quotes `""` and may contain any
|
||||
/// characters.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, arg};
|
||||
/// let cmd = Command::new("prog")
|
||||
/// .args(&[
|
||||
/// arg!(--config <FILE> "a required file for the configuration and no short"),
|
||||
/// arg!(-d --debug ... "turns on debugging information and allows multiples"),
|
||||
/// arg!([input] "an optional input file to use")
|
||||
/// ]);
|
||||
///
|
||||
/// let m = cmd.try_get_matches_from(["prog", "--config", "file.toml"]).unwrap();
|
||||
/// assert_eq!(m.get_one::<String>("config").unwrap(), "file.toml");
|
||||
/// assert_eq!(*m.get_one::<u8>("debug").unwrap(), 0);
|
||||
/// assert_eq!(m.get_one::<String>("input"), None);
|
||||
/// ```
|
||||
/// [`Arg`]: crate::Arg
|
||||
#[macro_export]
|
||||
macro_rules! arg {
|
||||
( -$($tail:tt)+ ) => {{
|
||||
let arg = $crate::Arg::default();
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) -$($tail)+
|
||||
};
|
||||
debug_assert_ne!(arg.get_id(), "", "Without a value or long flag, the `name:` prefix is required");
|
||||
arg
|
||||
}};
|
||||
( $name:ident: $($tail:tt)+ ) => {{
|
||||
let arg = $crate::Arg::new($crate::arg_impl! { @string $name });
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)+
|
||||
};
|
||||
arg
|
||||
}};
|
||||
( $name:literal: $($tail:tt)+ ) => {{
|
||||
let arg = $crate::Arg::new($crate::arg_impl! { @string $name });
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)+
|
||||
};
|
||||
arg
|
||||
}};
|
||||
( $($tail:tt)+ ) => {{
|
||||
let arg = $crate::Arg::default();
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)+
|
||||
};
|
||||
debug_assert_ne!(arg.get_id(), "", "Without a value or long flag, the `name:` prefix is required");
|
||||
arg
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
macro_rules! debug {
|
||||
($($arg:tt)*) => ({
|
||||
use std::fmt::Write as _;
|
||||
let hint = anstyle::Style::new().dimmed();
|
||||
|
||||
let module_path = module_path!();
|
||||
let body = format!($($arg)*);
|
||||
let mut styled = $crate::builder::StyledStr::new();
|
||||
let _ = write!(styled, "{hint}[{module_path:>28}]{body}{hint:#}\n");
|
||||
let color = $crate::output::fmt::Colorizer::new($crate::output::fmt::Stream::Stderr, $crate::ColorChoice::Auto).with_content(styled);
|
||||
let _ = color.print();
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "debug"))]
|
||||
macro_rules! debug {
|
||||
($($arg:tt)*) => {};
|
||||
}
|
||||
|
||||
macro_rules! ok {
|
||||
($expr:expr) => {
|
||||
match $expr {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! some {
|
||||
($expr:expr) => {
|
||||
match $expr {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
188
third_party/crates/clap_builder-4.6.7/src/mkeymap.rs
vendored
Normal file
188
third_party/crates/clap_builder-4.6.7/src/mkeymap.rs
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
use std::iter::Iterator;
|
||||
use std::ops::Index;
|
||||
|
||||
use crate::Arg;
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
use crate::builder::OsStr;
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub(crate) struct Key {
|
||||
key: KeyType,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Eq, Debug, Clone)]
|
||||
pub(crate) struct MKeyMap {
|
||||
/// All of the arguments.
|
||||
args: Vec<Arg>,
|
||||
|
||||
// Cache part:
|
||||
/// Will be set after `_build()`.
|
||||
keys: Vec<Key>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||
pub(crate) enum KeyType {
|
||||
Short(char),
|
||||
Long(OsStr),
|
||||
Position(usize),
|
||||
}
|
||||
|
||||
impl KeyType {
|
||||
pub(crate) fn is_position(&self) -> bool {
|
||||
matches!(self, Self::Position(_))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<usize> for KeyType {
|
||||
fn eq(&self, rhs: &usize) -> bool {
|
||||
match self {
|
||||
Self::Position(x) => x == rhs,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&str> for KeyType {
|
||||
fn eq(&self, rhs: &&str) -> bool {
|
||||
match self {
|
||||
Self::Long(l) => l == rhs,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for KeyType {
|
||||
fn eq(&self, rhs: &str) -> bool {
|
||||
match self {
|
||||
Self::Long(l) => l == rhs,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<OsStr> for KeyType {
|
||||
fn eq(&self, rhs: &OsStr) -> bool {
|
||||
match self {
|
||||
Self::Long(l) => l == rhs,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<char> for KeyType {
|
||||
fn eq(&self, rhs: &char) -> bool {
|
||||
match self {
|
||||
Self::Short(c) => c == rhs,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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`
|
||||
/// (for long flag)
|
||||
pub(crate) fn contains<K>(&self, key: K) -> bool
|
||||
where
|
||||
KeyType: PartialEq<K>,
|
||||
{
|
||||
self.keys.iter().any(|x| x.key == key)
|
||||
}
|
||||
|
||||
/// Push an argument in the map.
|
||||
pub(crate) fn push(&mut self, new_arg: Arg) {
|
||||
self.args.push(new_arg);
|
||||
}
|
||||
|
||||
/// 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)
|
||||
pub(crate) fn get<K: ?Sized>(&self, key: &K) -> Option<&Arg>
|
||||
where
|
||||
KeyType: PartialEq<K>,
|
||||
{
|
||||
self.keys
|
||||
.iter()
|
||||
.find(|k| &k.key == key)
|
||||
.map(|k| &self.args[k.index])
|
||||
}
|
||||
|
||||
/// Return iterators of all keys.
|
||||
pub(crate) fn keys(&self) -> impl Iterator<Item = &KeyType> {
|
||||
self.keys.iter().map(|x| &x.key)
|
||||
}
|
||||
|
||||
/// Return iterators of all args.
|
||||
pub(crate) fn args(&self) -> impl Iterator<Item = &Arg> {
|
||||
self.args.iter()
|
||||
}
|
||||
|
||||
/// Return mutable iterators of all args.
|
||||
pub(crate) fn args_mut(&mut self) -> impl Iterator<Item = &mut Arg> {
|
||||
self.args.iter_mut()
|
||||
}
|
||||
|
||||
/// Mutate every argument.
|
||||
pub(crate) fn mut_args<F>(&mut self, f: F)
|
||||
where
|
||||
F: FnMut(Arg) -> Arg,
|
||||
{
|
||||
let mut args = std::mem::take(&mut self.args);
|
||||
self.args.extend(args.drain(..).map(f));
|
||||
}
|
||||
|
||||
/// We need a lazy build here since some we may change args after creating
|
||||
/// the map, you can checkout who uses `args_mut`.
|
||||
pub(crate) fn _build(&mut self) {
|
||||
// There will be at least as many keys as args, so that is a good starting point
|
||||
self.keys.reserve(self.args.len());
|
||||
for (i, arg) in self.args.iter().enumerate() {
|
||||
append_keys(&mut self.keys, arg, i);
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove an arg in the graph by Id, usually used by `mut_arg`. Return
|
||||
/// `Some(arg)` if removed.
|
||||
pub(crate) fn remove_by_name(&mut self, name: &str) -> Option<Arg> {
|
||||
self.args
|
||||
.iter()
|
||||
.position(|arg| arg.id == name)
|
||||
// since it's a cold function, using this wouldn't hurt much
|
||||
.map(|i| self.args.remove(i))
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<&'_ KeyType> for MKeyMap {
|
||||
type Output = Arg;
|
||||
|
||||
fn index(&self, key: &KeyType) -> &Self::Output {
|
||||
self.get(key).expect(INTERNAL_ERROR_MSG)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate key types for an specific Arg.
|
||||
fn append_keys(keys: &mut Vec<Key>, arg: &Arg, index: usize) {
|
||||
if let Some(pos_index) = arg.index {
|
||||
let key = KeyType::Position(pos_index);
|
||||
keys.push(Key { key, index });
|
||||
} else {
|
||||
if let Some(short) = arg.short {
|
||||
let key = KeyType::Short(short);
|
||||
keys.push(Key { key, index });
|
||||
}
|
||||
if let Some(long) = arg.long.clone() {
|
||||
let key = KeyType::Long(long.into());
|
||||
keys.push(Key { key, index });
|
||||
}
|
||||
|
||||
for (short, _) in arg.short_aliases.iter() {
|
||||
let key = KeyType::Short(*short);
|
||||
keys.push(Key { key, index });
|
||||
}
|
||||
for (long, _) in arg.aliases.iter() {
|
||||
let key = KeyType::Long(long.into());
|
||||
keys.push(Key { key, index });
|
||||
}
|
||||
}
|
||||
}
|
||||
83
third_party/crates/clap_builder-4.6.7/src/output/fmt.rs
vendored
Normal file
83
third_party/crates/clap_builder-4.6.7/src/output/fmt.rs
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
use crate::builder::StyledStr;
|
||||
use crate::util::color::ColorChoice;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum Stream {
|
||||
Stdout,
|
||||
Stderr,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Colorizer {
|
||||
stream: Stream,
|
||||
#[allow(unused)]
|
||||
color_when: ColorChoice,
|
||||
content: StyledStr,
|
||||
}
|
||||
|
||||
impl Colorizer {
|
||||
pub(crate) fn new(stream: Stream, color_when: ColorChoice) -> Self {
|
||||
Self {
|
||||
stream,
|
||||
color_when,
|
||||
content: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_content(mut self, content: StyledStr) -> Self {
|
||||
self.content = content;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Printing methods.
|
||||
impl Colorizer {
|
||||
#[cfg(feature = "color")]
|
||||
pub(crate) fn print(&self) -> std::io::Result<()> {
|
||||
let color_when = match self.color_when {
|
||||
ColorChoice::Always => anstream::ColorChoice::Always,
|
||||
ColorChoice::Auto => anstream::ColorChoice::Auto,
|
||||
ColorChoice::Never => anstream::ColorChoice::Never,
|
||||
};
|
||||
|
||||
let mut stdout;
|
||||
let mut stderr;
|
||||
let writer: &mut dyn std::io::Write = match self.stream {
|
||||
Stream::Stderr => {
|
||||
stderr = anstream::AutoStream::new(std::io::stderr().lock(), color_when);
|
||||
&mut stderr
|
||||
}
|
||||
Stream::Stdout => {
|
||||
stdout = anstream::AutoStream::new(std::io::stdout().lock(), color_when);
|
||||
&mut stdout
|
||||
}
|
||||
};
|
||||
|
||||
self.content.write_to(writer)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "color"))]
|
||||
pub(crate) fn print(&self) -> std::io::Result<()> {
|
||||
// [e]println can't be used here because it panics
|
||||
// if something went wrong. We don't want that.
|
||||
match self.stream {
|
||||
Stream::Stdout => {
|
||||
let stdout = std::io::stdout();
|
||||
let mut stdout = stdout.lock();
|
||||
self.content.write_to(&mut stdout)
|
||||
}
|
||||
Stream::Stderr => {
|
||||
let stderr = std::io::stderr();
|
||||
let mut stderr = stderr.lock();
|
||||
self.content.write_to(&mut stderr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Color-unaware printing. Never uses coloring.
|
||||
impl std::fmt::Display for Colorizer {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.content.fmt(f)
|
||||
}
|
||||
}
|
||||
39
third_party/crates/clap_builder-4.6.7/src/output/help.rs
vendored
Normal file
39
third_party/crates/clap_builder-4.6.7/src/output/help.rs
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
#![cfg_attr(not(feature = "help"), allow(unused_variables))]
|
||||
|
||||
// Internal
|
||||
use crate::builder::Command;
|
||||
use crate::builder::StyledStr;
|
||||
use crate::output::Usage;
|
||||
|
||||
/// Writes the parser help to the wrapped stream.
|
||||
pub(crate) fn write_help(writer: &mut StyledStr, cmd: &Command, usage: &Usage<'_>, use_long: bool) {
|
||||
debug!("write_help");
|
||||
|
||||
if let Some(h) = cmd.get_override_help() {
|
||||
writer.push_styled(h);
|
||||
} else {
|
||||
#[cfg(feature = "help")]
|
||||
{
|
||||
use super::AutoHelp;
|
||||
use super::HelpTemplate;
|
||||
if let Some(tmpl) = cmd.get_help_template() {
|
||||
HelpTemplate::new(writer, cmd, usage, use_long)
|
||||
.write_templated_help(tmpl.as_styled_str());
|
||||
} else {
|
||||
AutoHelp::new(writer, cmd, usage, use_long).write_help();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "help"))]
|
||||
{
|
||||
debug!("write_help: no help, `Command::override_help` and `help` is missing");
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any lines from unused sections
|
||||
writer.trim_start_lines();
|
||||
// Remove any whitespace caused by book keeping
|
||||
writer.trim_end();
|
||||
// Ensure there is still a trailing newline
|
||||
writer.push_str("\n");
|
||||
}
|
||||
1191
third_party/crates/clap_builder-4.6.7/src/output/help_template.rs
vendored
Normal file
1191
third_party/crates/clap_builder-4.6.7/src/output/help_template.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
23
third_party/crates/clap_builder-4.6.7/src/output/mod.rs
vendored
Normal file
23
third_party/crates/clap_builder-4.6.7/src/output/mod.rs
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
mod help;
|
||||
#[cfg(feature = "help")]
|
||||
mod help_template;
|
||||
mod usage;
|
||||
|
||||
pub(crate) mod fmt;
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) mod textwrap;
|
||||
|
||||
pub(crate) use self::help::write_help;
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) use self::help_template::AutoHelp;
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) use self::help_template::HelpTemplate;
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) use self::textwrap::core::display_width;
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) use self::textwrap::wrap;
|
||||
pub(crate) use self::usage::Usage;
|
||||
|
||||
pub(crate) const TAB: &str = " ";
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) const TAB_WIDTH: usize = TAB.len();
|
||||
158
third_party/crates/clap_builder-4.6.7/src/output/textwrap/core.rs
vendored
Normal file
158
third_party/crates/clap_builder-4.6.7/src/output/textwrap/core.rs
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
/// Compute the display width of `text`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// **Note:** When the `unicode` Cargo feature is disabled, all characters are presumed to take up
|
||||
/// 1 width. With the feature enabled, function will correctly deal with [combining characters] in
|
||||
/// their decomposed form (see [Unicode equivalence]).
|
||||
///
|
||||
/// An example of a decomposed character is “é”, which can be decomposed into: “e” followed by a
|
||||
/// combining acute accent: “◌́”. Without the `unicode` Cargo feature, every `char` has a width of
|
||||
/// 1. This includes the combining accent:
|
||||
///
|
||||
/// ## Emojis and CJK Characters
|
||||
///
|
||||
/// Characters such as emojis and [CJK characters] used in the
|
||||
/// Chinese, Japanese, and Korean languages are seen as double-width,
|
||||
/// even if the `unicode-width` feature is disabled:
|
||||
///
|
||||
/// # Limitations
|
||||
///
|
||||
/// The displayed width of a string cannot always be computed from the
|
||||
/// string alone. This is because the width depends on the rendering
|
||||
/// engine used. This is particularly visible with [emoji modifier
|
||||
/// sequences] where a base emoji is modified with, e.g., skin tone or
|
||||
/// hair color modifiers. It is up to the rendering engine to detect
|
||||
/// this and to produce a suitable emoji.
|
||||
///
|
||||
/// A simple example is “❤️”, which consists of “❤” (U+2764: Black
|
||||
/// Heart Symbol) followed by U+FE0F (Variation Selector-16). By
|
||||
/// itself, “❤” is a black heart, but if you follow it with the
|
||||
/// variant selector, you may get a wider red heart.
|
||||
///
|
||||
/// A more complex example would be “👨🦰” which should depict a man
|
||||
/// with red hair. Here the computed width is too large — and the
|
||||
/// width differs depending on the use of the `unicode-width` feature:
|
||||
///
|
||||
/// This happens because the grapheme consists of three code points:
|
||||
/// “👨” (U+1F468: Man), Zero Width Joiner (U+200D), and “🦰”
|
||||
/// (U+1F9B0: Red Hair). You can see them above in the test. With
|
||||
/// `unicode-width` enabled, the ZWJ is correctly seen as having zero
|
||||
/// width, without it is counted as a double-width character.
|
||||
///
|
||||
/// ## Terminal Support
|
||||
///
|
||||
/// Modern browsers typically do a great job at combining characters
|
||||
/// as shown above, but terminals often struggle more. As an example,
|
||||
/// Gnome Terminal version 3.38.1, shows “❤️” as a big red heart, but
|
||||
/// shows "👨🦰" as “👨🦰”.
|
||||
///
|
||||
/// [combining characters]: https://en.wikipedia.org/wiki/Combining_character
|
||||
/// [Unicode equivalence]: https://en.wikipedia.org/wiki/Unicode_equivalence
|
||||
/// [CJK characters]: https://en.wikipedia.org/wiki/CJK_characters
|
||||
/// [emoji modifier sequences]: https://unicode.org/emoji/charts/full-emoji-modifiers.html
|
||||
#[inline(never)]
|
||||
pub(crate) fn display_width(text: &str) -> usize {
|
||||
let mut width = 0;
|
||||
|
||||
let mut control_sequence = false;
|
||||
let control_terminate: char = 'm';
|
||||
|
||||
for ch in text.chars() {
|
||||
if ch.is_ascii_control() {
|
||||
control_sequence = true;
|
||||
} else if control_sequence && ch == control_terminate {
|
||||
control_sequence = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if !control_sequence {
|
||||
width += ch_width(ch);
|
||||
}
|
||||
}
|
||||
width
|
||||
}
|
||||
|
||||
#[cfg(feature = "unicode")]
|
||||
fn ch_width(ch: char) -> usize {
|
||||
unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unicode"))]
|
||||
fn ch_width(_: char) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "unicode")]
|
||||
use unicode_width::UnicodeWidthChar;
|
||||
|
||||
#[test]
|
||||
fn emojis_have_correct_width() {
|
||||
use unic_emoji_char::is_emoji;
|
||||
|
||||
// Emojis in the Basic Latin (ASCII) and Latin-1 Supplement
|
||||
// blocks all have a width of 1 column. This includes
|
||||
// characters such as '#' and '©'.
|
||||
for ch in '\u{1}'..'\u{FF}' {
|
||||
if is_emoji(ch) {
|
||||
let desc = format!("{:?} U+{:04X}", ch, ch as u32);
|
||||
|
||||
#[cfg(feature = "unicode")]
|
||||
assert_eq!(ch.width().unwrap(), 1, "char: {desc}");
|
||||
|
||||
#[cfg(not(feature = "unicode"))]
|
||||
assert_eq!(ch_width(ch), 1, "char: {desc}");
|
||||
}
|
||||
}
|
||||
|
||||
// Emojis in the remaining blocks of the Basic Multilingual
|
||||
// Plane (BMP), in the Supplementary Multilingual Plane (SMP),
|
||||
// and in the Supplementary Ideographic Plane (SIP), are all 1
|
||||
// or 2 columns wide when unicode-width is used, and always 2
|
||||
// columns wide otherwise. This includes all of our favorite
|
||||
// emojis such as 😊.
|
||||
for ch in '\u{FF}'..'\u{2FFFF}' {
|
||||
if is_emoji(ch) {
|
||||
let desc = format!("{:?} U+{:04X}", ch, ch as u32);
|
||||
|
||||
#[cfg(feature = "unicode")]
|
||||
assert!(ch.width().unwrap() <= 2, "char: {desc}");
|
||||
|
||||
#[cfg(not(feature = "unicode"))]
|
||||
assert_eq!(ch_width(ch), 1, "char: {desc}");
|
||||
}
|
||||
}
|
||||
|
||||
// The remaining planes contain almost no assigned code points
|
||||
// and thus also no emojis.
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unicode")]
|
||||
fn display_width_works() {
|
||||
assert_eq!("Café Plain".len(), 11); // “é” is two bytes
|
||||
assert_eq!(display_width("Café Plain"), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unicode")]
|
||||
fn display_width_narrow_emojis() {
|
||||
assert_eq!(display_width("⁉"), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unicode")]
|
||||
fn display_width_narrow_emojis_variant_selector() {
|
||||
assert_eq!(display_width("⁉\u{fe0f}"), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unicode")]
|
||||
fn display_width_emojis() {
|
||||
assert_eq!(display_width("😂😭🥺🤣✨😍🙏🥰😊🔥"), 20);
|
||||
}
|
||||
}
|
||||
122
third_party/crates/clap_builder-4.6.7/src/output/textwrap/mod.rs
vendored
Normal file
122
third_party/crates/clap_builder-4.6.7/src/output/textwrap/mod.rs
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
//! Fork of `textwrap` crate
|
||||
//!
|
||||
//! 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`
|
||||
|
||||
pub(crate) mod core;
|
||||
#[cfg(feature = "wrap_help")]
|
||||
pub(crate) mod word_separators;
|
||||
#[cfg(feature = "wrap_help")]
|
||||
pub(crate) mod wrap_algorithms;
|
||||
|
||||
#[cfg(feature = "wrap_help")]
|
||||
pub(crate) fn wrap(content: &str, hard_width: usize) -> String {
|
||||
let mut wrapper = wrap_algorithms::LineWrapper::new(hard_width);
|
||||
let mut total = Vec::new();
|
||||
for line in content.split_inclusive('\n') {
|
||||
wrapper.reset();
|
||||
let line = word_separators::find_words_ascii_space(line).collect::<Vec<_>>();
|
||||
total.extend(wrapper.wrap(line));
|
||||
}
|
||||
total.join("")
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "wrap_help"))]
|
||||
pub(crate) fn wrap(content: &str, _hard_width: usize) -> String {
|
||||
content.to_owned()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "wrap_help")]
|
||||
mod test {
|
||||
/// Compatibility shim to keep textwrap's tests
|
||||
fn wrap(content: &str, hard_width: usize) -> Vec<String> {
|
||||
super::wrap(content, hard_width)
|
||||
.trim_end()
|
||||
.split('\n')
|
||||
.map(|s| s.to_owned())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_wrap() {
|
||||
assert_eq!(wrap("foo", 10), vec!["foo"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrap_simple() {
|
||||
assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_be_or_not() {
|
||||
assert_eq!(
|
||||
wrap("To be, or not to be, that is the question.", 10),
|
||||
vec!["To be, or", "not to be,", "that is", "the", "question."]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_words_on_first_line() {
|
||||
assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_word() {
|
||||
assert_eq!(wrap("foo", 0), vec!["foo"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_words() {
|
||||
assert_eq!(wrap("foo bar", 0), vec!["foo", "bar"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_width() {
|
||||
assert_eq!(wrap("foo bar", usize::MAX), vec!["foo bar"]);
|
||||
|
||||
let text = "Hello there! This is some English text. \
|
||||
It should not be wrapped given the extents below.";
|
||||
assert_eq!(wrap(text, usize::MAX), vec![text]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leading_whitespace() {
|
||||
assert_eq!(wrap(" foo bar", 6), vec![" foo", " bar"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leading_whitespace_empty_first_line() {
|
||||
// If there is no space for the first word, the first line
|
||||
// will be empty. This is because the string is split into
|
||||
// words like [" ", "foobar ", "baz"], which puts "foobar " on
|
||||
// the second line. We never output trailing whitespace
|
||||
assert_eq!(wrap(" foobar baz", 6), vec![" foobar", " baz"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_whitespace() {
|
||||
// Whitespace is only significant inside a line. After a line
|
||||
// gets too long and is broken, the first word starts in
|
||||
// column zero and is not indented.
|
||||
assert_eq!(wrap("foo bar baz ", 5), vec!["foo", "bar", "baz"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_99() {
|
||||
// We did not reset the in_whitespace flag correctly and did
|
||||
// not handle single-character words after a line break.
|
||||
assert_eq!(
|
||||
wrap("aaabbbccc x yyyzzzwww", 9),
|
||||
vec!["aaabbbccc", "x", "yyyzzzwww"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_129() {
|
||||
// The dash is an em-dash which takes up four bytes. We used
|
||||
// to panic since we tried to index into the character.
|
||||
assert_eq!(wrap("x – x", 1), vec!["x", "–", "x"]);
|
||||
}
|
||||
}
|
||||
92
third_party/crates/clap_builder-4.6.7/src/output/textwrap/word_separators.rs
vendored
Normal file
92
third_party/crates/clap_builder-4.6.7/src/output/textwrap/word_separators.rs
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
pub(crate) fn find_words_ascii_space(line: &str) -> impl Iterator<Item = &'_ str> + '_ {
|
||||
let mut start = 0;
|
||||
let mut in_whitespace = false;
|
||||
let mut char_indices = line.char_indices();
|
||||
|
||||
std::iter::from_fn(move || {
|
||||
for (idx, ch) in char_indices.by_ref() {
|
||||
let next_whitespace = ch == ' ';
|
||||
if in_whitespace && !next_whitespace {
|
||||
let word = &line[start..idx];
|
||||
start = idx;
|
||||
in_whitespace = next_whitespace;
|
||||
return Some(word);
|
||||
}
|
||||
|
||||
in_whitespace = next_whitespace;
|
||||
}
|
||||
|
||||
if start < line.len() {
|
||||
let word = &line[start..];
|
||||
start = line.len();
|
||||
return Some(word);
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
macro_rules! test_find_words {
|
||||
($ascii_name:ident,
|
||||
$([ $line:expr, $ascii_words:expr ]),+) => {
|
||||
#[test]
|
||||
fn $ascii_name() {
|
||||
$(
|
||||
let expected_words: Vec<&str> = $ascii_words.to_vec();
|
||||
let actual_words = find_words_ascii_space($line)
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(actual_words, expected_words, "Line: {:?}", $line);
|
||||
)+
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test_find_words!(ascii_space_empty, ["", []]);
|
||||
|
||||
test_find_words!(ascii_single_word, ["foo", ["foo"]]);
|
||||
|
||||
test_find_words!(ascii_two_words, ["foo bar", ["foo ", "bar"]]);
|
||||
|
||||
test_find_words!(
|
||||
ascii_multiple_words,
|
||||
["foo bar", ["foo ", "bar"]],
|
||||
["x y z", ["x ", "y ", "z"]]
|
||||
);
|
||||
|
||||
test_find_words!(ascii_only_whitespace, [" ", [" "]], [" ", [" "]]);
|
||||
|
||||
test_find_words!(
|
||||
ascii_inter_word_whitespace,
|
||||
["foo bar", ["foo ", "bar"]]
|
||||
);
|
||||
|
||||
test_find_words!(ascii_trailing_whitespace, ["foo ", ["foo "]]);
|
||||
|
||||
test_find_words!(ascii_leading_whitespace, [" foo", [" ", "foo"]]);
|
||||
|
||||
test_find_words!(
|
||||
ascii_multi_column_char,
|
||||
["\u{1f920}", ["\u{1f920}"]] // cowboy emoji 🤠
|
||||
);
|
||||
|
||||
test_find_words!(
|
||||
ascii_hyphens,
|
||||
["foo-bar", ["foo-bar"]],
|
||||
["foo- bar", ["foo- ", "bar"]],
|
||||
["foo - bar", ["foo ", "- ", "bar"]],
|
||||
["foo -bar", ["foo ", "-bar"]]
|
||||
);
|
||||
|
||||
test_find_words!(ascii_newline, ["foo\nbar", ["foo\nbar"]]);
|
||||
|
||||
test_find_words!(ascii_tab, ["foo\tbar", ["foo\tbar"]]);
|
||||
|
||||
test_find_words!(
|
||||
ascii_non_breaking_space,
|
||||
["foo\u{00A0}bar", ["foo\u{00A0}bar"]]
|
||||
);
|
||||
}
|
||||
68
third_party/crates/clap_builder-4.6.7/src/output/textwrap/wrap_algorithms.rs
vendored
Normal file
68
third_party/crates/clap_builder-4.6.7/src/output/textwrap/wrap_algorithms.rs
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
use super::core::display_width;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct LineWrapper<'w> {
|
||||
hard_width: usize,
|
||||
line_width: usize,
|
||||
indentation: Option<&'w str>,
|
||||
}
|
||||
|
||||
impl<'w> LineWrapper<'w> {
|
||||
pub(crate) fn new(hard_width: usize) -> Self {
|
||||
Self {
|
||||
hard_width,
|
||||
line_width: 0,
|
||||
indentation: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reset(&mut self) {
|
||||
self.line_width = 0;
|
||||
self.indentation = None;
|
||||
}
|
||||
|
||||
pub(crate) fn wrap(&mut self, mut words: Vec<&'w str>) -> Vec<&'w str> {
|
||||
let mut first_word = false;
|
||||
if self.indentation.is_none() {
|
||||
first_word = true;
|
||||
if let Some(word) = words.first() {
|
||||
if word.trim().is_empty() {
|
||||
self.indentation = Some(*word);
|
||||
} else {
|
||||
self.indentation = Some("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
while i < words.len() {
|
||||
let word = &words[i];
|
||||
let trimmed = word.trim_end();
|
||||
let word_width = display_width(trimmed);
|
||||
let trimmed_delta = word.len() - trimmed.len();
|
||||
if first_word && 0 < word_width {
|
||||
// Never try to wrap the first word
|
||||
first_word = false;
|
||||
} else if self.hard_width < self.line_width + word_width {
|
||||
if 0 < i {
|
||||
let prev = i - 1;
|
||||
let trimmed = words[prev].trim_end();
|
||||
words[prev] = trimmed;
|
||||
}
|
||||
|
||||
self.line_width = 0;
|
||||
words.insert(i, "\n");
|
||||
i += 1;
|
||||
if let Some(indentation) = self.indentation {
|
||||
words.insert(i, indentation);
|
||||
self.line_width += indentation.len();
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
self.line_width += word_width + trimmed_delta;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
words
|
||||
}
|
||||
}
|
||||
494
third_party/crates/clap_builder-4.6.7/src/output/usage.rs
vendored
Normal file
494
third_party/crates/clap_builder-4.6.7/src/output/usage.rs
vendored
Normal file
@@ -0,0 +1,494 @@
|
||||
#![cfg_attr(not(feature = "usage"), allow(unused_imports))]
|
||||
#![cfg_attr(not(feature = "usage"), allow(unused_variables))]
|
||||
#![cfg_attr(not(feature = "usage"), allow(clippy::manual_map))]
|
||||
#![cfg_attr(not(feature = "usage"), allow(dead_code))]
|
||||
|
||||
// Internal
|
||||
use crate::builder::ArgAction;
|
||||
use crate::builder::StyledStr;
|
||||
use crate::builder::Styles;
|
||||
use crate::builder::{ArgPredicate, Command};
|
||||
use crate::parser::ArgMatcher;
|
||||
use crate::util::ChildGraph;
|
||||
use crate::util::FlatSet;
|
||||
use crate::util::Id;
|
||||
|
||||
static DEFAULT_SUB_VALUE_NAME: &str = "COMMAND";
|
||||
const USAGE_SEP: &str = "\n ";
|
||||
|
||||
pub(crate) struct Usage<'cmd> {
|
||||
cmd: &'cmd Command,
|
||||
styles: &'cmd Styles,
|
||||
required: Option<&'cmd ChildGraph<Id>>,
|
||||
}
|
||||
|
||||
impl<'cmd> Usage<'cmd> {
|
||||
pub(crate) fn new(cmd: &'cmd Command) -> Self {
|
||||
Usage {
|
||||
cmd,
|
||||
styles: cmd.get_styles(),
|
||||
required: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn required(mut self, required: &'cmd ChildGraph<Id>) -> Self {
|
||||
self.required = Some(required);
|
||||
self
|
||||
}
|
||||
|
||||
// Creates a usage string for display. This happens just after all arguments were parsed, but before
|
||||
// any subcommands have been parsed (so as to give subcommands their own usage recursively)
|
||||
pub(crate) fn create_usage_with_title(&self, used: &[Id]) -> Option<StyledStr> {
|
||||
debug!("Usage::create_usage_with_title");
|
||||
use std::fmt::Write as _;
|
||||
let mut styled = StyledStr::new();
|
||||
let _ = write!(
|
||||
styled,
|
||||
"{}Usage:{} ",
|
||||
self.styles.get_usage().render(),
|
||||
self.styles.get_usage().render_reset()
|
||||
);
|
||||
if self.write_usage_no_title(&mut styled, used) {
|
||||
styled.trim_end();
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
debug!("Usage::create_usage_with_title: usage={styled}");
|
||||
Some(styled)
|
||||
}
|
||||
|
||||
// Creates a usage string (*without title*) if one was not provided by the user manually.
|
||||
pub(crate) fn create_usage_no_title(&self, used: &[Id]) -> Option<StyledStr> {
|
||||
debug!("Usage::create_usage_no_title");
|
||||
|
||||
let mut styled = StyledStr::new();
|
||||
if self.write_usage_no_title(&mut styled, used) {
|
||||
styled.trim_end();
|
||||
debug!("Usage::create_usage_no_title: usage={styled}");
|
||||
Some(styled)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a usage string (*without title*) if one was not provided by the user manually.
|
||||
fn write_usage_no_title(&self, styled: &mut StyledStr, used: &[Id]) -> bool {
|
||||
debug!("Usage::create_usage_no_title");
|
||||
if let Some(u) = self.cmd.get_overridden_usage() {
|
||||
styled.push_styled(u);
|
||||
true
|
||||
} else {
|
||||
#[cfg(feature = "usage")]
|
||||
{
|
||||
if used.is_empty() {
|
||||
self.write_help_usage(styled);
|
||||
} else {
|
||||
self.write_smart_usage(styled, used);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "usage"))]
|
||||
{
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "usage")]
|
||||
impl Usage<'_> {
|
||||
// Creates a usage string for display in help messages (i.e. not for errors)
|
||||
fn write_help_usage(&self, styled: &mut StyledStr) {
|
||||
debug!("Usage::write_help_usage");
|
||||
use std::fmt::Write;
|
||||
|
||||
if self.cmd.has_visible_subcommands() && self.cmd.is_flatten_help_set() {
|
||||
if !self.cmd.is_subcommand_required_set()
|
||||
|| self.cmd.is_args_conflicts_with_subcommands_set()
|
||||
{
|
||||
self.write_arg_usage(styled, &[], true);
|
||||
styled.trim_end();
|
||||
let _ = write!(styled, "{USAGE_SEP}");
|
||||
}
|
||||
let mut cmd = self.cmd.clone();
|
||||
cmd.build();
|
||||
for (i, sub) in cmd
|
||||
.get_subcommands()
|
||||
.filter(|c| !c.is_hide_set())
|
||||
.enumerate()
|
||||
{
|
||||
if i != 0 {
|
||||
styled.trim_end();
|
||||
let _ = write!(styled, "{USAGE_SEP}");
|
||||
}
|
||||
Usage::new(sub).write_usage_no_title(styled, &[]);
|
||||
}
|
||||
} else {
|
||||
self.write_arg_usage(styled, &[], true);
|
||||
self.write_subcommand_usage(styled);
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a context aware usage string, or "smart usage" from currently used
|
||||
// args, and requirements
|
||||
fn write_smart_usage(&self, styled: &mut StyledStr, used: &[Id]) {
|
||||
debug!("Usage::create_smart_usage");
|
||||
use std::fmt::Write;
|
||||
let placeholder = &self.styles.get_placeholder();
|
||||
|
||||
self.write_arg_usage(styled, used, true);
|
||||
|
||||
if self.cmd.is_subcommand_required_set() {
|
||||
let value_name = self
|
||||
.cmd
|
||||
.get_subcommand_value_name()
|
||||
.unwrap_or(DEFAULT_SUB_VALUE_NAME);
|
||||
let _ = write!(styled, "{placeholder}<{value_name}>{placeholder:#}",);
|
||||
}
|
||||
}
|
||||
|
||||
fn write_arg_usage(&self, styled: &mut StyledStr, used: &[Id], incl_reqs: bool) {
|
||||
debug!("Usage::write_arg_usage; incl_reqs={incl_reqs:?}");
|
||||
use std::fmt::Write as _;
|
||||
let literal = &self.styles.get_literal();
|
||||
let placeholder = &self.styles.get_placeholder();
|
||||
|
||||
let bin_name = self.cmd.get_usage_name_fallback();
|
||||
if !bin_name.is_empty() {
|
||||
// the trim won't properly remove a leading space due to the formatting
|
||||
let _ = write!(styled, "{literal}{bin_name}{literal:#} ",);
|
||||
}
|
||||
|
||||
if used.is_empty() && self.needs_options_tag() {
|
||||
let _ = write!(styled, "{placeholder}[OPTIONS]{placeholder:#} ",);
|
||||
}
|
||||
|
||||
self.write_args(styled, used, !incl_reqs);
|
||||
}
|
||||
|
||||
fn write_subcommand_usage(&self, styled: &mut StyledStr) {
|
||||
debug!("Usage::write_subcommand_usage");
|
||||
use std::fmt::Write as _;
|
||||
|
||||
// incl_reqs is only false when this function is called recursively
|
||||
if self.cmd.has_visible_subcommands() || self.cmd.is_allow_external_subcommands_set() {
|
||||
let literal = &self.styles.get_literal();
|
||||
let placeholder = &self.styles.get_placeholder();
|
||||
let value_name = self
|
||||
.cmd
|
||||
.get_subcommand_value_name()
|
||||
.unwrap_or(DEFAULT_SUB_VALUE_NAME);
|
||||
if self.cmd.is_subcommand_negates_reqs_set()
|
||||
|| self.cmd.is_args_conflicts_with_subcommands_set()
|
||||
{
|
||||
styled.trim_end();
|
||||
let _ = write!(styled, "{USAGE_SEP}");
|
||||
if self.cmd.is_args_conflicts_with_subcommands_set() {
|
||||
let bin_name = self.cmd.get_usage_name_fallback();
|
||||
// Short-circuit full usage creation since no args will be relevant
|
||||
let _ = write!(styled, "{literal}{bin_name}{literal:#} ",);
|
||||
} else {
|
||||
self.write_arg_usage(styled, &[], false);
|
||||
}
|
||||
let _ = write!(styled, "{placeholder}<{value_name}>{placeholder:#}",);
|
||||
} else if self.cmd.is_subcommand_required_set() {
|
||||
let _ = write!(styled, "{placeholder}<{value_name}>{placeholder:#}",);
|
||||
} else {
|
||||
let _ = write!(styled, "{placeholder}[{value_name}]{placeholder:#}",);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determines if we need the `[OPTIONS]` tag in the usage string
|
||||
fn needs_options_tag(&self) -> bool {
|
||||
debug!("Usage::needs_options_tag");
|
||||
'outer: for f in self.cmd.get_non_positionals() {
|
||||
debug!("Usage::needs_options_tag:iter: f={}", f.get_id());
|
||||
|
||||
// Don't print `[OPTIONS]` just for help or version
|
||||
if f.get_long() == Some("help") || f.get_long() == Some("version") {
|
||||
debug!("Usage::needs_options_tag:iter Option is built-in");
|
||||
continue;
|
||||
}
|
||||
match f.get_action() {
|
||||
ArgAction::Set
|
||||
| ArgAction::Append
|
||||
| ArgAction::SetTrue
|
||||
| ArgAction::SetFalse
|
||||
| ArgAction::Count => {}
|
||||
ArgAction::Help
|
||||
| ArgAction::HelpShort
|
||||
| ArgAction::HelpLong
|
||||
| ArgAction::Version => {
|
||||
debug!("Usage::needs_options_tag:iter Option is built-in");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if f.is_hide_set() {
|
||||
debug!("Usage::needs_options_tag:iter Option is hidden");
|
||||
continue;
|
||||
}
|
||||
if f.is_required_set() {
|
||||
debug!("Usage::needs_options_tag:iter Option is required");
|
||||
continue;
|
||||
}
|
||||
for grp_s in self.cmd.groups_for_arg(f.get_id()) {
|
||||
debug!("Usage::needs_options_tag:iter:iter: grp_s={grp_s:?}");
|
||||
if self.cmd.get_groups().any(|g| g.id == grp_s && g.required) {
|
||||
debug!("Usage::needs_options_tag:iter:iter: Group is required");
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
|
||||
debug!("Usage::needs_options_tag:iter: [OPTIONS] required");
|
||||
return true;
|
||||
}
|
||||
|
||||
debug!("Usage::needs_options_tag: [OPTIONS] not required");
|
||||
false
|
||||
}
|
||||
|
||||
// Returns the required args in usage string form by fully unrolling all groups
|
||||
pub(crate) fn write_args(&self, styled: &mut StyledStr, incls: &[Id], force_optional: bool) {
|
||||
debug!("Usage::write_args: incls={incls:?}",);
|
||||
use std::fmt::Write as _;
|
||||
let literal = &self.styles.get_literal();
|
||||
|
||||
let required_owned;
|
||||
let required = if let Some(required) = self.required {
|
||||
required
|
||||
} else {
|
||||
required_owned = self.cmd.required_graph();
|
||||
&required_owned
|
||||
};
|
||||
|
||||
let mut unrolled_reqs = Vec::new();
|
||||
for a in required.iter() {
|
||||
let is_relevant = |(val, req_arg): &(ArgPredicate, Id)| -> Option<Id> {
|
||||
let required = match val {
|
||||
ArgPredicate::Equals(_) => false,
|
||||
ArgPredicate::IsPresent => true,
|
||||
};
|
||||
required.then(|| req_arg.clone())
|
||||
};
|
||||
|
||||
for aa in self.cmd.unroll_arg_requires(is_relevant, a) {
|
||||
// if we don't check for duplicates here this causes duplicate error messages
|
||||
// see https://github.com/clap-rs/clap/issues/2770
|
||||
unrolled_reqs.push(aa);
|
||||
}
|
||||
// always include the required arg itself. it will not be enumerated
|
||||
// by unroll_requirements_for_arg.
|
||||
unrolled_reqs.push(a.clone());
|
||||
}
|
||||
debug!("Usage::get_args: unrolled_reqs={unrolled_reqs:?}");
|
||||
|
||||
let mut required_groups_members = FlatSet::new();
|
||||
let mut required_groups = FlatSet::new();
|
||||
for req in unrolled_reqs.iter().chain(incls.iter()) {
|
||||
if self.cmd.find_group(req).is_some() {
|
||||
let group_members = self.cmd.unroll_args_in_group(req);
|
||||
let elem = self.cmd.format_group(req);
|
||||
required_groups.insert(elem);
|
||||
required_groups_members.extend(group_members);
|
||||
} else {
|
||||
debug_assert!(self.cmd.find(req).is_some());
|
||||
}
|
||||
}
|
||||
|
||||
let mut required_opts = FlatSet::new();
|
||||
let mut required_positionals = Vec::new();
|
||||
for req in unrolled_reqs.iter().chain(incls.iter()) {
|
||||
if let Some(arg) = self.cmd.find(req) {
|
||||
if required_groups_members.contains(arg.get_id()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let stylized = arg.stylized(self.styles, Some(!force_optional));
|
||||
if let Some(index) = arg.get_index() {
|
||||
let new_len = index + 1;
|
||||
if required_positionals.len() < new_len {
|
||||
required_positionals.resize(new_len, None);
|
||||
}
|
||||
required_positionals[index] = Some(stylized);
|
||||
} else {
|
||||
required_opts.insert(stylized);
|
||||
}
|
||||
} else {
|
||||
debug_assert!(self.cmd.find_group(req).is_some());
|
||||
}
|
||||
}
|
||||
|
||||
for pos in self.cmd.get_positionals() {
|
||||
if pos.is_hide_set() {
|
||||
continue;
|
||||
}
|
||||
if required_groups_members.contains(pos.get_id()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let index = pos.get_index().unwrap();
|
||||
let new_len = index + 1;
|
||||
if required_positionals.len() < new_len {
|
||||
required_positionals.resize(new_len, None);
|
||||
}
|
||||
if required_positionals[index].is_some() {
|
||||
if pos.is_last_set() {
|
||||
let styled = required_positionals[index].take().unwrap();
|
||||
let mut new = StyledStr::new();
|
||||
let _ = write!(new, "{literal}--{literal:#} ");
|
||||
new.push_styled(&styled);
|
||||
required_positionals[index] = Some(new);
|
||||
}
|
||||
} else {
|
||||
let mut styled;
|
||||
if pos.is_last_set() {
|
||||
styled = StyledStr::new();
|
||||
let _ = write!(styled, "{literal}[--{literal:#} ");
|
||||
styled.push_styled(&pos.stylized(self.styles, Some(true)));
|
||||
let _ = write!(styled, "{literal}]{literal:#}");
|
||||
} else {
|
||||
styled = pos.stylized(self.styles, Some(false));
|
||||
}
|
||||
required_positionals[index] = Some(styled);
|
||||
}
|
||||
if pos.is_last_set() && force_optional {
|
||||
required_positionals[index] = None;
|
||||
}
|
||||
}
|
||||
|
||||
if !force_optional {
|
||||
for arg in required_opts {
|
||||
styled.push_styled(&arg);
|
||||
styled.push_str(" ");
|
||||
}
|
||||
for arg in required_groups {
|
||||
styled.push_styled(&arg);
|
||||
styled.push_str(" ");
|
||||
}
|
||||
}
|
||||
for arg in required_positionals.into_iter().flatten() {
|
||||
styled.push_styled(&arg);
|
||||
styled.push_str(" ");
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_required_usage_from(
|
||||
&self,
|
||||
incls: &[Id],
|
||||
matcher: Option<&ArgMatcher>,
|
||||
incl_last: bool,
|
||||
) -> Vec<StyledStr> {
|
||||
debug!(
|
||||
"Usage::get_required_usage_from: incls={:?}, matcher={:?}, incl_last={:?}",
|
||||
incls,
|
||||
matcher.is_some(),
|
||||
incl_last
|
||||
);
|
||||
|
||||
let required_owned;
|
||||
let required = if let Some(required) = self.required {
|
||||
required
|
||||
} else {
|
||||
required_owned = self.cmd.required_graph();
|
||||
&required_owned
|
||||
};
|
||||
|
||||
let mut unrolled_reqs = Vec::new();
|
||||
for a in required.iter() {
|
||||
let is_relevant = |(val, req_arg): &(ArgPredicate, Id)| -> Option<Id> {
|
||||
let required = match val {
|
||||
ArgPredicate::Equals(_) => {
|
||||
if let Some(matcher) = matcher {
|
||||
matcher.check_explicit(a, val)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ArgPredicate::IsPresent => true,
|
||||
};
|
||||
required.then(|| req_arg.clone())
|
||||
};
|
||||
|
||||
for aa in self.cmd.unroll_arg_requires(is_relevant, a) {
|
||||
// if we don't check for duplicates here this causes duplicate error messages
|
||||
// see https://github.com/clap-rs/clap/issues/2770
|
||||
unrolled_reqs.push(aa);
|
||||
}
|
||||
// always include the required arg itself. it will not be enumerated
|
||||
// by unroll_requirements_for_arg.
|
||||
unrolled_reqs.push(a.clone());
|
||||
}
|
||||
debug!("Usage::get_required_usage_from: unrolled_reqs={unrolled_reqs:?}");
|
||||
|
||||
let mut required_groups_members = FlatSet::new();
|
||||
let mut required_groups = FlatSet::new();
|
||||
for req in unrolled_reqs.iter().chain(incls.iter()) {
|
||||
if self.cmd.find_group(req).is_some() {
|
||||
let group_members = self.cmd.unroll_args_in_group(req);
|
||||
let is_present = matcher
|
||||
.map(|m| {
|
||||
group_members
|
||||
.iter()
|
||||
.any(|arg| m.check_explicit(arg, &ArgPredicate::IsPresent))
|
||||
})
|
||||
.unwrap_or(false);
|
||||
debug!("Usage::get_required_usage_from:iter:{req:?} group is_present={is_present}");
|
||||
if is_present {
|
||||
continue;
|
||||
}
|
||||
|
||||
let elem = self.cmd.format_group(req);
|
||||
required_groups.insert(elem);
|
||||
required_groups_members.extend(group_members);
|
||||
} else {
|
||||
debug_assert!(self.cmd.find(req).is_some(), "`{req}` must exist");
|
||||
}
|
||||
}
|
||||
|
||||
let mut required_opts = FlatSet::new();
|
||||
let mut required_positionals = Vec::new();
|
||||
for req in unrolled_reqs.iter().chain(incls.iter()) {
|
||||
if let Some(arg) = self.cmd.find(req) {
|
||||
if required_groups_members.contains(arg.get_id()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_present = matcher
|
||||
.map(|m| m.check_explicit(req, &ArgPredicate::IsPresent))
|
||||
.unwrap_or(false);
|
||||
debug!("Usage::get_required_usage_from:iter:{req:?} arg is_present={is_present}");
|
||||
if is_present {
|
||||
continue;
|
||||
}
|
||||
|
||||
let stylized = arg.stylized(self.styles, Some(true));
|
||||
if let Some(index) = arg.get_index() {
|
||||
if !arg.is_last_set() || incl_last {
|
||||
let new_len = index + 1;
|
||||
if required_positionals.len() < new_len {
|
||||
required_positionals.resize(new_len, None);
|
||||
}
|
||||
required_positionals[index] = Some(stylized);
|
||||
}
|
||||
} else {
|
||||
required_opts.insert(stylized);
|
||||
}
|
||||
} else {
|
||||
debug_assert!(self.cmd.find_group(req).is_some());
|
||||
}
|
||||
}
|
||||
|
||||
let mut ret_val = Vec::new();
|
||||
ret_val.extend(required_opts);
|
||||
ret_val.extend(required_groups);
|
||||
for pos in required_positionals.into_iter().flatten() {
|
||||
ret_val.push(pos);
|
||||
}
|
||||
|
||||
debug!("Usage::get_required_usage_from: ret_val={ret_val:?}");
|
||||
ret_val
|
||||
}
|
||||
}
|
||||
238
third_party/crates/clap_builder-4.6.7/src/parser/arg_matcher.rs
vendored
Normal file
238
third_party/crates/clap_builder-4.6.7/src/parser/arg_matcher.rs
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
// Std
|
||||
use std::ffi::OsString;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
|
||||
// Internal
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
use crate::builder::{Arg, ArgPredicate, Command};
|
||||
use crate::parser::Identifier;
|
||||
use crate::parser::PendingArg;
|
||||
use crate::parser::{ArgMatches, MatchedArg, SubCommand, ValueSource};
|
||||
use crate::util::AnyValue;
|
||||
use crate::util::FlatMap;
|
||||
use crate::util::Id;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct ArgMatcher {
|
||||
matches: ArgMatches,
|
||||
pending: Option<PendingArg>,
|
||||
}
|
||||
|
||||
impl ArgMatcher {
|
||||
pub(crate) fn new(_cmd: &Command) -> Self {
|
||||
Self {
|
||||
matches: ArgMatches {
|
||||
#[cfg(debug_assertions)]
|
||||
valid_args: {
|
||||
let args = _cmd.get_arguments().map(|a| a.get_id().clone());
|
||||
let groups = _cmd.get_groups().map(|g| g.get_id().clone());
|
||||
args.chain(groups).collect()
|
||||
},
|
||||
#[cfg(debug_assertions)]
|
||||
valid_subcommands: _cmd
|
||||
.get_subcommands()
|
||||
.map(|sc| sc.get_name_str().clone())
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
pending: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_inner(self) -> ArgMatches {
|
||||
self.matches
|
||||
}
|
||||
|
||||
pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
|
||||
debug!("ArgMatcher::get_global_values: global_arg_vec={global_arg_vec:?}");
|
||||
let mut vals_map = FlatMap::new();
|
||||
self.fill_in_global_values(global_arg_vec, &mut vals_map);
|
||||
}
|
||||
|
||||
fn fill_in_global_values(
|
||||
&mut self,
|
||||
global_arg_vec: &[Id],
|
||||
vals_map: &mut FlatMap<Id, MatchedArg>,
|
||||
) {
|
||||
for global_arg in global_arg_vec {
|
||||
if let Some(ma) = self.get(global_arg) {
|
||||
// We have to check if the parent's global arg wasn't used but still exists
|
||||
// such as from a default value.
|
||||
//
|
||||
// For example, `myprog subcommand --global-arg=value` where `--global-arg` defines
|
||||
// a default value of `other` myprog would have an existing MatchedArg for
|
||||
// `--global-arg` where the value is `other`
|
||||
let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
|
||||
if parent_ma.source() > ma.source() {
|
||||
parent_ma
|
||||
} else {
|
||||
ma
|
||||
}
|
||||
} else {
|
||||
ma
|
||||
}
|
||||
.clone();
|
||||
vals_map.insert(global_arg.clone(), to_update);
|
||||
}
|
||||
}
|
||||
if let Some(ref mut sc) = self.matches.subcommand {
|
||||
let mut am = Self {
|
||||
matches: mem::take(&mut sc.matches),
|
||||
pending: None,
|
||||
};
|
||||
am.fill_in_global_values(global_arg_vec, vals_map);
|
||||
mem::swap(&mut am.matches, &mut sc.matches);
|
||||
}
|
||||
|
||||
for (name, matched_arg) in vals_map.iter_mut() {
|
||||
self.matches.args.insert(name.clone(), matched_arg.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> {
|
||||
self.matches.args.get(arg)
|
||||
}
|
||||
|
||||
pub(crate) fn get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg> {
|
||||
self.matches.args.get_mut(arg)
|
||||
}
|
||||
|
||||
pub(crate) fn remove(&mut self, arg: &Id) -> bool {
|
||||
self.matches.args.remove(arg).is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn contains(&self, arg: &Id) -> bool {
|
||||
self.matches.args.contains_key(arg)
|
||||
}
|
||||
|
||||
pub(crate) fn arg_ids(&self) -> std::slice::Iter<'_, Id> {
|
||||
self.matches.args.keys()
|
||||
}
|
||||
|
||||
pub(crate) fn args(&self) -> crate::util::flat_map::Iter<'_, Id, MatchedArg> {
|
||||
self.matches.args.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn entry(&mut self, arg: Id) -> crate::util::Entry<'_, Id, MatchedArg> {
|
||||
self.matches.args.entry(arg)
|
||||
}
|
||||
|
||||
pub(crate) fn subcommand(&mut self, sc: SubCommand) {
|
||||
self.matches.subcommand = Some(Box::new(sc));
|
||||
}
|
||||
|
||||
pub(crate) fn subcommand_name(&self) -> Option<&str> {
|
||||
self.matches.subcommand_name()
|
||||
}
|
||||
|
||||
pub(crate) fn check_explicit(&self, arg: &Id, predicate: &ArgPredicate) -> bool {
|
||||
self.get(arg)
|
||||
.map(|a| a.check_explicit(predicate))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub(crate) fn start_custom_arg(&mut self, arg: &Arg, source: ValueSource) {
|
||||
let id = arg.get_id().clone();
|
||||
debug!("ArgMatcher::start_custom_arg: id={id:?}, source={source:?}");
|
||||
let ma = self.entry(id).or_insert(MatchedArg::new_arg(arg));
|
||||
debug_assert_eq!(ma.type_id(), Some(arg.get_value_parser().type_id()));
|
||||
ma.set_source(source);
|
||||
ma.new_val_group();
|
||||
}
|
||||
|
||||
pub(crate) fn start_custom_group(&mut self, id: Id, source: ValueSource) {
|
||||
debug!("ArgMatcher::start_custom_arg: id={id:?}, source={source:?}");
|
||||
let ma = self.entry(id).or_insert(MatchedArg::new_group());
|
||||
debug_assert_eq!(ma.type_id(), None);
|
||||
ma.set_source(source);
|
||||
ma.new_val_group();
|
||||
}
|
||||
|
||||
pub(crate) fn start_occurrence_of_external(&mut self, cmd: &Command) {
|
||||
let id = Id::from_static_ref(Id::EXTERNAL);
|
||||
debug!("ArgMatcher::start_occurrence_of_external: id={id:?}");
|
||||
let ma = self.entry(id).or_insert(MatchedArg::new_external(cmd));
|
||||
debug_assert_eq!(
|
||||
ma.type_id(),
|
||||
Some(
|
||||
cmd.get_external_subcommand_value_parser()
|
||||
.expect(INTERNAL_ERROR_MSG)
|
||||
.type_id()
|
||||
)
|
||||
);
|
||||
ma.set_source(ValueSource::CommandLine);
|
||||
ma.new_val_group();
|
||||
}
|
||||
|
||||
pub(crate) fn add_val_to(&mut self, arg: &Id, val: AnyValue, raw_val: OsString) {
|
||||
let ma = self.get_mut(arg).expect(INTERNAL_ERROR_MSG);
|
||||
ma.append_val(val, raw_val);
|
||||
}
|
||||
|
||||
pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize) {
|
||||
let ma = self.get_mut(arg).expect(INTERNAL_ERROR_MSG);
|
||||
ma.push_index(idx);
|
||||
}
|
||||
|
||||
pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
|
||||
let num_pending = self
|
||||
.pending
|
||||
.as_ref()
|
||||
.and_then(|p| (p.id == *o.get_id()).then_some(p.raw_vals.len()))
|
||||
.unwrap_or(0);
|
||||
debug!(
|
||||
"ArgMatcher::needs_more_vals: o={}, pending={}",
|
||||
o.get_id(),
|
||||
num_pending
|
||||
);
|
||||
let expected = o.get_num_args().expect(INTERNAL_ERROR_MSG);
|
||||
debug!("ArgMatcher::needs_more_vals: expected={expected}, actual={num_pending}");
|
||||
expected.accepts_more(num_pending)
|
||||
}
|
||||
|
||||
pub(crate) fn pending_arg_id(&self) -> Option<&Id> {
|
||||
self.pending.as_ref().map(|p| &p.id)
|
||||
}
|
||||
|
||||
pub(crate) fn pending_values_mut(
|
||||
&mut self,
|
||||
id: &Id,
|
||||
ident: Option<Identifier>,
|
||||
trailing_values: bool,
|
||||
) -> &mut Vec<OsString> {
|
||||
let pending = self.pending.get_or_insert_with(|| PendingArg {
|
||||
id: id.clone(),
|
||||
ident,
|
||||
raw_vals: Default::default(),
|
||||
trailing_idx: None,
|
||||
});
|
||||
debug_assert_eq!(pending.id, *id, "{INTERNAL_ERROR_MSG}");
|
||||
if ident.is_some() {
|
||||
debug_assert_eq!(pending.ident, ident, "{INTERNAL_ERROR_MSG}");
|
||||
}
|
||||
if trailing_values {
|
||||
pending.trailing_idx.get_or_insert(pending.raw_vals.len());
|
||||
}
|
||||
&mut pending.raw_vals
|
||||
}
|
||||
|
||||
pub(crate) fn start_trailing(&mut self) {
|
||||
if let Some(pending) = &mut self.pending {
|
||||
// Allow asserting its started on subsequent calls
|
||||
pending.trailing_idx.get_or_insert(pending.raw_vals.len());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn take_pending(&mut self) -> Option<PendingArg> {
|
||||
self.pending.take()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ArgMatcher {
|
||||
type Target = ArgMatches;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.matches
|
||||
}
|
||||
}
|
||||
66
third_party/crates/clap_builder-4.6.7/src/parser/error.rs
vendored
Normal file
66
third_party/crates/clap_builder-4.6.7/src/parser/error.rs
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
use crate::util::AnyValueId;
|
||||
|
||||
/// Violation of [`ArgMatches`][crate::ArgMatches] assumptions
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(missing_copy_implementations)] // We might add non-Copy types in the future
|
||||
#[non_exhaustive]
|
||||
pub enum MatchesError {
|
||||
/// Failed to downcast `AnyValue` to the specified type
|
||||
#[non_exhaustive]
|
||||
Downcast {
|
||||
/// Type for value stored in [`ArgMatches`][crate::ArgMatches]
|
||||
actual: AnyValueId,
|
||||
/// The target type to downcast to
|
||||
expected: AnyValueId,
|
||||
},
|
||||
/// Argument not defined in [`Command`][crate::Command]
|
||||
#[non_exhaustive]
|
||||
UnknownArgument {
|
||||
// Missing `id` but blocked on a public id type which will hopefully come with `unstable-v4`
|
||||
},
|
||||
}
|
||||
|
||||
impl MatchesError {
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
pub(crate) fn unwrap<T>(id: &str, r: Result<T, Self>) -> T {
|
||||
let err = match r {
|
||||
Ok(t) => {
|
||||
return t;
|
||||
}
|
||||
Err(err) => err,
|
||||
};
|
||||
panic!("Mismatch between definition and access of `{id}`. {err}",)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for MatchesError {}
|
||||
|
||||
impl std::fmt::Display for MatchesError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Downcast { actual, expected } => {
|
||||
writeln!(
|
||||
f,
|
||||
"Could not downcast to {expected:?}, need to downcast to {actual:?}"
|
||||
)
|
||||
}
|
||||
Self::UnknownArgument {} => {
|
||||
writeln!(
|
||||
f,
|
||||
"Unknown argument or group id. Make sure you are using the argument id and not the short or long flags"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_auto_traits() {
|
||||
static_assertions::assert_impl_all!(
|
||||
MatchesError: Send,
|
||||
Sync,
|
||||
std::panic::RefUnwindSafe,
|
||||
std::panic::UnwindSafe,
|
||||
Unpin
|
||||
);
|
||||
}
|
||||
1
third_party/crates/clap_builder-4.6.7/src/parser/features/mod.rs
vendored
Normal file
1
third_party/crates/clap_builder-4.6.7/src/parser/features/mod.rs
vendored
Normal file
@@ -0,0 +1 @@
|
||||
pub(crate) mod suggestions;
|
||||
178
third_party/crates/clap_builder-4.6.7/src/parser/features/suggestions.rs
vendored
Normal file
178
third_party/crates/clap_builder-4.6.7/src/parser/features/suggestions.rs
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
// Internal
|
||||
use crate::builder::Command;
|
||||
|
||||
/// Find strings from an iterable of `possible_values` similar to a given value `v`
|
||||
/// Returns a Vec of all possible values that exceed a similarity threshold
|
||||
/// sorted by ascending similarity, most similar comes last
|
||||
#[cfg(feature = "suggestions")]
|
||||
pub(crate) fn did_you_mean<T, I>(v: &str, possible_values: I) -> Vec<String>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
use std::cmp::Ordering;
|
||||
|
||||
let mut candidates: Vec<(f64, String)> = Vec::new();
|
||||
for pv in possible_values {
|
||||
// GH #4660: using `jaro` because `jaro_winkler` implementation in `strsim-rs` is wrong
|
||||
// causing strings with common prefix >=10 to be considered perfectly similar
|
||||
let confidence = strsim::jaro(v, pv.as_ref());
|
||||
|
||||
if confidence > 0.7 {
|
||||
let new_elem = (confidence, pv.as_ref().to_owned());
|
||||
let pos = candidates
|
||||
.binary_search_by(|probe| {
|
||||
if probe.0 > confidence {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
Ordering::Less
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|e| e);
|
||||
candidates.insert(pos, new_elem);
|
||||
}
|
||||
}
|
||||
|
||||
candidates.into_iter().map(|(_, pv)| pv).collect()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "suggestions"))]
|
||||
pub(crate) fn did_you_mean<T, I>(_: &str, _: I) -> Vec<String>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
|
||||
pub(crate) fn did_you_mean_flag<'a, 'help, I, T>(
|
||||
arg: &str,
|
||||
remaining_args: &[&std::ffi::OsStr],
|
||||
longs: I,
|
||||
subcommands: impl IntoIterator<Item = &'a mut Command>,
|
||||
) -> Option<(String, Option<String>)>
|
||||
where
|
||||
'help: 'a,
|
||||
T: AsRef<str>,
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
use crate::mkeymap::KeyType;
|
||||
|
||||
match did_you_mean(arg, longs).pop() {
|
||||
Some(candidate) => Some((candidate, None)),
|
||||
None => subcommands
|
||||
.into_iter()
|
||||
.filter_map(|subcommand| {
|
||||
subcommand._build_self(false);
|
||||
|
||||
let longs = subcommand.get_keymap().keys().filter_map(|a| {
|
||||
if let KeyType::Long(v) = a {
|
||||
Some(v.to_string_lossy().into_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let subcommand_name = subcommand.get_name();
|
||||
|
||||
let candidate = some!(did_you_mean(arg, longs).pop());
|
||||
let score = some!(remaining_args.iter().position(|x| subcommand_name == *x));
|
||||
Some((score, (candidate, Some(subcommand_name.to_owned()))))
|
||||
})
|
||||
.min_by_key(|(x, _)| *x)
|
||||
.map(|(_, suggestion)| suggestion),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "suggestions"))]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn missing_letter() {
|
||||
let p_vals = ["test", "possible", "values"];
|
||||
assert_eq!(did_you_mean("tst", p_vals.iter()), vec!["test"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ambiguous() {
|
||||
let p_vals = ["test", "temp", "possible", "values"];
|
||||
assert_eq!(did_you_mean("te", p_vals.iter()), vec!["test", "temp"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unrelated() {
|
||||
let p_vals = ["test", "possible", "values"];
|
||||
assert_eq!(
|
||||
did_you_mean("hahaahahah", p_vals.iter()),
|
||||
Vec::<String>::new()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn best_fit() {
|
||||
let p_vals = [
|
||||
"test",
|
||||
"possible",
|
||||
"values",
|
||||
"alignmentStart",
|
||||
"alignmentScore",
|
||||
];
|
||||
assert_eq!(
|
||||
did_you_mean("alignmentScorr", p_vals.iter()),
|
||||
vec!["alignmentStart", "alignmentScore"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn best_fit_long_common_prefix_issue_4660() {
|
||||
let p_vals = ["alignmentScore", "alignmentStart"];
|
||||
assert_eq!(
|
||||
did_you_mean("alignmentScorr", p_vals.iter()),
|
||||
vec!["alignmentStart", "alignmentScore"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flag_missing_letter() {
|
||||
let p_vals = ["test", "possible", "values"];
|
||||
assert_eq!(
|
||||
did_you_mean_flag("tst", &[], p_vals.iter(), []),
|
||||
Some(("test".to_owned(), None))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flag_ambiguous() {
|
||||
let p_vals = ["test", "temp", "possible", "values"];
|
||||
assert_eq!(
|
||||
did_you_mean_flag("te", &[], p_vals.iter(), []),
|
||||
Some(("temp".to_owned(), None))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flag_unrelated() {
|
||||
let p_vals = ["test", "possible", "values"];
|
||||
assert_eq!(
|
||||
did_you_mean_flag("hahaahahah", &[], p_vals.iter(), []),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flag_best_fit() {
|
||||
let p_vals = [
|
||||
"test",
|
||||
"possible",
|
||||
"values",
|
||||
"alignmentStart",
|
||||
"alignmentScore",
|
||||
];
|
||||
assert_eq!(
|
||||
did_you_mean_flag("alignmentScorr", &[], p_vals.iter(), []),
|
||||
Some(("alignmentScore".to_owned(), None))
|
||||
);
|
||||
}
|
||||
}
|
||||
2045
third_party/crates/clap_builder-4.6.7/src/parser/matches/arg_matches.rs
vendored
Normal file
2045
third_party/crates/clap_builder-4.6.7/src/parser/matches/arg_matches.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
221
third_party/crates/clap_builder-4.6.7/src/parser/matches/matched_arg.rs
vendored
Normal file
221
third_party/crates/clap_builder-4.6.7/src/parser/matches/matched_arg.rs
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
// Std
|
||||
use std::{
|
||||
ffi::{OsStr, OsString},
|
||||
iter::{Cloned, Flatten},
|
||||
slice::Iter,
|
||||
};
|
||||
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
use crate::builder::ArgPredicate;
|
||||
use crate::parser::ValueSource;
|
||||
use crate::util::AnyValue;
|
||||
use crate::util::AnyValueId;
|
||||
use crate::util::eq_ignore_case;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct MatchedArg {
|
||||
source: Option<ValueSource>,
|
||||
indices: Vec<usize>,
|
||||
type_id: Option<AnyValueId>,
|
||||
vals: Vec<Vec<AnyValue>>,
|
||||
raw_vals: Vec<Vec<OsString>>,
|
||||
ignore_case: bool,
|
||||
}
|
||||
|
||||
impl MatchedArg {
|
||||
pub(crate) fn new_arg(arg: &crate::Arg) -> Self {
|
||||
let ignore_case = arg.is_ignore_case_set();
|
||||
Self {
|
||||
source: None,
|
||||
indices: Vec::new(),
|
||||
type_id: Some(arg.get_value_parser().type_id()),
|
||||
vals: Vec::new(),
|
||||
raw_vals: Vec::new(),
|
||||
ignore_case,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_group() -> Self {
|
||||
let ignore_case = false;
|
||||
Self {
|
||||
source: None,
|
||||
indices: Vec::new(),
|
||||
type_id: None,
|
||||
vals: Vec::new(),
|
||||
raw_vals: Vec::new(),
|
||||
ignore_case,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_external(cmd: &crate::Command) -> Self {
|
||||
let ignore_case = false;
|
||||
Self {
|
||||
source: None,
|
||||
indices: Vec::new(),
|
||||
type_id: Some(
|
||||
cmd.get_external_subcommand_value_parser()
|
||||
.expect(INTERNAL_ERROR_MSG)
|
||||
.type_id(),
|
||||
),
|
||||
vals: Vec::new(),
|
||||
raw_vals: Vec::new(),
|
||||
ignore_case,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn indices(&self) -> Cloned<Iter<'_, usize>> {
|
||||
self.indices.iter().cloned()
|
||||
}
|
||||
|
||||
pub(crate) fn get_index(&self, index: usize) -> Option<usize> {
|
||||
self.indices.get(index).cloned()
|
||||
}
|
||||
|
||||
pub(crate) fn push_index(&mut self, index: usize) {
|
||||
self.indices.push(index);
|
||||
}
|
||||
|
||||
pub(crate) fn vals(&self) -> Iter<'_, Vec<AnyValue>> {
|
||||
self.vals.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn into_vals(self) -> Vec<Vec<AnyValue>> {
|
||||
self.vals
|
||||
}
|
||||
|
||||
pub(crate) fn vals_flatten(&self) -> Flatten<Iter<'_, Vec<AnyValue>>> {
|
||||
self.vals.iter().flatten()
|
||||
}
|
||||
|
||||
pub(crate) fn into_vals_flatten(self) -> Flatten<std::vec::IntoIter<Vec<AnyValue>>> {
|
||||
self.vals.into_iter().flatten()
|
||||
}
|
||||
|
||||
pub(crate) fn raw_vals(&self) -> Iter<'_, Vec<OsString>> {
|
||||
self.raw_vals.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn raw_vals_flatten(&self) -> Flatten<Iter<'_, Vec<OsString>>> {
|
||||
self.raw_vals.iter().flatten()
|
||||
}
|
||||
|
||||
pub(crate) fn first(&self) -> Option<&AnyValue> {
|
||||
self.vals_flatten().next()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn first_raw(&self) -> Option<&OsString> {
|
||||
self.raw_vals_flatten().next()
|
||||
}
|
||||
|
||||
pub(crate) fn new_val_group(&mut self) {
|
||||
self.vals.push(vec![]);
|
||||
self.raw_vals.push(vec![]);
|
||||
}
|
||||
|
||||
pub(crate) fn append_val(&mut self, val: AnyValue, raw_val: OsString) {
|
||||
// We assume there is always a group created before.
|
||||
self.vals.last_mut().expect(INTERNAL_ERROR_MSG).push(val);
|
||||
self.raw_vals
|
||||
.last_mut()
|
||||
.expect(INTERNAL_ERROR_MSG)
|
||||
.push(raw_val);
|
||||
}
|
||||
|
||||
pub(crate) fn num_vals(&self) -> usize {
|
||||
self.vals.iter().map(|v| v.len()).sum()
|
||||
}
|
||||
|
||||
// Will be used later
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn num_vals_last_group(&self) -> usize {
|
||||
self.vals.last().map(|x| x.len()).unwrap_or(0)
|
||||
}
|
||||
|
||||
pub(crate) fn check_explicit(&self, predicate: &ArgPredicate) -> bool {
|
||||
if self.source.map(|s| !s.is_explicit()).unwrap_or(false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
match predicate {
|
||||
ArgPredicate::Equals(val) => self.raw_vals_flatten().any(|v| {
|
||||
if self.ignore_case {
|
||||
// If `v` isn't utf8, it can't match `val`, so `OsStr::to_str` should be fine
|
||||
eq_ignore_case(&v.to_string_lossy(), &val.to_string_lossy())
|
||||
} else {
|
||||
OsString::as_os_str(v) == OsStr::new(val)
|
||||
}
|
||||
}),
|
||||
ArgPredicate::IsPresent => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn source(&self) -> Option<ValueSource> {
|
||||
self.source
|
||||
}
|
||||
|
||||
pub(crate) fn set_source(&mut self, source: ValueSource) {
|
||||
if let Some(existing) = self.source {
|
||||
self.source = Some(existing.max(source));
|
||||
} else {
|
||||
self.source = Some(source);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn type_id(&self) -> Option<AnyValueId> {
|
||||
self.type_id
|
||||
}
|
||||
|
||||
pub(crate) fn infer_type_id(&self, expected: AnyValueId) -> AnyValueId {
|
||||
self.type_id()
|
||||
.or_else(|| {
|
||||
self.vals_flatten()
|
||||
.map(|v| v.type_id())
|
||||
.find(|actual| *actual != expected)
|
||||
})
|
||||
.unwrap_or(expected)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for MatchedArg {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Self {
|
||||
source: self_source,
|
||||
indices: self_indices,
|
||||
type_id: self_type_id,
|
||||
vals: _,
|
||||
raw_vals: self_raw_vals,
|
||||
ignore_case: self_ignore_case,
|
||||
} = self;
|
||||
let Self {
|
||||
source: other_source,
|
||||
indices: other_indices,
|
||||
type_id: other_type_id,
|
||||
vals: _,
|
||||
raw_vals: other_raw_vals,
|
||||
ignore_case: other_ignore_case,
|
||||
} = other;
|
||||
self_source == other_source
|
||||
&& self_indices == other_indices
|
||||
&& self_type_id == other_type_id
|
||||
&& self_raw_vals == other_raw_vals
|
||||
&& self_ignore_case == other_ignore_case
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for MatchedArg {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_grouped_vals_first() {
|
||||
let mut m = MatchedArg::new_group();
|
||||
m.new_val_group();
|
||||
m.new_val_group();
|
||||
m.append_val(AnyValue::new(String::from("bbb")), "bbb".into());
|
||||
m.append_val(AnyValue::new(String::from("ccc")), "ccc".into());
|
||||
assert_eq!(m.first_raw(), Some(&OsString::from("bbb")));
|
||||
}
|
||||
}
|
||||
13
third_party/crates/clap_builder-4.6.7/src/parser/matches/mod.rs
vendored
Normal file
13
third_party/crates/clap_builder-4.6.7/src/parser/matches/mod.rs
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
mod arg_matches;
|
||||
mod matched_arg;
|
||||
mod value_source;
|
||||
|
||||
pub use arg_matches::IdsRef;
|
||||
pub use arg_matches::RawValues;
|
||||
pub use arg_matches::Values;
|
||||
pub use arg_matches::ValuesRef;
|
||||
pub use arg_matches::{ArgMatches, Indices};
|
||||
pub use value_source::ValueSource;
|
||||
|
||||
pub(crate) use arg_matches::SubCommand;
|
||||
pub(crate) use matched_arg::MatchedArg;
|
||||
17
third_party/crates/clap_builder-4.6.7/src/parser/matches/value_source.rs
vendored
Normal file
17
third_party/crates/clap_builder-4.6.7/src/parser/matches/value_source.rs
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/// Origin of the argument's value
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[non_exhaustive]
|
||||
pub enum ValueSource {
|
||||
/// Value came [`Arg::default_value`][crate::Arg::default_value]
|
||||
DefaultValue,
|
||||
/// Value came [`Arg::env`][crate::Arg::env]
|
||||
EnvVariable,
|
||||
/// Value was passed in on the command-line
|
||||
CommandLine,
|
||||
}
|
||||
|
||||
impl ValueSource {
|
||||
pub(crate) fn is_explicit(self) -> bool {
|
||||
self != Self::DefaultValue
|
||||
}
|
||||
}
|
||||
25
third_party/crates/clap_builder-4.6.7/src/parser/mod.rs
vendored
Normal file
25
third_party/crates/clap_builder-4.6.7/src/parser/mod.rs
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
//! [`Command`][crate::Command] line argument parser
|
||||
|
||||
mod arg_matcher;
|
||||
mod error;
|
||||
mod matches;
|
||||
#[allow(clippy::module_inception)]
|
||||
mod parser;
|
||||
mod validator;
|
||||
|
||||
pub(crate) mod features;
|
||||
|
||||
pub(crate) use self::arg_matcher::ArgMatcher;
|
||||
pub(crate) use self::matches::{MatchedArg, SubCommand};
|
||||
pub(crate) use self::parser::Identifier;
|
||||
pub(crate) use self::parser::Parser;
|
||||
pub(crate) use self::parser::PendingArg;
|
||||
pub(crate) use self::validator::Validator;
|
||||
pub(crate) use self::validator::get_possible_values_cli;
|
||||
|
||||
pub use self::matches::IdsRef;
|
||||
pub use self::matches::RawValues;
|
||||
pub use self::matches::Values;
|
||||
pub use self::matches::ValuesRef;
|
||||
pub use self::matches::{ArgMatches, Indices, ValueSource};
|
||||
pub use error::MatchesError;
|
||||
1685
third_party/crates/clap_builder-4.6.7/src/parser/parser.rs
vendored
Normal file
1685
third_party/crates/clap_builder-4.6.7/src/parser/parser.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
537
third_party/crates/clap_builder-4.6.7/src/parser/validator.rs
vendored
Normal file
537
third_party/crates/clap_builder-4.6.7/src/parser/validator.rs
vendored
Normal file
@@ -0,0 +1,537 @@
|
||||
// Internal
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
use crate::builder::StyledStr;
|
||||
use crate::builder::{Arg, ArgGroup, ArgPredicate, Command, PossibleValue};
|
||||
use crate::error::{Error, Result as ClapResult};
|
||||
use crate::output::Usage;
|
||||
use crate::parser::ArgMatcher;
|
||||
use crate::util::ChildGraph;
|
||||
use crate::util::FlatMap;
|
||||
use crate::util::FlatSet;
|
||||
use crate::util::Id;
|
||||
|
||||
pub(crate) struct Validator<'cmd> {
|
||||
cmd: &'cmd Command,
|
||||
required: ChildGraph<Id>,
|
||||
}
|
||||
|
||||
impl<'cmd> Validator<'cmd> {
|
||||
pub(crate) fn new(cmd: &'cmd Command) -> Self {
|
||||
let required = cmd.required_graph();
|
||||
Validator { cmd, required }
|
||||
}
|
||||
|
||||
pub(crate) fn validate(&mut self, matcher: &mut ArgMatcher) -> ClapResult<()> {
|
||||
debug!("Validator::validate");
|
||||
let conflicts = Conflicts::with_args(self.cmd, matcher);
|
||||
let has_subcmd = matcher.subcommand_name().is_some();
|
||||
|
||||
if !has_subcmd && self.cmd.is_arg_required_else_help_set() {
|
||||
let num_user_values = matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.count();
|
||||
if num_user_values == 0 {
|
||||
let message = self.cmd.write_help_err(false);
|
||||
return Err(Error::display_help_error(self.cmd, message));
|
||||
}
|
||||
}
|
||||
if !has_subcmd && self.cmd.is_subcommand_required_set() {
|
||||
let bn = self.cmd.get_bin_name_fallback();
|
||||
return Err(Error::missing_subcommand(
|
||||
self.cmd,
|
||||
bn.to_owned(),
|
||||
self.cmd
|
||||
.all_subcommand_names()
|
||||
.map(|s| s.to_owned())
|
||||
.collect::<Vec<_>>(),
|
||||
Usage::new(self.cmd)
|
||||
.required(&self.required)
|
||||
.create_usage_with_title(&[]),
|
||||
));
|
||||
}
|
||||
|
||||
ok!(self.validate_conflicts(matcher, &conflicts));
|
||||
if !(self.cmd.is_subcommand_negates_reqs_set() && has_subcmd) {
|
||||
ok!(self.validate_required(matcher, &conflicts));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_conflicts(
|
||||
&mut self,
|
||||
matcher: &ArgMatcher,
|
||||
conflicts: &Conflicts,
|
||||
) -> ClapResult<()> {
|
||||
debug!("Validator::validate_conflicts");
|
||||
|
||||
ok!(self.validate_exclusive(matcher));
|
||||
|
||||
for (arg_id, _) in matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.filter(|(arg_id, _)| self.cmd.find(arg_id).is_some())
|
||||
{
|
||||
debug!("Validator::validate_conflicts::iter: id={arg_id:?}");
|
||||
let conflicts = conflicts.gather_conflicts(self.cmd, arg_id);
|
||||
ok!(self.build_conflict_err(arg_id, &conflicts, matcher));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_exclusive(&self, matcher: &ArgMatcher) -> ClapResult<()> {
|
||||
debug!("Validator::validate_exclusive");
|
||||
let args_count = matcher
|
||||
.args()
|
||||
.filter(|(arg_id, matched)| {
|
||||
matched.check_explicit(&ArgPredicate::IsPresent)
|
||||
// Avoid including our own groups by checking none of them. If a group is present, the
|
||||
// args for the group will be.
|
||||
&& self.cmd.find(arg_id).is_some()
|
||||
})
|
||||
.count();
|
||||
if args_count <= 1 {
|
||||
// Nothing present to conflict with
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.find_map(|(id, _)| {
|
||||
debug!("Validator::validate_exclusive:iter:{id:?}");
|
||||
self.cmd
|
||||
.find(id)
|
||||
// Find `arg`s which are exclusive but also appear with other args.
|
||||
.filter(|&arg| arg.is_exclusive_set() && args_count > 1)
|
||||
})
|
||||
.map(|arg| {
|
||||
// Throw an error for the first conflict found.
|
||||
Err(Error::argument_conflict(
|
||||
self.cmd,
|
||||
arg.to_string(),
|
||||
Vec::new(),
|
||||
Usage::new(self.cmd)
|
||||
.required(&self.required)
|
||||
.create_usage_with_title(&[]),
|
||||
))
|
||||
})
|
||||
.unwrap_or(Ok(()))
|
||||
}
|
||||
|
||||
fn build_conflict_err(
|
||||
&self,
|
||||
name: &Id,
|
||||
conflict_ids: &[Id],
|
||||
matcher: &ArgMatcher,
|
||||
) -> ClapResult<()> {
|
||||
if conflict_ids.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
debug!("Validator::build_conflict_err: name={name:?}");
|
||||
let conflict_ids = conflict_ids
|
||||
.iter()
|
||||
.flat_map(|c_id| {
|
||||
if self.cmd.find_group(c_id).is_some() {
|
||||
self.cmd.unroll_args_in_group(c_id)
|
||||
} else {
|
||||
vec![c_id.clone()]
|
||||
}
|
||||
})
|
||||
.collect::<FlatSet<_>>()
|
||||
.into_vec();
|
||||
let conflicts = conflict_ids
|
||||
.iter()
|
||||
.map(|c_id| {
|
||||
let c_arg = self.cmd.find(c_id).expect(INTERNAL_ERROR_MSG);
|
||||
c_arg.to_string()
|
||||
})
|
||||
.collect();
|
||||
|
||||
let former_arg = self.cmd.find(name).expect(INTERNAL_ERROR_MSG);
|
||||
let usg = self.build_conflict_err_usage(matcher, &conflict_ids);
|
||||
Err(Error::argument_conflict(
|
||||
self.cmd,
|
||||
former_arg.to_string(),
|
||||
conflicts,
|
||||
usg,
|
||||
))
|
||||
}
|
||||
|
||||
fn build_conflict_err_usage(
|
||||
&self,
|
||||
matcher: &ArgMatcher,
|
||||
conflicting_keys: &[Id],
|
||||
) -> Option<StyledStr> {
|
||||
let used_filtered: Vec<Id> = matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.map(|(n, _)| n)
|
||||
.filter(|n| {
|
||||
// Filter out the args we don't want to specify.
|
||||
self.cmd
|
||||
.find(n)
|
||||
.map(|a| !a.is_hide_set())
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.filter(|key| !conflicting_keys.contains(key))
|
||||
.cloned()
|
||||
.collect();
|
||||
let required: Vec<Id> = used_filtered
|
||||
.iter()
|
||||
.filter_map(|key| self.cmd.find(key))
|
||||
.flat_map(|arg| arg.requires.iter().map(|item| &item.1))
|
||||
.filter(|key| !used_filtered.contains(key) && !conflicting_keys.contains(key))
|
||||
.chain(used_filtered.iter())
|
||||
.cloned()
|
||||
.collect();
|
||||
Usage::new(self.cmd)
|
||||
.required(&self.required)
|
||||
.create_usage_with_title(&required)
|
||||
}
|
||||
|
||||
fn gather_requires(&mut self, matcher: &ArgMatcher) {
|
||||
debug!("Validator::gather_requires");
|
||||
for (name, matched) in matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
{
|
||||
debug!("Validator::gather_requires:iter:{name:?}");
|
||||
if let Some(arg) = self.cmd.find(name) {
|
||||
let is_relevant = |(val, req_arg): &(ArgPredicate, Id)| -> Option<Id> {
|
||||
let required = matched.check_explicit(val);
|
||||
required.then(|| req_arg.clone())
|
||||
};
|
||||
|
||||
for req in self.cmd.unroll_arg_requires(is_relevant, arg.get_id()) {
|
||||
self.required.insert(req);
|
||||
}
|
||||
} else if let Some(g) = self.cmd.find_group(name) {
|
||||
debug!("Validator::gather_requires:iter:{name:?}:group");
|
||||
for r in &g.requires {
|
||||
self.required.insert(r.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_required(&mut self, matcher: &ArgMatcher, conflicts: &Conflicts) -> ClapResult<()> {
|
||||
debug!("Validator::validate_required: required={:?}", self.required);
|
||||
self.gather_requires(matcher);
|
||||
|
||||
let mut missing_required = Vec::new();
|
||||
let mut highest_index = 0;
|
||||
|
||||
let is_exclusive_present = matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.any(|(id, _)| {
|
||||
self.cmd
|
||||
.find(id)
|
||||
.map(|arg| arg.is_exclusive_set())
|
||||
.unwrap_or_default()
|
||||
});
|
||||
debug!("Validator::validate_required: is_exclusive_present={is_exclusive_present}");
|
||||
|
||||
for arg_or_group in self
|
||||
.required
|
||||
.iter()
|
||||
.filter(|r| !matcher.check_explicit(r, &ArgPredicate::IsPresent))
|
||||
{
|
||||
debug!("Validator::validate_required:iter:aog={arg_or_group:?}");
|
||||
if let Some(arg) = self.cmd.find(arg_or_group) {
|
||||
debug!("Validator::validate_required:iter: This is an arg");
|
||||
if !is_exclusive_present && !self.is_missing_required_ok(arg, conflicts) {
|
||||
debug!(
|
||||
"Validator::validate_required:iter: Missing {:?}",
|
||||
arg.get_id()
|
||||
);
|
||||
missing_required.push(arg.get_id().clone());
|
||||
if !arg.is_last_set() {
|
||||
highest_index = highest_index.max(arg.get_index().unwrap_or(0));
|
||||
}
|
||||
}
|
||||
} else if let Some(group) = self.cmd.find_group(arg_or_group) {
|
||||
debug!("Validator::validate_required:iter: This is a group");
|
||||
if !self
|
||||
.cmd
|
||||
.unroll_args_in_group(&group.id)
|
||||
.iter()
|
||||
.any(|a| matcher.check_explicit(a, &ArgPredicate::IsPresent))
|
||||
{
|
||||
debug!(
|
||||
"Validator::validate_required:iter: Missing {:?}",
|
||||
group.get_id()
|
||||
);
|
||||
missing_required.push(group.get_id().clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the conditionally required args
|
||||
for a in self
|
||||
.cmd
|
||||
.get_arguments()
|
||||
.filter(|a| !matcher.check_explicit(a.get_id(), &ArgPredicate::IsPresent))
|
||||
{
|
||||
let mut required = false;
|
||||
|
||||
for (other, val) in &a.r_ifs {
|
||||
if matcher.check_explicit(other, &ArgPredicate::Equals(val.into())) {
|
||||
debug!(
|
||||
"Validator::validate_required:iter: Missing {:?}",
|
||||
a.get_id()
|
||||
);
|
||||
required = true;
|
||||
}
|
||||
}
|
||||
|
||||
let match_all = a.r_ifs_all.iter().all(|(other, val)| {
|
||||
matcher.check_explicit(other, &ArgPredicate::Equals(val.into()))
|
||||
});
|
||||
if match_all && !a.r_ifs_all.is_empty() {
|
||||
debug!(
|
||||
"Validator::validate_required:iter: Missing {:?}",
|
||||
a.get_id()
|
||||
);
|
||||
required = true;
|
||||
}
|
||||
|
||||
if (!a.r_unless.is_empty() || !a.r_unless_all.is_empty())
|
||||
&& self.fails_arg_required_unless(a, matcher)
|
||||
{
|
||||
debug!(
|
||||
"Validator::validate_required:iter: Missing {:?}",
|
||||
a.get_id()
|
||||
);
|
||||
required = true;
|
||||
}
|
||||
|
||||
if !is_exclusive_present && required {
|
||||
missing_required.push(a.get_id().clone());
|
||||
if !a.is_last_set() {
|
||||
highest_index = highest_index.max(a.get_index().unwrap_or(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For display purposes, include all of the preceding positional arguments
|
||||
if !self.cmd.is_allow_missing_positional_set() {
|
||||
for pos in self
|
||||
.cmd
|
||||
.get_positionals()
|
||||
.filter(|a| !matcher.check_explicit(a.get_id(), &ArgPredicate::IsPresent))
|
||||
{
|
||||
if pos.get_index() < Some(highest_index) {
|
||||
debug!(
|
||||
"Validator::validate_required:iter: Missing {:?}",
|
||||
pos.get_id()
|
||||
);
|
||||
missing_required.push(pos.get_id().clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !missing_required.is_empty() {
|
||||
ok!(self.missing_required_error(matcher, missing_required));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_missing_required_ok(&self, a: &Arg, conflicts: &Conflicts) -> bool {
|
||||
debug!("Validator::is_missing_required_ok: {}", a.get_id());
|
||||
if !conflicts.gather_conflicts(self.cmd, a.get_id()).is_empty() {
|
||||
debug!("Validator::is_missing_required_ok: true (self)");
|
||||
return true;
|
||||
}
|
||||
for group_id in self.cmd.groups_for_arg(a.get_id()) {
|
||||
if !conflicts.gather_conflicts(self.cmd, &group_id).is_empty() {
|
||||
debug!("Validator::is_missing_required_ok: true ({group_id})");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// Failing a required unless means, the arg's "unless" wasn't present, and neither were they
|
||||
fn fails_arg_required_unless(&self, a: &Arg, matcher: &ArgMatcher) -> bool {
|
||||
debug!("Validator::fails_arg_required_unless: a={:?}", a.get_id());
|
||||
let exists = |id| matcher.check_explicit(id, &ArgPredicate::IsPresent);
|
||||
|
||||
(a.r_unless_all.is_empty() || !a.r_unless_all.iter().all(exists))
|
||||
&& !a.r_unless.iter().any(exists)
|
||||
}
|
||||
|
||||
// `req_args`: an arg to include in the error even if not used
|
||||
fn missing_required_error(
|
||||
&self,
|
||||
matcher: &ArgMatcher,
|
||||
raw_req_args: Vec<Id>,
|
||||
) -> ClapResult<()> {
|
||||
debug!("Validator::missing_required_error; incl={raw_req_args:?}");
|
||||
debug!(
|
||||
"Validator::missing_required_error: reqs={:?}",
|
||||
self.required
|
||||
);
|
||||
|
||||
let usg = Usage::new(self.cmd).required(&self.required);
|
||||
|
||||
let req_args = {
|
||||
#[cfg(feature = "usage")]
|
||||
{
|
||||
usg.get_required_usage_from(&raw_req_args, Some(matcher), true)
|
||||
.into_iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "usage"))]
|
||||
{
|
||||
raw_req_args
|
||||
.iter()
|
||||
.map(|id| {
|
||||
if let Some(arg) = self.cmd.find(id) {
|
||||
arg.to_string()
|
||||
} else if let Some(_group) = self.cmd.find_group(id) {
|
||||
self.cmd.format_group(id).to_string()
|
||||
} else {
|
||||
debug_assert!(false, "id={id:?} is unknown");
|
||||
"".to_owned()
|
||||
}
|
||||
})
|
||||
.collect::<FlatSet<_>>()
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
};
|
||||
|
||||
debug!("Validator::missing_required_error: req_args={req_args:#?}");
|
||||
|
||||
let used: Vec<Id> = matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.map(|(n, _)| n)
|
||||
.filter(|n| {
|
||||
// Filter out the args we don't want to specify.
|
||||
self.cmd
|
||||
.find(n)
|
||||
.map(|a| !a.is_hide_set())
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.cloned()
|
||||
.chain(raw_req_args)
|
||||
.collect();
|
||||
|
||||
Err(Error::missing_required_argument(
|
||||
self.cmd,
|
||||
req_args,
|
||||
usg.create_usage_with_title(&used),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
struct Conflicts {
|
||||
potential: FlatMap<Id, Vec<Id>>,
|
||||
}
|
||||
|
||||
impl Conflicts {
|
||||
fn with_args(cmd: &Command, matcher: &ArgMatcher) -> Self {
|
||||
let mut potential = FlatMap::new();
|
||||
potential.extend_unchecked(
|
||||
matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.map(|(id, _)| {
|
||||
let conf = gather_direct_conflicts(cmd, id);
|
||||
(id.clone(), conf)
|
||||
}),
|
||||
);
|
||||
Self { potential }
|
||||
}
|
||||
|
||||
fn gather_conflicts(&self, cmd: &Command, arg_id: &Id) -> Vec<Id> {
|
||||
debug!("Conflicts::gather_conflicts: arg={arg_id:?}");
|
||||
let mut conflicts = Vec::new();
|
||||
|
||||
let arg_id_conflicts_storage;
|
||||
let arg_id_conflicts = if let Some(arg_id_conflicts) = self.get_direct_conflicts(arg_id) {
|
||||
arg_id_conflicts
|
||||
} else {
|
||||
// `is_missing_required_ok` is a case where we check not-present args for conflicts
|
||||
arg_id_conflicts_storage = gather_direct_conflicts(cmd, arg_id);
|
||||
&arg_id_conflicts_storage
|
||||
};
|
||||
for (other_arg_id, other_arg_id_conflicts) in self.potential.iter() {
|
||||
if arg_id == other_arg_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
if arg_id_conflicts.contains(other_arg_id) {
|
||||
conflicts.push(other_arg_id.clone());
|
||||
}
|
||||
if other_arg_id_conflicts.contains(arg_id) {
|
||||
conflicts.push(other_arg_id.clone());
|
||||
}
|
||||
}
|
||||
|
||||
debug!("Conflicts::gather_conflicts: conflicts={conflicts:?}");
|
||||
conflicts
|
||||
}
|
||||
|
||||
fn get_direct_conflicts(&self, arg_id: &Id) -> Option<&[Id]> {
|
||||
self.potential.get(arg_id).map(Vec::as_slice)
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_direct_conflicts(cmd: &Command, id: &Id) -> Vec<Id> {
|
||||
let conf = if let Some(arg) = cmd.find(id) {
|
||||
gather_arg_direct_conflicts(cmd, arg)
|
||||
} else if let Some(group) = cmd.find_group(id) {
|
||||
gather_group_direct_conflicts(group)
|
||||
} else {
|
||||
debug_assert!(false, "id={id:?} is unknown");
|
||||
Vec::new()
|
||||
};
|
||||
debug!("Conflicts::gather_direct_conflicts id={id:?}, conflicts={conf:?}",);
|
||||
conf
|
||||
}
|
||||
|
||||
fn gather_arg_direct_conflicts(cmd: &Command, arg: &Arg) -> Vec<Id> {
|
||||
let mut conf = arg.conflicts.clone();
|
||||
for group_id in cmd.groups_for_arg(arg.get_id()) {
|
||||
let group = cmd.find_group(&group_id).expect(INTERNAL_ERROR_MSG);
|
||||
conf.extend(group.conflicts.iter().cloned());
|
||||
if !group.multiple {
|
||||
for member_id in &group.args {
|
||||
if member_id != arg.get_id() {
|
||||
conf.push(member_id.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Overrides are implicitly conflicts
|
||||
conf.extend(arg.overrides.iter().cloned());
|
||||
|
||||
conf
|
||||
}
|
||||
|
||||
fn gather_group_direct_conflicts(group: &ArgGroup) -> Vec<Id> {
|
||||
group.conflicts.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn get_possible_values_cli(a: &Arg) -> Vec<PossibleValue> {
|
||||
if !a.is_takes_value_set() {
|
||||
vec![]
|
||||
} else {
|
||||
a.get_value_parser()
|
||||
.possible_values()
|
||||
.map(|pvs| pvs.collect())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
127
third_party/crates/clap_builder-4.6.7/src/util/any_value.rs
vendored
Normal file
127
third_party/crates/clap_builder-4.6.7/src/util/any_value.rs
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct AnyValue {
|
||||
inner: std::sync::Arc<dyn std::any::Any + Send + Sync + 'static>,
|
||||
// While we can extract `TypeId` from `inner`, the debug repr is of a number, so let's track
|
||||
// the type_name in debug builds.
|
||||
id: AnyValueId,
|
||||
}
|
||||
|
||||
impl AnyValue {
|
||||
pub(crate) fn new<V: std::any::Any + Clone + Send + Sync + 'static>(inner: V) -> Self {
|
||||
let id = AnyValueId::of::<V>();
|
||||
let inner = std::sync::Arc::new(inner);
|
||||
Self { inner, id }
|
||||
}
|
||||
|
||||
pub(crate) fn downcast_ref<T: std::any::Any + Clone + Send + Sync + 'static>(
|
||||
&self,
|
||||
) -> Option<&T> {
|
||||
self.inner.downcast_ref::<T>()
|
||||
}
|
||||
|
||||
pub(crate) fn downcast_into<T: std::any::Any + Clone + Send + Sync>(self) -> Result<T, Self> {
|
||||
let id = self.id;
|
||||
let value =
|
||||
ok!(std::sync::Arc::downcast::<T>(self.inner).map_err(|inner| Self { inner, id }));
|
||||
let value = std::sync::Arc::try_unwrap(value).unwrap_or_else(|arc| (*arc).clone());
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
pub(crate) fn type_id(&self) -> AnyValueId {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for AnyValue {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
f.debug_struct("AnyValue").field("inner", &self.id).finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AnyValueId {
|
||||
type_id: std::any::TypeId,
|
||||
#[cfg(debug_assertions)]
|
||||
type_name: &'static str,
|
||||
}
|
||||
|
||||
impl AnyValueId {
|
||||
pub(crate) fn of<A: ?Sized + 'static>() -> Self {
|
||||
Self {
|
||||
type_id: std::any::TypeId::of::<A>(),
|
||||
#[cfg(debug_assertions)]
|
||||
type_name: std::any::type_name::<A>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for AnyValueId {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.type_id == other.type_id
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for AnyValueId {}
|
||||
|
||||
impl PartialOrd for AnyValueId {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::any::TypeId> for AnyValueId {
|
||||
fn eq(&self, other: &std::any::TypeId) -> bool {
|
||||
self.type_id == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for AnyValueId {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.type_id.cmp(&other.type_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::hash::Hash for AnyValueId {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.type_id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for AnyValueId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
self.type_id.fmt(f)
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
f.debug_struct(self.type_name).finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: ?Sized + 'static> From<&'a A> for AnyValueId {
|
||||
fn from(_: &'a A) -> Self {
|
||||
Self::of::<A>()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
#[cfg(debug_assertions)]
|
||||
fn debug_impl() {
|
||||
use super::*;
|
||||
|
||||
assert_eq!(format!("{:?}", AnyValue::new(5)), "AnyValue { inner: i32 }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eq_to_type_id() {
|
||||
use super::*;
|
||||
|
||||
let any_value_id = AnyValueId::of::<i32>();
|
||||
let type_id = std::any::TypeId::of::<i32>();
|
||||
assert_eq!(any_value_id, type_id);
|
||||
}
|
||||
}
|
||||
103
third_party/crates/clap_builder-4.6.7/src/util/color.rs
vendored
Normal file
103
third_party/crates/clap_builder-4.6.7/src/util/color.rs
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
use crate::builder::PossibleValue;
|
||||
use crate::derive::ValueEnum;
|
||||
|
||||
/// Represents the color preferences for program output
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||
pub enum ColorChoice {
|
||||
/// Enables colored output only when the output is going to a terminal or TTY.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// **NOTE:** This is the default behavior of `clap`.
|
||||
///
|
||||
/// </div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "color")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ColorChoice};
|
||||
/// Command::new("myprog")
|
||||
/// .color(ColorChoice::Auto)
|
||||
/// .get_matches();
|
||||
/// # }
|
||||
/// ```
|
||||
#[default]
|
||||
Auto,
|
||||
|
||||
/// Enables colored output regardless of whether or not the output is going to a terminal/TTY.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "color")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ColorChoice};
|
||||
/// Command::new("myprog")
|
||||
/// .color(ColorChoice::Always)
|
||||
/// .get_matches();
|
||||
/// # }
|
||||
/// ```
|
||||
Always,
|
||||
|
||||
/// Disables colored output no matter if the output is going to a terminal/TTY, or not.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "color")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ColorChoice};
|
||||
/// Command::new("myprog")
|
||||
/// .color(ColorChoice::Never)
|
||||
/// .get_matches();
|
||||
/// # }
|
||||
/// ```
|
||||
Never,
|
||||
}
|
||||
|
||||
impl ColorChoice {
|
||||
/// Report all `possible_values`
|
||||
pub fn possible_values() -> impl Iterator<Item = PossibleValue> {
|
||||
Self::value_variants()
|
||||
.iter()
|
||||
.filter_map(ValueEnum::to_possible_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ColorChoice {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.to_possible_value()
|
||||
.expect("no values are skipped")
|
||||
.get_name()
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for ColorChoice {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
for variant in Self::value_variants() {
|
||||
if variant.to_possible_value().unwrap().matches(s, false) {
|
||||
return Ok(*variant);
|
||||
}
|
||||
}
|
||||
Err(format!("invalid variant: {s}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ValueEnum for ColorChoice {
|
||||
fn value_variants<'a>() -> &'a [Self] {
|
||||
&[Self::Auto, Self::Always, Self::Never]
|
||||
}
|
||||
|
||||
fn to_possible_value(&self) -> Option<PossibleValue> {
|
||||
Some(match self {
|
||||
Self::Auto => PossibleValue::new("auto"),
|
||||
Self::Always => PossibleValue::new("always"),
|
||||
Self::Never => PossibleValue::new("never"),
|
||||
})
|
||||
}
|
||||
}
|
||||
29
third_party/crates/clap_builder-4.6.7/src/util/escape.rs
vendored
Normal file
29
third_party/crates/clap_builder-4.6.7/src/util/escape.rs
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
#[cfg(feature = "help")]
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub(crate) struct Escape<'s>(pub(crate) &'s str);
|
||||
|
||||
impl<'s> Escape<'s> {
|
||||
pub(crate) fn needs_escaping(&self) -> bool {
|
||||
self.0.is_empty() || self.0.contains(char::is_whitespace)
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn to_cow(&self) -> Cow<'s, str> {
|
||||
if self.needs_escaping() {
|
||||
Cow::Owned(format!("{:?}", self.0))
|
||||
} else {
|
||||
Cow::Borrowed(self.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Escape<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.needs_escaping() {
|
||||
std::fmt::Debug::fmt(self.0, f)
|
||||
} else {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
259
third_party/crates/clap_builder-4.6.7/src/util/flat_map.rs
vendored
Normal file
259
third_party/crates/clap_builder-4.6.7/src/util/flat_map.rs
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::borrow::Borrow;
|
||||
|
||||
/// Flat (Vec) backed map
|
||||
///
|
||||
/// This preserves insertion order
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct FlatMap<K, V> {
|
||||
keys: Vec<K>,
|
||||
values: Vec<V>,
|
||||
}
|
||||
|
||||
impl<K: PartialEq + Eq, V> FlatMap<K, V> {
|
||||
pub(crate) fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, key: K, mut value: V) -> Option<V> {
|
||||
for (index, existing) in self.keys.iter().enumerate() {
|
||||
if *existing == key {
|
||||
std::mem::swap(&mut self.values[index], &mut value);
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
self.insert_unchecked(key, value);
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn insert_unchecked(&mut self, key: K, value: V) {
|
||||
self.keys.push(key);
|
||||
self.values.push(value);
|
||||
}
|
||||
|
||||
pub(crate) fn extend_unchecked(&mut self, iter: impl IntoIterator<Item = (K, V)>) {
|
||||
for (key, value) in iter {
|
||||
self.insert_unchecked(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
for existing in &self.keys {
|
||||
if existing.borrow() == key {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: std::hash::Hash + Eq,
|
||||
{
|
||||
self.remove_entry(key).map(|(_, v)| v)
|
||||
}
|
||||
|
||||
pub(crate) fn remove_entry<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: std::hash::Hash + Eq,
|
||||
{
|
||||
let index = some!(
|
||||
self.keys
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(|(i, k)| (k.borrow() == key).then_some(i))
|
||||
);
|
||||
let key = self.keys.remove(index);
|
||||
let value = self.values.remove(index);
|
||||
Some((key, value))
|
||||
}
|
||||
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.keys.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn entry(&mut self, key: K) -> Entry<'_, K, V> {
|
||||
for (index, existing) in self.keys.iter().enumerate() {
|
||||
if *existing == key {
|
||||
return Entry::Occupied(OccupiedEntry { v: self, index });
|
||||
}
|
||||
}
|
||||
Entry::Vacant(VacantEntry { v: self, key })
|
||||
}
|
||||
|
||||
pub(crate) fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
for (index, existing) in self.keys.iter().enumerate() {
|
||||
if existing.borrow() == k {
|
||||
return Some(&self.values[index]);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
for (index, existing) in self.keys.iter().enumerate() {
|
||||
if existing.borrow() == k {
|
||||
return Some(&mut self.values[index]);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn keys(&self) -> std::slice::Iter<'_, K> {
|
||||
self.keys.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn values(&self) -> std::slice::Iter<'_, V> {
|
||||
self.values.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> Iter<'_, K, V> {
|
||||
Iter {
|
||||
keys: self.keys.iter(),
|
||||
values: self.values.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn iter_mut(&mut self) -> IterMut<'_, K, V> {
|
||||
IterMut {
|
||||
keys: self.keys.iter_mut(),
|
||||
values: self.values.iter_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: PartialEq + Eq, V> Default for FlatMap<K, V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
keys: Default::default(),
|
||||
values: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum Entry<'a, K, V> {
|
||||
Vacant(VacantEntry<'a, K, V>),
|
||||
Occupied(OccupiedEntry<'a, K, V>),
|
||||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a> Entry<'a, K, V> {
|
||||
pub(crate) fn or_insert(self, default: V) -> &'a mut V {
|
||||
match self {
|
||||
Entry::Occupied(entry) => &mut entry.v.values[entry.index],
|
||||
Entry::Vacant(entry) => {
|
||||
entry.v.keys.push(entry.key);
|
||||
entry.v.values.push(default);
|
||||
entry.v.values.last_mut().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
|
||||
match self {
|
||||
Entry::Occupied(entry) => &mut entry.v.values[entry.index],
|
||||
Entry::Vacant(entry) => {
|
||||
entry.v.keys.push(entry.key);
|
||||
entry.v.values.push(default());
|
||||
entry.v.values.last_mut().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct VacantEntry<'a, K, V> {
|
||||
v: &'a mut FlatMap<K, V>,
|
||||
key: K,
|
||||
}
|
||||
|
||||
pub(crate) struct OccupiedEntry<'a, K, V> {
|
||||
v: &'a mut FlatMap<K, V>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
pub(crate) struct Iter<'a, K, V> {
|
||||
keys: std::slice::Iter<'a, K>,
|
||||
values: std::slice::Iter<'a, V>,
|
||||
}
|
||||
|
||||
impl<'a, K, V> Iterator for Iter<'a, K, V> {
|
||||
type Item = (&'a K, &'a V);
|
||||
|
||||
fn next(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
match self.keys.next() {
|
||||
Some(k) => {
|
||||
let v = self.values.next().unwrap();
|
||||
Some((k, v))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.keys.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> DoubleEndedIterator for Iter<'a, K, V> {
|
||||
fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
match self.keys.next_back() {
|
||||
Some(k) => {
|
||||
let v = self.values.next_back().unwrap();
|
||||
Some((k, v))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> ExactSizeIterator for Iter<'_, K, V> {}
|
||||
|
||||
pub(crate) struct IterMut<'a, K, V> {
|
||||
keys: std::slice::IterMut<'a, K>,
|
||||
values: std::slice::IterMut<'a, V>,
|
||||
}
|
||||
|
||||
impl<'a, K, V> Iterator for IterMut<'a, K, V> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
|
||||
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
match self.keys.next() {
|
||||
Some(k) => {
|
||||
let v = self.values.next().unwrap();
|
||||
Some((k, v))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.keys.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> DoubleEndedIterator for IterMut<'a, K, V> {
|
||||
fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
match self.keys.next_back() {
|
||||
Some(k) => {
|
||||
let v = self.values.next_back().unwrap();
|
||||
Some((k, v))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> ExactSizeIterator for IterMut<'_, K, V> {}
|
||||
111
third_party/crates/clap_builder-4.6.7/src/util/flat_set.rs
vendored
Normal file
111
third_party/crates/clap_builder-4.6.7/src/util/flat_set.rs
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::borrow::Borrow;
|
||||
|
||||
/// Flat (Vec) backed set
|
||||
///
|
||||
/// This preserves insertion order
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct FlatSet<T> {
|
||||
inner: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq> FlatSet<T> {
|
||||
pub(crate) fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, value: T) -> bool {
|
||||
for existing in &self.inner {
|
||||
if *existing == value {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.inner.push(value);
|
||||
true
|
||||
}
|
||||
|
||||
pub(crate) fn contains<Q: ?Sized>(&self, value: &Q) -> bool
|
||||
where
|
||||
T: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
for existing in &self.inner {
|
||||
if existing.borrow() == value {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn retain<F>(&mut self, f: F)
|
||||
where
|
||||
F: FnMut(&T) -> bool,
|
||||
{
|
||||
self.inner.retain(f);
|
||||
}
|
||||
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> std::slice::Iter<'_, T> {
|
||||
self.inner.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn sort_by_key<K, F>(&mut self, f: F)
|
||||
where
|
||||
F: FnMut(&T) -> K,
|
||||
K: Ord,
|
||||
{
|
||||
self.inner.sort_by_key(f);
|
||||
}
|
||||
|
||||
pub(crate) fn into_vec(self) -> Vec<T> {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq> Default for FlatSet<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq> IntoIterator for FlatSet<T> {
|
||||
type Item = T;
|
||||
type IntoIter = std::vec::IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.inner.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, T: PartialEq + Eq> IntoIterator for &'s FlatSet<T> {
|
||||
type Item = &'s T;
|
||||
type IntoIter = std::slice::Iter<'s, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.inner.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq> Extend<T> for FlatSet<T> {
|
||||
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||
for value in iter {
|
||||
self.insert(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq> FromIterator<T> for FlatSet<T> {
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
let mut set = Self::new();
|
||||
for value in iter {
|
||||
set.insert(value);
|
||||
}
|
||||
set
|
||||
}
|
||||
}
|
||||
49
third_party/crates/clap_builder-4.6.7/src/util/graph.rs
vendored
Normal file
49
third_party/crates/clap_builder-4.6.7/src/util/graph.rs
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
#[derive(Debug)]
|
||||
struct Child<T> {
|
||||
id: T,
|
||||
children: Vec<usize>,
|
||||
}
|
||||
|
||||
impl<T> Child<T> {
|
||||
fn new(id: T) -> Self {
|
||||
Self {
|
||||
id,
|
||||
children: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ChildGraph<T>(Vec<Child<T>>);
|
||||
|
||||
impl<T> ChildGraph<T>
|
||||
where
|
||||
T: Sized + PartialEq + Clone,
|
||||
{
|
||||
pub(crate) fn with_capacity(s: usize) -> Self {
|
||||
Self(Vec::with_capacity(s))
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, req: T) -> usize {
|
||||
self.0.iter().position(|e| e.id == req).unwrap_or_else(|| {
|
||||
let idx = self.0.len();
|
||||
self.0.push(Child::new(req));
|
||||
idx
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn insert_child(&mut self, parent: usize, child: T) -> usize {
|
||||
let c_idx = self.0.len();
|
||||
self.0.push(Child::new(child));
|
||||
self.0[parent].children.push(c_idx);
|
||||
c_idx
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &T> {
|
||||
self.0.iter().map(|r| &r.id)
|
||||
}
|
||||
|
||||
pub(crate) fn contains(&self, req: &T) -> bool {
|
||||
self.0.iter().any(|r| r.id == *req)
|
||||
}
|
||||
}
|
||||
195
third_party/crates/clap_builder-4.6.7/src/util/id.rs
vendored
Normal file
195
third_party/crates/clap_builder-4.6.7/src/util/id.rs
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
use crate::builder::Str;
|
||||
#[cfg(feature = "string")]
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// [`Arg`][crate::Arg] or [`ArgGroup`][crate::ArgGroup] identifier
|
||||
///
|
||||
/// This is used for accessing the value in [`ArgMatches`][crate::ArgMatches] or defining
|
||||
/// relationships between `Arg`s and `ArgGroup`s with functions like
|
||||
/// [`Arg::conflicts_with`][crate::Arg::conflicts_with].
|
||||
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct Id(Str);
|
||||
|
||||
impl Id {
|
||||
pub(crate) const HELP: &'static str = "help";
|
||||
pub(crate) const VERSION: &'static str = "version";
|
||||
pub(crate) const EXTERNAL: &'static str = "";
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static str) -> Self {
|
||||
Self(Str::from_static_ref(name))
|
||||
}
|
||||
|
||||
/// Get the raw string of the `Id`
|
||||
pub fn as_str(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
|
||||
pub(crate) fn as_internal_str(&self) -> &Str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Self> for Id {
|
||||
fn from(id: &'_ Self) -> Self {
|
||||
id.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for Id {
|
||||
fn from(name: Str) -> Self {
|
||||
Self(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Str> for Id {
|
||||
fn from(name: &'_ Str) -> Self {
|
||||
Self(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<String> for Id {
|
||||
fn from(name: String) -> Self {
|
||||
Self(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ String> for Id {
|
||||
fn from(name: &'_ String) -> Self {
|
||||
Self(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Id {
|
||||
fn from(name: &'static str) -> Self {
|
||||
Self(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static str> for Id {
|
||||
fn from(name: &'_ &'static str) -> Self {
|
||||
Self(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Id> for Str {
|
||||
fn from(name: Id) -> Self {
|
||||
name.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<Cow<'static, str>> for Id {
|
||||
fn from(name: Cow<'static, str>) -> Self {
|
||||
Self(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Id> for String {
|
||||
fn from(name: Id) -> Self {
|
||||
Str::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Id {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Id {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Id {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::borrow::Borrow<str> for Id {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for Id {
|
||||
#[inline]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
PartialEq::eq(self.as_str(), other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Id> for str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Id) -> bool {
|
||||
PartialEq::eq(self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ str> for Id {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
PartialEq::eq(self.as_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Id> for &'_ str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Id) -> bool {
|
||||
PartialEq::eq(*self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Str> for Id {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<Id> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Id) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<String> for Id {
|
||||
#[inline]
|
||||
fn eq(&self, other: &String) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<Id> for String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Id) -> bool {
|
||||
PartialEq::eq(other, self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(feature = "string")]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "string")]
|
||||
fn from_cow_borrowed() {
|
||||
let cow = Cow::Borrowed("hello");
|
||||
let id = Id::from(cow);
|
||||
assert_eq!(id, Id::from("hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "string")]
|
||||
fn from_cow_owned() {
|
||||
let cow = Cow::Owned("world".to_owned());
|
||||
let id = Id::from(cow);
|
||||
assert_eq!(id, Id::from("world"));
|
||||
}
|
||||
}
|
||||
40
third_party/crates/clap_builder-4.6.7/src/util/mod.rs
vendored
Normal file
40
third_party/crates/clap_builder-4.6.7/src/util/mod.rs
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
#![allow(clippy::single_component_path_imports)]
|
||||
|
||||
mod any_value;
|
||||
mod escape;
|
||||
pub(crate) mod flat_map;
|
||||
pub(crate) mod flat_set;
|
||||
mod graph;
|
||||
mod id;
|
||||
mod str_to_bool;
|
||||
|
||||
pub use self::id::Id;
|
||||
|
||||
pub(crate) use self::any_value::AnyValue;
|
||||
pub(crate) use self::any_value::AnyValueId;
|
||||
pub(crate) use self::escape::Escape;
|
||||
pub(crate) use self::flat_map::Entry;
|
||||
pub(crate) use self::flat_map::FlatMap;
|
||||
pub(crate) use self::flat_set::FlatSet;
|
||||
pub(crate) use self::graph::ChildGraph;
|
||||
pub(crate) use self::str_to_bool::FALSE_LITERALS;
|
||||
pub(crate) use self::str_to_bool::TRUE_LITERALS;
|
||||
pub(crate) use self::str_to_bool::str_to_bool;
|
||||
|
||||
pub(crate) mod color;
|
||||
|
||||
pub(crate) const SUCCESS_CODE: i32 = 0;
|
||||
// While sysexists.h defines EX_USAGE as 64, this doesn't seem to be used much in practice but
|
||||
// instead 2 seems to be frequently used.
|
||||
// Examples
|
||||
// - GNU `ls` returns 2
|
||||
// - Python's `argparse` returns 2
|
||||
pub(crate) const USAGE_CODE: i32 = 2;
|
||||
|
||||
#[cfg(not(feature = "unicode"))]
|
||||
pub(crate) fn eq_ignore_case(left: &str, right: &str) -> bool {
|
||||
left.eq_ignore_ascii_case(right)
|
||||
}
|
||||
|
||||
#[cfg(feature = "unicode")]
|
||||
pub(crate) use unicase::eq as eq_ignore_case;
|
||||
21
third_party/crates/clap_builder-4.6.7/src/util/str_to_bool.rs
vendored
Normal file
21
third_party/crates/clap_builder-4.6.7/src/util/str_to_bool.rs
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/// True values are `y`, `yes`, `t`, `true`, `on`, and `1`.
|
||||
pub(crate) const TRUE_LITERALS: [&str; 6] = ["y", "yes", "t", "true", "on", "1"];
|
||||
|
||||
/// False values are `n`, `no`, `f`, `false`, `off`, and `0`.
|
||||
pub(crate) const FALSE_LITERALS: [&str; 6] = ["n", "no", "f", "false", "off", "0"];
|
||||
|
||||
/// Converts a string literal representation of truth to true or false.
|
||||
///
|
||||
/// `false` values are `n`, `no`, `f`, `false`, `off`, and `0` (case insensitive).
|
||||
///
|
||||
/// Any other value will be considered as `true`.
|
||||
pub(crate) fn str_to_bool(val: impl AsRef<str>) -> Option<bool> {
|
||||
let pat: &str = &val.as_ref().to_lowercase();
|
||||
if TRUE_LITERALS.contains(&pat) {
|
||||
Some(true)
|
||||
} else if FALSE_LITERALS.contains(&pat) {
|
||||
Some(false)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user