Bug 1770072 - Upgrade geckodriver to clap 3.1. r=webdriver-reviewers,jgraham

Differential Revision: https://phabricator.services.mozilla.com/D146753
This commit is contained in:
Mike Hommey 2022-05-24 08:17:58 +00:00
Родитель c8b2b8d7b4
Коммит bc89e96a24
123 изменённых файлов: 13620 добавлений и 8106 удалений

22
Cargo.lock сгенерированный
Просмотреть файл

@ -704,19 +704,28 @@ dependencies = [
[[package]]
name = "clap"
version = "3.0.10"
version = "3.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b"
dependencies = [
"bitflags",
"clap_lex",
"indexmap",
"lazy_static",
"os_str_bytes",
"strsim",
"terminal_size",
"textwrap",
]
[[package]]
name = "clap_lex"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "cmake"
version = "0.1.999"
@ -3753,9 +3762,6 @@ name = "os_str_bytes"
version = "6.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435"
dependencies = [
"memchr",
]
[[package]]
name = "osclientcerts-static"
@ -5071,9 +5077,9 @@ dependencies = [
[[package]]
name = "textwrap"
version = "0.14.2"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
dependencies = [
"terminal_size",
]

Просмотреть файл

@ -12,7 +12,7 @@ edition = "2018"
[dependencies]
base64 = "0.12"
chrono = "0.4.6"
clap = { version = "3", default-features = false, features = ["cargo", "std", "suggestions", "wrap_help"] }
clap = { version = "3.1", default-features = false, features = ["cargo", "std", "suggestions", "wrap_help"] }
hyper = "0.13"
lazy_static = "1.0"
log = { version = "0.4", features = ["std"] }

Просмотреть файл

@ -34,7 +34,7 @@ use std::path::PathBuf;
use std::result;
use std::str::FromStr;
use clap::{App, AppSettings, Arg};
use clap::{AppSettings, Arg, Command};
macro_rules! try_opt {
($expr:expr, $err_type:expr, $err_msg:expr) => {{
@ -234,8 +234,8 @@ fn get_allowed_origins(allow_origins: Option<clap::Values>) -> Result<Vec<Url>,
.unwrap_or_else(|| Ok(vec![]))
}
fn parse_args(app: &mut App) -> ProgramResult<Operation> {
let args = app.try_get_matches_from_mut(env::args())?;
fn parse_args(cmd: &mut Command) -> ProgramResult<Operation> {
let args = cmd.try_get_matches_from_mut(env::args())?;
if args.is_present("help") {
return Ok(Operation::Help);
@ -340,9 +340,9 @@ fn parse_args(app: &mut App) -> ProgramResult<Operation> {
})
}
fn inner_main(app: &mut App) -> ProgramResult<()> {
match parse_args(app)? {
Operation::Help => print_help(app),
fn inner_main(cmd: &mut Command) -> ProgramResult<()> {
match parse_args(cmd)? {
Operation::Help => print_help(cmd),
Operation::Version => print_version(),
Operation::Server {
@ -381,16 +381,16 @@ fn inner_main(app: &mut App) -> ProgramResult<()> {
fn main() {
use std::process::exit;
let mut app = make_app();
let mut cmd = make_command();
// use std::process:Termination when it graduates
exit(match inner_main(&mut app) {
exit(match inner_main(&mut cmd) {
Ok(_) => EXIT_SUCCESS,
Err(e) => {
eprintln!("{}: {}", get_program_name(), e);
if !e.help_included() {
print_help(&mut app);
print_help(&mut cmd);
}
e.exit_code()
@ -398,8 +398,8 @@ fn main() {
});
}
fn make_app<'a>() -> App<'a> {
App::new(format!("geckodriver {}", build::build_info()))
fn make_command<'a>() -> Command<'a> {
Command::new(format!("geckodriver {}", build::build_info()))
.setting(AppSettings::NoAutoHelp)
.setting(AppSettings::NoAutoVersion)
.about("WebDriver implementation for Firefox")
@ -525,8 +525,8 @@ fn get_program_name() -> String {
env::args().next().unwrap()
}
fn print_help(app: &mut App) {
app.print_help().ok();
fn print_help(cmd: &mut Command) {
cmd.print_help().ok();
println!();
}

2
third_party/rust/clap/.cargo-checksum.json поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

303
third_party/rust/clap/Cargo.lock сгенерированный поставляемый
Просмотреть файл

@ -39,15 +39,15 @@ dependencies = [
[[package]]
name = "autocfg"
version = "1.0.1"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
version = "0.3.63"
version = "0.3.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6"
checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61"
dependencies = [
"addr2line",
"cc",
@ -78,9 +78,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.8.0"
version = "3.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
[[package]]
name = "bytes"
@ -99,9 +99,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.72"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cfg-if"
@ -111,9 +111,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "2.33.3"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"bitflags",
"textwrap 0.11.0",
@ -122,22 +122,25 @@ dependencies = [
[[package]]
name = "clap"
version = "3.0.10"
version = "3.1.18"
dependencies = [
"atty",
"backtrace",
"bitflags",
"clap_derive",
"clap_lex",
"criterion",
"humantime",
"indexmap",
"lazy_static",
"os_str_bytes",
"regex",
"rustversion",
"shlex",
"snapbox",
"strsim",
"termcolor",
"terminal_size",
"textwrap 0.14.2",
"textwrap 0.15.0",
"trybuild",
"trycmd",
"unicase",
@ -146,9 +149,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "3.0.6"
version = "3.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153"
checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c"
dependencies = [
"heck",
"proc-macro-error",
@ -158,20 +161,29 @@ dependencies = [
]
[[package]]
name = "combine"
version = "4.6.2"
name = "clap_lex"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5"
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "combine"
version = "4.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948"
dependencies = [
"bytes",
"memchr",
]
[[package]]
name = "concolor-control"
version = "0.0.7"
name = "concolor"
version = "0.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7104119c2f80d887239879d0c50e033cd40eac9a3f3561e0684ba7d5d654f4da"
checksum = "015267563b1df20adccdd00cb05257b1dfbea70a04928e9cf88ffb850c1a40af"
dependencies = [
"atty",
"bitflags",
@ -180,9 +192,9 @@ dependencies = [
[[package]]
name = "concolor-query"
version = "0.0.4"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad159cc964ac8f9d407cbc0aa44b02436c054b541f2b4b5f06972e1efdc54bc7"
checksum = "d6417fe6fc03a8b533fd2177742eeb39a90c7233eedec7bac96d4d6b69a09449"
[[package]]
name = "criterion"
@ -192,7 +204,7 @@ checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
dependencies = [
"atty",
"cast",
"clap 2.33.3",
"clap 2.34.0",
"criterion-plot",
"csv",
"itertools",
@ -222,9 +234,9 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
version = "0.5.1"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
dependencies = [
"cfg-if",
"crossbeam-utils",
@ -243,10 +255,11 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
version = "0.9.5"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"lazy_static",
@ -256,9 +269,9 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.8.5"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
dependencies = [
"cfg-if",
"lazy_static",
@ -272,7 +285,7 @@ checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
dependencies = [
"bstr",
"csv-core",
"itoa",
"itoa 0.4.8",
"ryu",
"serde",
]
@ -286,12 +299,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "difflib"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]]
name = "either"
version = "1.6.1"
@ -357,9 +364,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "humantime-serde"
version = "1.0.1"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac34a56cfd4acddb469cc7fff187ed5ac36f498ba085caf8bbc725e3ff474058"
checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c"
dependencies = [
"humantime",
"serde",
@ -367,9 +374,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "1.7.0"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [
"autocfg",
"hashbrown",
@ -377,9 +384,9 @@ dependencies = [
[[package]]
name = "itertools"
version = "0.10.1"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
@ -391,21 +398,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "js-sys"
version = "0.3.55"
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
dependencies = [
"wasm-bindgen",
]
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "kstring"
version = "1.0.6"
name = "js-sys"
version = "0.3.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b310ccceade8121d7d77fee406160e457c2f4e7c7982d589da3499bc7ea4526"
checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397"
dependencies = [
"serde",
"wasm-bindgen",
]
[[package]]
@ -416,9 +420,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.107"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
[[package]]
name = "linked-hash-map"
@ -428,36 +432,35 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "log"
version = "0.4.14"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.4.1"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
version = "0.6.4"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.4.4"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
dependencies = [
"adler",
"autocfg",
]
[[package]]
@ -468,18 +471,18 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]]
name = "num-traits"
version = "0.2.14"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [
"hermit-abi",
"libc",
@ -487,18 +490,18 @@ dependencies = [
[[package]]
name = "object"
version = "0.27.1"
version = "0.28.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
checksum = "40bec70ba014595f99f7aa110b84331ffe1ee9aece7fe6f387cc7e3ecda4d456"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.8.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "oorandom"
@ -508,9 +511,9 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "os_pipe"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e3492ebca331b895fe23ed427dce2013d9b2e00c45964f12040b0db38b8ab27"
checksum = "2c92f2b54f081d635c77e7120862d48db8e91f7f21cef23ab1b4fe9971c59f55"
dependencies = [
"libc",
"winapi",
@ -521,9 +524,6 @@ name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]]
name = "plotters"
@ -579,27 +579,27 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.32"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.10"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rayon"
version = "1.5.1"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221"
dependencies = [
"autocfg",
"crossbeam-deque",
@ -609,22 +609,21 @@ dependencies = [
[[package]]
name = "rayon-core"
version = "1.9.1"
version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static",
"num_cpus",
]
[[package]]
name = "regex"
version = "1.5.4"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
@ -660,15 +659,15 @@ dependencies = [
[[package]]
name = "rustversion"
version = "1.0.5"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
[[package]]
name = "ryu"
version = "1.0.5"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "same-file"
@ -687,15 +686,15 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semver"
version = "1.0.4"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd"
[[package]]
name = "serde"
version = "1.0.130"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
dependencies = [
"serde_derive",
]
@ -712,9 +711,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.130"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
dependencies = [
"proc-macro2",
"quote",
@ -723,11 +722,11 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.69"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
dependencies = [
"itoa",
"itoa 1.0.1",
"ryu",
"serde",
]
@ -738,6 +737,33 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
[[package]]
name = "similar"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3"
[[package]]
name = "snapbox"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "767a1d5da232b6959cd1bd5c9e8db8a7cce09c3038e89deedb49a549a2aefd93"
dependencies = [
"concolor",
"normalize-line-endings",
"os_pipe",
"similar",
"snapbox-macros",
"wait-timeout",
"yansi",
]
[[package]]
name = "snapbox-macros"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c01dea7e04cbb27ef4c86e9922184608185f7cd95c1763bc30d727cda4a5e930"
[[package]]
name = "strsim"
version = "0.10.0"
@ -746,9 +772,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.81"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52"
dependencies = [
"proc-macro2",
"quote",
@ -757,9 +783,9 @@ dependencies = [
[[package]]
name = "termcolor"
version = "1.1.2"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
@ -785,9 +811,9 @@ dependencies = [
[[package]]
name = "textwrap"
version = "0.14.2"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
dependencies = [
"terminal_size",
"unicode-width",
@ -805,35 +831,35 @@ dependencies = [
[[package]]
name = "toml"
version = "0.5.8"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.12.3"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f2d523490d6542d4ffa1f1a7cae4d0c9f2ee634bf4e779b0f5ff5fde74dd4b6"
checksum = "ba98375fd631b83696f87c64e4ed8e29e6a1f3404d6aed95fa95163bad38e705"
dependencies = [
"combine",
"indexmap",
"itertools",
"kstring",
"serde",
]
[[package]]
name = "trybuild"
version = "1.0.52"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "150e726dc059e6fbd4fce3288f5bb3cf70128cf63b0dde23b938a3cad810fb23"
checksum = "7fc92f558afb6d1d7c6f175eb8d615b8ef49c227543e68e19c123d4ee43d8a7d"
dependencies = [
"glob",
"lazy_static",
"once_cell",
"serde",
"serde_derive",
"serde_json",
"termcolor",
"toml",
@ -841,24 +867,19 @@ dependencies = [
[[package]]
name = "trycmd"
version = "0.9.0"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a03bb057469ddca02e598e6c84e771bfdc464f188803d3101f133d6643e638d"
checksum = "ffb4185126cc904642173a54c185083f410c86d1202ada6761aacf7c40829f13"
dependencies = [
"concolor-control",
"difflib",
"escargot",
"glob",
"humantime",
"humantime-serde",
"normalize-line-endings",
"os_pipe",
"rayon",
"serde",
"shlex",
"snapbox",
"toml_edit",
"wait-timeout",
"yansi",
]
[[package]]
@ -878,15 +899,15 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
[[package]]
name = "version_check"
version = "0.9.3"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wait-timeout"
@ -910,9 +931,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.78"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@ -920,9 +941,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.78"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4"
dependencies = [
"bumpalo",
"lazy_static",
@ -935,9 +956,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.78"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -945,9 +966,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.78"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b"
dependencies = [
"proc-macro2",
"quote",
@ -958,15 +979,15 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.78"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744"
[[package]]
name = "web-sys"
version = "0.3.55"
version = "0.3.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -1014,6 +1035,6 @@ dependencies = [
[[package]]
name = "yansi"
version = "0.5.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"

225
third_party/rust/clap/Cargo.toml поставляемый
Просмотреть файл

@ -12,19 +12,40 @@
[package]
edition = "2018"
name = "clap"
version = "3.0.10"
include = ["build.rs", "src/**/*", "Cargo.toml", "LICENSE*", "README.md", "benches/**/*", "examples/**/*"]
version = "3.1.18"
include = [
"build.rs",
"src/**/*",
"Cargo.toml",
"LICENSE*",
"README.md",
"benches/**/*",
"examples/**/*",
]
description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
documentation = "https://docs.rs/clap/"
readme = "README.md"
keywords = ["argument", "cli", "arg", "parser", "parse"]
keywords = [
"argument",
"cli",
"arg",
"parser",
"parse",
]
categories = ["command-line-interface"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/clap-rs/clap"
[package.metadata.docs.rs]
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples=examples"]
features = ["unstable-doc"]
rustdoc-args = ["--cfg", "docsrs"]
rustdoc-args = [
"--cfg",
"docsrs",
]
cargo-args = [
"-Zunstable-options",
"-Zrustdoc-scrape-examples=examples",
]
[package.metadata.playground]
features = ["unstable-doc"]
@ -35,54 +56,60 @@ tag-name = "v{{version}}"
[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"
min = 1
replace = "{{version}}"
search = "Unreleased"
[[package.metadata.release.pre-release-replacements]]
exactly = 1
file = "CHANGELOG.md"
replace = "...{{tag_name}}"
search = "\\.\\.\\.HEAD"
[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"
replace = "{{version}}"
min = 1
replace = "{{date}}"
[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"
search = '\.\.\.HEAD'
replace = "...{{tag_name}}"
exactly = 1
[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"
search = "ReleaseDate"
replace = "{{date}}"
min = 1
[[package.metadata.release.pre-release-replacements]]
exactly = 1
file = "CHANGELOG.md"
replace = "<!-- next-header -->\n## [Unreleased] - ReleaseDate\n"
search = "<!-- next-header -->"
replace = """
<!-- next-header -->
## [Unreleased] - ReleaseDate
"""
exactly = 1
[[package.metadata.release.pre-release-replacements]]
exactly = 1
file = "CHANGELOG.md"
replace = "<!-- next-url -->\n[Unreleased]: https://github.com/clap-rs/clap/compare/{{tag_name}}...HEAD"
search = "<!-- next-url -->"
[[package.metadata.release.pre-release-replacements]]
exactly = 9
file = "README.md"
prerelease = true
replace = "github.com/clap-rs/clap/blob/{{tag_name}}/"
search = "github.com/clap-rs/clap/blob/[^/]+/"
[[package.metadata.release.pre-release-replacements]]
replace = """
<!-- next-url -->
[Unreleased]: https://github.com/clap-rs/clap/compare/{{tag_name}}...HEAD"""
exactly = 1
file = "README.md"
prerelease = true
replace = "version = \"{{version}}\""
search = "version = \"[a-z0-9\\.-]+\""
[[package.metadata.release.pre-release-replacements]]
exactly = 4
file = "src/derive.rs"
prerelease = true
replace = "github.com/clap-rs/clap/blob/{{tag_name}}/"
file = "README.md"
search = "github.com/clap-rs/clap/blob/[^/]+/"
replace = "github.com/clap-rs/clap/blob/{{tag_name}}/"
exactly = 13
prerelease = true
[[package.metadata.release.pre-release-replacements]]
file = "README.md"
search = 'version = "[a-z0-9\.-]+"'
replace = "version = \"{{version}}\""
exactly = 1
prerelease = true
[[package.metadata.release.pre-release-replacements]]
file = "src/derive.rs"
search = "github.com/clap-rs/clap/blob/[^/]+/"
replace = "github.com/clap-rs/clap/blob/{{tag_name}}/"
exactly = 4
prerelease = true
[profile.bench]
lto = true
codegen-units = 1
@ -118,7 +145,7 @@ name = "git-derive"
required-features = ["derive"]
[[example]]
name = "keyvalue-derive"
name = "typed-derive"
required-features = ["derive"]
[[example]]
@ -131,6 +158,11 @@ name = "hostname"
path = "examples/multicall-hostname.rs"
required-features = ["unstable-multicall"]
[[example]]
name = "repl"
path = "examples/repl.rs"
required-features = ["unstable-multicall"]
[[example]]
name = "01_quick"
path = "examples/tutorial_builder/01_quick.rs"
@ -139,7 +171,6 @@ required-features = ["cargo"]
[[example]]
name = "02_apps"
path = "examples/tutorial_builder/02_apps.rs"
required-features = ["cargo"]
[[example]]
name = "02_crate"
@ -189,7 +220,15 @@ required-features = ["cargo"]
[[example]]
name = "04_01_enum"
path = "examples/tutorial_builder/04_01_enum.rs"
required-features = ["cargo", "derive"]
required-features = [
"cargo",
"derive",
]
[[example]]
name = "04_02_parse"
path = "examples/tutorial_builder/04_02_parse.rs"
required-features = ["cargo"]
[[example]]
name = "04_02_validate"
@ -257,6 +296,11 @@ name = "03_04_subcommands_derive"
path = "examples/tutorial_derive/03_04_subcommands.rs"
required-features = ["derive"]
[[example]]
name = "03_04_subcommands_alt_derive"
path = "examples/tutorial_derive/03_04_subcommands_alt.rs"
required-features = ["derive"]
[[example]]
name = "03_05_default_values_derive"
path = "examples/tutorial_derive/03_05_default_values.rs"
@ -267,6 +311,11 @@ name = "04_01_enum_derive"
path = "examples/tutorial_derive/04_01_enum.rs"
required-features = ["derive"]
[[example]]
name = "04_02_parse_derive"
path = "examples/tutorial_derive/04_02_parse.rs"
required-features = ["derive"]
[[example]]
name = "04_02_validate_derive"
path = "examples/tutorial_derive/04_02_validate.rs"
@ -293,6 +342,26 @@ name = "custom-bool"
path = "examples/derive_ref/custom-bool.rs"
required-features = ["derive"]
[[example]]
name = "interop_augment_args"
path = "examples/derive_ref/augment_args.rs"
required-features = ["derive"]
[[example]]
name = "interop_augment_subcommands"
path = "examples/derive_ref/augment_subcommands.rs"
required-features = ["derive"]
[[example]]
name = "interop_hand_subcommand"
path = "examples/derive_ref/hand_subcommand.rs"
required-features = ["derive"]
[[example]]
name = "interop_flatten_hand_args"
path = "examples/derive_ref/flatten_hand_args.rs"
required-features = ["derive"]
[[bench]]
name = "01_default"
path = "benches/01_default.rs"
@ -322,6 +391,7 @@ harness = false
name = "06_rustup"
path = "benches/06_rustup.rs"
harness = false
[dependencies.atty]
version = "0.2"
optional = true
@ -334,9 +404,12 @@ optional = true
version = "1.2"
[dependencies.clap_derive]
version = "3.0.0"
version = "=3.1.18"
optional = true
[dependencies.clap_lex]
version = "0.2.0"
[dependencies.indexmap]
version = "1.0"
@ -344,9 +417,6 @@ version = "1.0"
version = "1"
optional = true
[dependencies.os_str_bytes]
version = "6.0"
[dependencies.regex]
version = "1.0"
optional = true
@ -364,7 +434,7 @@ version = "0.1.12"
optional = true
[dependencies.textwrap]
version = "0.14.0"
version = "0.15.0"
features = []
default-features = false
@ -375,9 +445,13 @@ optional = true
[dependencies.yaml-rust]
version = "0.4.1"
optional = true
[dev-dependencies.criterion]
version = "0.3.2"
[dev-dependencies.humantime]
version = "2"
[dev-dependencies.lazy_static]
version = "1"
@ -387,27 +461,68 @@ version = "1.0"
[dev-dependencies.rustversion]
version = "1"
[dev-dependencies.shlex]
version = "1.1.0"
[dev-dependencies.snapbox]
version = "0.2.9"
[dev-dependencies.trybuild]
version = "1.0.18"
[dev-dependencies.trycmd]
version = "0.9"
features = ["color-auto", "diff", "examples"]
version = "0.13"
features = [
"color-auto",
"diff",
"examples",
]
default-features = false
[features]
cargo = ["lazy_static"]
color = ["atty", "termcolor"]
debug = ["clap_derive/debug", "backtrace"]
default = ["std", "color", "suggestions"]
derive = ["clap_derive", "lazy_static"]
color = [
"atty",
"termcolor",
]
debug = [
"clap_derive/debug",
"backtrace",
]
default = [
"std",
"color",
"suggestions",
]
derive = [
"clap_derive",
"lazy_static",
]
env = []
std = ["indexmap/std"]
suggestions = ["strsim"]
unicode = ["textwrap/unicode-width", "unicase"]
unstable-doc = ["derive", "cargo", "wrap_help", "yaml", "env", "unicode", "regex", "unstable-replace", "unstable-multicall", "unstable-grouped"]
unicode = [
"textwrap/unicode-width",
"unicase",
]
unstable-doc = [
"derive",
"cargo",
"wrap_help",
"yaml",
"env",
"unicode",
"regex",
"unstable-replace",
"unstable-multicall",
"unstable-grouped",
]
unstable-grouped = []
unstable-multicall = []
unstable-replace = []
wrap_help = ["terminal_size", "textwrap/terminal_size"]
unstable-v4 = ["clap_derive/unstable-v4"]
wrap_help = [
"terminal_size",
"textwrap/terminal_size",
]
yaml = ["yaml-rust"]

47
third_party/rust/clap/README.md поставляемый
Просмотреть файл

@ -5,8 +5,8 @@
[![Crates.io](https://img.shields.io/crates/v/clap?style=flat-square)](https://crates.io/crates/clap)
[![Crates.io](https://img.shields.io/crates/d/clap?style=flat-square)](https://crates.io/crates/clap)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/v3.0.10/LICENSE-APACHE)
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/v3.0.10/LICENSE-MIT)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/v3.1.18/LICENSE-APACHE)
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/v3.1.18/LICENSE-MIT)
[![Build Status](https://img.shields.io/github/workflow/status/clap-rs/clap/CI/staging?style=flat-square)](https://github.com/clap-rs/clap/actions/workflows/ci.yml?query=branch%3Astaging)
[![Coverage Status](https://img.shields.io/coveralls/github/clap-rs/clap/master?style=flat-square)](https://coveralls.io/github/clap-rs/clap?branch=master)
[![Contributors](https://img.shields.io/github/contributors/clap-rs/clap?style=flat-square)](https://github.com/clap-rs/clap/graphs/contributors)
@ -14,15 +14,15 @@
Dual-licensed under [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT).
1. [About](#about)
2. Tutorial: [Builder API](https://github.com/clap-rs/clap/blob/v3.0.10/examples/tutorial_builder/README.md), [Derive API](https://github.com/clap-rs/clap/blob/v3.0.10/examples/tutorial_derive/README.md)
3. [Examples](https://github.com/clap-rs/clap/blob/v3.0.10/examples/README.md)
2. Tutorial: [Builder API](https://github.com/clap-rs/clap/blob/v3.1.18/examples/tutorial_builder/README.md), [Derive API](https://github.com/clap-rs/clap/blob/v3.1.18/examples/tutorial_derive/README.md)
3. [Examples](https://github.com/clap-rs/clap/blob/v3.1.18/examples/README.md)
4. [API Reference](https://docs.rs/clap)
- [Derive Reference](https://github.com/clap-rs/clap/blob/v3.0.10/examples/derive_ref/README.md)
- [Derive Reference](https://github.com/clap-rs/clap/blob/v3.1.18/examples/derive_ref/README.md)
- [Feature Flags](#feature-flags)
5. [CHANGELOG](https://github.com/clap-rs/clap/blob/v3.0.10/CHANGELOG.md)
6. [FAQ](https://github.com/clap-rs/clap/blob/v3.0.10/docs/FAQ.md)
5. [CHANGELOG](https://github.com/clap-rs/clap/blob/v3.1.18/CHANGELOG.md)
6. [FAQ](https://github.com/clap-rs/clap/blob/v3.1.18/docs/FAQ.md)
7. [Questions & Discussions](https://github.com/clap-rs/clap/discussions)
8. [Contributing](https://github.com/clap-rs/clap/blob/v3.0.10/CONTRIBUTING.md)
8. [Contributing](https://github.com/clap-rs/clap/blob/v3.1.18/CONTRIBUTING.md)
8. [Sponsors](#sponsors)
## About
@ -31,6 +31,10 @@ Create your command-line parser, with all of the bells and whistles, declarative
### Example
This uses our
[Derive API](https://github.com/clap-rs/clap/blob/v3.1.18/examples/tutorial_derive/README.md)
which provides access to the [Builder API](https://github.com/clap-rs/clap/blob/v3.1.18/examples/tutorial_builder/README.md) as attributes on a `struct`:
<!-- Copied from examples/demo.{rs,md} -->
```rust,no_run
use clap::Parser;
@ -59,13 +63,12 @@ fn main() {
Add this to `Cargo.toml`:
```toml
[dependencies]
clap = { version = "3.0.10", features = ["derive"] }
clap = { version = "3.1.18", features = ["derive"] }
```
```bash
$ demo --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
Simple program to greet a person
USAGE:
demo[EXE] [OPTIONS] --name <NAME>
@ -98,10 +101,27 @@ get. Check out the
[argparse-benchmarks](https://github.com/rust-cli/argparse-benchmarks-rs) for
CLI parsers optimized for other use cases.
### Selecting an API
Why use the declarative [Derive API](https://github.com/clap-rs/clap/blob/v3.1.18/examples/tutorial_derive/README.md):
- Easier to read, write, and modify
- Easier to keep the argument declaration and reading of argument in sync
- Easier to reuse, e.g. [clap-verbosity-flag](https://crates.io/crates/clap-verbosity-flag)
Why use the procedural [Builder API](https://github.com/clap-rs/clap/blob/v3.1.18/examples/tutorial_builder/README.md):
- Faster compile times if you aren't already using other procedural macros
- More flexible, e.g. you can look up how many times an argument showed up,
what its values were, and what were the indexes of those values. The Derive
API can only report presence, number of occurrences, or values but no indices
or combinations of data.
### Related Projects
- [wild](https://crates.io/crates/wild) for supporting wildcards (`*`) on Windows like you do Linux
- [argfile](https://crates.io/crates/argfile) for loading additional arguments from a file (aka response files)
- [shadow-rs](https://crates.io/crates/shadow-rs) for generating `Command::long_version`
- [clap_lex](https://crates.io/crates/clap_lex) for a lighter-weight, battle-tested CLI parser
- [clap_mangen](https://crates.io/crates/clap_mangen) for generating man page source (roff)
- [clap_complete](https://crates.io/crates/clap_complete) for shell completion support
- [clap-verbosity-flag](https://crates.io/crates/clap-verbosity-flag)
- [clap-cargo](https://crates.io/crates/clap-cargo)
@ -131,9 +151,10 @@ CLI parsers optimized for other use cases.
**Warning:** These may contain breaking changes between minor releases.
* **unstable-replace**: Enable [`App::replace`](https://github.com/clap-rs/clap/issues/2836)
* **unstable-multicall**: Enable [`AppSettings::Multicall`](https://github.com/clap-rs/clap/issues/2861)
* **unstable-replace**: Enable [`Command::replace`](https://github.com/clap-rs/clap/issues/2836)
* **unstable-multicall**: Enable [`Command::multicall`](https://github.com/clap-rs/clap/issues/2861)
* **unstable-grouped**: Enable [`ArgMatches::grouped_values_of`](https://github.com/clap-rs/clap/issues/2924)
* **unstable-v4**: Preview features which will be stable on the v4.0 release
## Sponsors

6
third_party/rust/clap/benches/01_default.rs поставляемый
Просмотреть файл

@ -1,13 +1,13 @@
use clap::App;
use clap::Command;
use criterion::{criterion_group, criterion_main, Criterion};
pub fn build_empty(c: &mut Criterion) {
c.bench_function("build_empty", |b| b.iter(|| App::new("claptests")));
c.bench_function("build_empty", |b| b.iter(|| Command::new("claptests")));
}
pub fn parse_empty(c: &mut Criterion) {
c.bench_function("parse_empty", |b| {
b.iter(|| App::new("claptests").get_matches_from(vec![""]))
b.iter(|| Command::new("claptests").get_matches_from(vec![""]))
});
}

16
third_party/rust/clap/benches/02_simple.rs поставляемый
Просмотреть файл

@ -1,9 +1,9 @@
use clap::{arg, App, Arg};
use clap::{arg, Arg, Command};
use criterion::{criterion_group, criterion_main, Criterion};
macro_rules! create_app {
() => {{
App::new("claptests")
Command::new("claptests")
.version("0.1")
.about("tests clap library")
.author("Kevin K. <kbknapp@gmail.com>")
@ -19,7 +19,7 @@ pub fn build_simple(c: &mut Criterion) {
pub fn build_with_flag(c: &mut Criterion) {
c.bench_function("build_with_flag", |b| {
b.iter(|| App::new("claptests").arg(arg!(-s --some "something")))
b.iter(|| Command::new("claptests").arg(arg!(-s --some "something")))
});
}
@ -27,14 +27,14 @@ pub fn build_with_flag_ref(c: &mut Criterion) {
c.bench_function("build_with_flag_ref", |b| {
b.iter(|| {
let arg = arg!(-s --some "something");
App::new("claptests").arg(&arg)
Command::new("claptests").arg(&arg)
})
});
}
pub fn build_with_opt(c: &mut Criterion) {
c.bench_function("build_with_opt", |b| {
b.iter(|| App::new("claptests").arg(arg!(-s --some <FILE> "something")))
b.iter(|| Command::new("claptests").arg(arg!(-s --some <FILE> "something")))
});
}
@ -42,14 +42,14 @@ pub fn build_with_opt_ref(c: &mut Criterion) {
c.bench_function("build_with_opt_ref", |b| {
b.iter(|| {
let arg = arg!(-s --some <FILE> "something");
App::new("claptests").arg(&arg)
Command::new("claptests").arg(&arg)
})
});
}
pub fn build_with_pos(c: &mut Criterion) {
c.bench_function("build_with_pos", |b| {
b.iter(|| App::new("claptests").arg(Arg::new("some")))
b.iter(|| Command::new("claptests").arg(Arg::new("some")))
});
}
@ -57,7 +57,7 @@ pub fn build_with_pos_ref(c: &mut Criterion) {
c.bench_function("build_with_pos_ref", |b| {
b.iter(|| {
let arg = Arg::new("some");
App::new("claptests").arg(&arg)
Command::new("claptests").arg(&arg)
})
});
}

12
third_party/rust/clap/benches/03_complex.rs поставляемый
Просмотреть файл

@ -1,4 +1,4 @@
use clap::{arg, App, AppSettings, Arg};
use clap::{arg, Arg, Command};
use criterion::{criterion_group, criterion_main, Criterion};
static OPT3_VALS: [&str; 2] = ["fast", "slow"];
@ -6,7 +6,7 @@ static POS3_VALS: [&str; 2] = ["vi", "emacs"];
macro_rules! create_app {
() => {{
App::new("claptests")
Command::new("claptests")
.version("0.1")
.about("tests clap library")
.author("Kevin K. <kbknapp@gmail.com>")
@ -35,7 +35,7 @@ macro_rules! create_app {
arg!(--maxvals3 <maxvals> ... "Tests 3 max vals").max_values(3).multiple_values(true).required(false),
])
.subcommand(
App::new("subcmd")
Command::new("subcmd")
.about("tests subcommands")
.version("0.1")
.author("Kevin K. <kbknapp@gmail.com>")
@ -48,7 +48,7 @@ macro_rules! create_app {
pub fn build_from_builder(c: &mut Criterion) {
c.bench_function("build_from_builder", |b| {
b.iter(|| {
App::new("claptests")
Command::new("claptests")
.version("0.1")
.about("tests clap library")
.author("Kevin K. <kbknapp@gmail.com>")
@ -141,7 +141,7 @@ pub fn build_from_builder(c: &mut Criterion) {
.max_values(3),
)
.subcommand(
App::new("subcmd")
Command::new("subcmd")
.about("tests subcommands")
.version("0.1")
.author("Kevin K. <kbknapp@gmail.com>")
@ -257,7 +257,7 @@ pub fn parse_args_negate_scs(c: &mut Criterion) {
c.bench_function("parse_args_negate_scs", |b| {
b.iter(|| {
create_app!()
.setting(AppSettings::ArgsNegateSubcommands)
.args_conflicts_with_subcommands(true)
.get_matches_from(vec![
"myprog",
"arg1",

84
third_party/rust/clap/benches/04_new_help.rs поставляемый
Просмотреть файл

@ -1,17 +1,17 @@
use clap::App;
use clap::Command;
use clap::{arg, Arg};
use criterion::{criterion_group, criterion_main, Criterion};
use std::io::Cursor;
fn build_help(app: &mut App) -> String {
fn build_help(cmd: &mut Command) -> String {
let mut buf = Cursor::new(Vec::with_capacity(50));
app.write_help(&mut buf).unwrap();
cmd.write_help(&mut buf).unwrap();
let content = buf.into_inner();
String::from_utf8(content).unwrap()
}
fn app_example1<'c>() -> App<'c> {
App::new("MyApp")
fn app_example1<'c>() -> Command<'c> {
Command::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
@ -24,21 +24,21 @@ fn app_example1<'c>() -> App<'c> {
.arg(arg!(<output> "Sets an optional output file"))
.arg(arg!(d: -d ... "Turn debugging information on"))
.subcommand(
App::new("test")
Command::new("test")
.about("does testing things")
.arg(arg!(-l --list "lists test values")),
)
}
fn app_example2<'c>() -> App<'c> {
App::new("MyApp")
fn app_example2<'c>() -> Command<'c> {
Command::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
}
fn app_example3<'c>() -> App<'c> {
App::new("MyApp")
fn app_example3<'c>() -> Command<'c> {
Command::new("MyApp")
.arg(
Arg::new("debug")
.help("turn on debugging information")
@ -64,8 +64,8 @@ fn app_example3<'c>() -> App<'c> {
)
}
fn app_example4<'c>() -> App<'c> {
App::new("MyApp")
fn app_example4<'c>() -> Command<'c> {
Command::new("MyApp")
.about("Parses an input file to do awesome things")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
@ -89,8 +89,8 @@ fn app_example4<'c>() -> App<'c> {
)
}
fn app_example5<'c>() -> App<'c> {
App::new("MyApp").arg(
fn app_example5<'c>() -> Command<'c> {
Command::new("MyApp").arg(
Arg::new("awesome")
.help("turns up the awesome")
.short('a')
@ -99,8 +99,8 @@ fn app_example5<'c>() -> App<'c> {
)
}
fn app_example6<'c>() -> App<'c> {
App::new("MyApp")
fn app_example6<'c>() -> Command<'c> {
Command::new("MyApp")
.arg(
Arg::new("input")
.help("the input file to use")
@ -111,8 +111,8 @@ fn app_example6<'c>() -> App<'c> {
.arg(Arg::new("config").help("the config file to use").index(2))
}
fn app_example7<'c>() -> App<'c> {
App::new("MyApp")
fn app_example7<'c>() -> Command<'c> {
Command::new("MyApp")
.arg(Arg::new("config"))
.arg(Arg::new("output"))
.arg(
@ -129,8 +129,8 @@ fn app_example7<'c>() -> App<'c> {
)
}
fn app_example8<'c>() -> App<'c> {
App::new("MyApp")
fn app_example8<'c>() -> Command<'c> {
Command::new("MyApp")
.arg(Arg::new("config"))
.arg(Arg::new("output"))
.arg(
@ -147,8 +147,8 @@ fn app_example8<'c>() -> App<'c> {
)
}
fn app_example10<'c>() -> App<'c> {
App::new("myapp").about("does awesome things").arg(
fn app_example10<'c>() -> Command<'c> {
Command::new("myapp").about("does awesome things").arg(
Arg::new("CONFIG")
.help("The config file to use (default is \"config.json\")")
.short('c')
@ -157,53 +157,53 @@ fn app_example10<'c>() -> App<'c> {
}
pub fn example1(c: &mut Criterion) {
let mut app = app_example1();
c.bench_function("example1", |b| b.iter(|| build_help(&mut app)));
let mut cmd = app_example1();
c.bench_function("example1", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example2(c: &mut Criterion) {
let mut app = app_example2();
c.bench_function("example2", |b| b.iter(|| build_help(&mut app)));
let mut cmd = app_example2();
c.bench_function("example2", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example3(c: &mut Criterion) {
let mut app = app_example3();
c.bench_function("example3", |b| b.iter(|| build_help(&mut app)));
let mut cmd = app_example3();
c.bench_function("example3", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example4(c: &mut Criterion) {
let mut app = app_example4();
c.bench_function("example4", |b| b.iter(|| build_help(&mut app)));
let mut cmd = app_example4();
c.bench_function("example4", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example5(c: &mut Criterion) {
let mut app = app_example5();
c.bench_function("example5", |b| b.iter(|| build_help(&mut app)));
let mut cmd = app_example5();
c.bench_function("example5", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example6(c: &mut Criterion) {
let mut app = app_example6();
c.bench_function("example6", |b| b.iter(|| build_help(&mut app)));
let mut cmd = app_example6();
c.bench_function("example6", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example7(c: &mut Criterion) {
let mut app = app_example7();
c.bench_function("example7", |b| b.iter(|| build_help(&mut app)));
let mut cmd = app_example7();
c.bench_function("example7", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example8(c: &mut Criterion) {
let mut app = app_example8();
c.bench_function("example8", |b| b.iter(|| build_help(&mut app)));
let mut cmd = app_example8();
c.bench_function("example8", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example10(c: &mut Criterion) {
let mut app = app_example10();
c.bench_function("example10", |b| b.iter(|| build_help(&mut app)));
let mut cmd = app_example10();
c.bench_function("example10", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example4_template(c: &mut Criterion) {
let mut app = app_example4().help_template("{bin} {version}\n{author}\n{about}\n\nUSAGE:\n {usage}\n\nOPTIONS:\n{options}\n\nARGS:\n{args}\n");
c.bench_function("example4_template", |b| b.iter(|| build_help(&mut app)));
let mut cmd = app_example4().help_template("{bin} {version}\n{author}\n{about}\n\nUSAGE:\n {usage}\n\nOPTIONS:\n{options}\n\nARGS:\n{args}\n");
c.bench_function("example4_template", |b| b.iter(|| build_help(&mut cmd)));
}
criterion_group!(

28
third_party/rust/clap/benches/05_ripgrep.rs поставляемый
Просмотреть файл

@ -3,7 +3,7 @@
//
// CLI used is adapted from ripgrep 48a8a3a691220f9e5b2b08f4051abe8655ea7e8a
use clap::{App, Arg};
use clap::{Arg, Command};
use criterion::{criterion_group, criterion_main, Criterion};
use std::collections::HashMap;
use std::io::Cursor;
@ -19,13 +19,13 @@ pub fn build_rg_with_long_help(c: &mut Criterion) {
}
pub fn write_rg_short_help(c: &mut Criterion) {
let mut app = app_short();
c.bench_function("write_rg_short_help", |b| b.iter(|| build_help(&mut app)));
let mut cmd = app_short();
c.bench_function("write_rg_short_help", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn write_rg_long_help(c: &mut Criterion) {
let mut app = app_long();
c.bench_function("write_rg_long_help", |b| b.iter(|| build_help(&mut app)));
let mut cmd = app_long();
c.bench_function("write_rg_long_help", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn parse_rg(c: &mut Criterion) {
@ -270,19 +270,19 @@ OPTIONS:
{options}";
/// Build a clap application with short help strings.
fn app_short() -> App<'static> {
app(false, |k| USAGES[k].short)
fn app_short() -> Command<'static> {
cmd(false, |k| USAGES[k].short)
}
/// Build a clap application with long help strings.
fn app_long() -> App<'static> {
app(true, |k| USAGES[k].long)
fn app_long() -> Command<'static> {
cmd(true, |k| USAGES[k].long)
}
/// Build the help text of an application.
fn build_help(app: &mut App) -> String {
fn build_help(cmd: &mut Command) -> String {
let mut buf = Cursor::new(Vec::with_capacity(50));
app.write_help(&mut buf).unwrap();
cmd.write_help(&mut buf).unwrap();
let content = buf.into_inner();
String::from_utf8(content).unwrap()
}
@ -290,18 +290,18 @@ fn build_help(app: &mut App) -> String {
/// Build a clap application parameterized by usage strings.
///
/// The function given should take a clap argument name and return a help
/// string. `app` will panic if a usage string is not defined.
/// string. `cmd` will panic if a usage string is not defined.
///
/// This is an intentionally stand-alone module so that it can be used easily
/// in a `build.rs` script to build shell completion files.
fn app<F>(_next_line_help: bool, doc: F) -> App<'static>
fn cmd<F>(_next_line_help: bool, doc: F) -> Command<'static>
where
F: Fn(&'static str) -> &'static str,
{
let arg = |name| Arg::new(name).help(doc(name));
let flag = |name| arg(name).long(name);
App::new("ripgrep")
Command::new("ripgrep")
.author("BurntSushi") // simulating since it's only a bench
.version("0.4.0") // Simulating
.about(ABOUT)

120
third_party/rust/clap/benches/06_rustup.rs поставляемый
Просмотреть файл

@ -2,7 +2,7 @@
//
// CLI used is from rustup 408ed84f0e50511ed44a405dd91365e5da588790
use clap::{App, AppSettings, Arg, ArgGroup};
use clap::{AppSettings, Arg, ArgGroup, Command};
use criterion::{criterion_group, criterion_main, Criterion};
pub fn build_rustup(c: &mut Criterion) {
@ -21,8 +21,8 @@ pub fn parse_rustup_with_sc(c: &mut Criterion) {
});
}
fn build_cli() -> App<'static> {
App::new("rustup")
fn build_cli() -> Command<'static> {
Command::new("rustup")
.version("0.9.0") // Simulating
.about("The Rust toolchain installer")
.after_help(RUSTUP_HELP)
@ -35,19 +35,19 @@ fn build_cli() -> App<'static> {
.long("verbose"),
)
.subcommand(
App::new("show")
Command::new("show")
.about("Show the active and installed toolchains")
.after_help(SHOW_HELP),
)
.subcommand(
App::new("install")
Command::new("install")
.about("Update Rust toolchains")
.after_help(TOOLCHAIN_INSTALL_HELP)
.setting(AppSettings::Hidden) // synonym for 'toolchain install'
.hide(true) // synonym for 'toolchain install'
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
App::new("update")
Command::new("update")
.about("Update Rust toolchains")
.after_help(UPDATE_HELP)
.arg(Arg::new("toolchain").required(true))
@ -59,104 +59,104 @@ fn build_cli() -> App<'static> {
),
)
.subcommand(
App::new("default")
Command::new("default")
.about("Set the default toolchain")
.after_help(DEFAULT_HELP)
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
App::new("toolchain")
Command::new("toolchain")
.about("Modify or query the installed toolchains")
.after_help(TOOLCHAIN_HELP)
.setting(AppSettings::DeriveDisplayOrder)
// .setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(App::new("list").about("List installed toolchains"))
.subcommand(Command::new("list").about("List installed toolchains"))
.subcommand(
App::new("install")
Command::new("install")
.about("Install or update a given toolchain")
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
App::new("uninstall")
Command::new("uninstall")
.about("Uninstall a toolchain")
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
App::new("link")
Command::new("link")
.about("Create a custom toolchain by symlinking to a directory")
.arg(Arg::new("toolchain").required(true))
.arg(Arg::new("path").required(true)),
)
.subcommand(
App::new("update")
.setting(AppSettings::Hidden) // synonym for 'install'
Command::new("update")
.hide(true) // synonym for 'install'
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
App::new("add")
.setting(AppSettings::Hidden) // synonym for 'install'
Command::new("add")
.hide(true) // synonym for 'install'
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
App::new("remove")
.setting(AppSettings::Hidden) // synonym for 'uninstall'
Command::new("remove")
.hide(true) // synonym for 'uninstall'
.arg(Arg::new("toolchain").required(true)),
),
)
.subcommand(
App::new("target")
Command::new("target")
.about("Modify a toolchain's supported targets")
.setting(AppSettings::DeriveDisplayOrder)
// .setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
App::new("list")
Command::new("list")
.about("List installed and available targets")
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
)
.subcommand(
App::new("add")
Command::new("add")
.about("Add a target to a Rust toolchain")
.arg(Arg::new("target").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
)
.subcommand(
App::new("remove")
Command::new("remove")
.about("Remove a target from a Rust toolchain")
.arg(Arg::new("target").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
)
.subcommand(
App::new("install")
.setting(AppSettings::Hidden) // synonym for 'add'
Command::new("install")
.hide(true) // synonym for 'add'
.arg(Arg::new("target").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
)
.subcommand(
App::new("uninstall")
.setting(AppSettings::Hidden) // synonym for 'remove'
Command::new("uninstall")
.hide(true) // synonym for 'remove'
.arg(Arg::new("target").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
),
)
.subcommand(
App::new("component")
Command::new("component")
.about("Modify a toolchain's installed components")
.setting(AppSettings::DeriveDisplayOrder)
// .setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
App::new("list")
Command::new("list")
.about("List installed and available components")
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
)
.subcommand(
App::new("add")
Command::new("add")
.about("Add a component to a Rust toolchain")
.arg(Arg::new("component").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true))
.arg(Arg::new("target").long("target").takes_value(true)),
)
.subcommand(
App::new("remove")
Command::new("remove")
.about("Remove a component from a Rust toolchain")
.arg(Arg::new("component").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true))
@ -164,19 +164,19 @@ fn build_cli() -> App<'static> {
),
)
.subcommand(
App::new("override")
Command::new("override")
.about("Modify directory toolchain overrides")
.after_help(OVERRIDE_HELP)
.setting(AppSettings::DeriveDisplayOrder)
// .setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(App::new("list").about("List directory toolchain overrides"))
.subcommand(Command::new("list").about("List directory toolchain overrides"))
.subcommand(
App::new("set")
Command::new("set")
.about("Set the override toolchain for a directory")
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
App::new("unset")
Command::new("unset")
.about("Remove the override toolchain for a directory")
.after_help(OVERRIDE_UNSET_HELP)
.arg(
@ -192,13 +192,13 @@ fn build_cli() -> App<'static> {
),
)
.subcommand(
App::new("add")
.setting(AppSettings::Hidden) // synonym for 'set'
Command::new("add")
.hide(true) // synonym for 'set'
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
App::new("remove")
.setting(AppSettings::Hidden) // synonym for 'unset'
Command::new("remove")
.hide(true) // synonym for 'unset'
.about("Remove the override toolchain for a directory")
.arg(Arg::new("path").long("path").takes_value(true))
.arg(
@ -209,10 +209,10 @@ fn build_cli() -> App<'static> {
),
)
.subcommand(
App::new("run")
Command::new("run")
.about("Run a command with an environment configured for a given toolchain")
.after_help(RUN_HELP)
.setting(AppSettings::TrailingVarArg)
.trailing_var_arg(true)
.arg(Arg::new("toolchain").required(true))
.arg(
Arg::new("command")
@ -223,12 +223,12 @@ fn build_cli() -> App<'static> {
),
)
.subcommand(
App::new("which")
Command::new("which")
.about("Display which binary will be run for a given command")
.arg(Arg::new("command").required(true)),
)
.subcommand(
App::new("doc")
Command::new("doc")
.about("Open the documentation for the current toolchain")
.after_help(DOC_HELP)
.arg(
@ -244,38 +244,42 @@ fn build_cli() -> App<'static> {
.group(ArgGroup::new("page").args(&["book", "std"])),
)
.subcommand(
App::new("man")
Command::new("man")
.about("View the man page for a given command")
.arg(Arg::new("command").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
)
.subcommand(
App::new("self")
Command::new("self")
.about("Modify the rustup installation")
.setting(AppSettings::DeriveDisplayOrder)
.subcommand(App::new("update").about("Download and install updates to rustup"))
.subcommand(Command::new("update").about("Download and install updates to rustup"))
.subcommand(
App::new("uninstall")
Command::new("uninstall")
.about("Uninstall rustup.")
.arg(Arg::new("no-prompt").short('y')),
)
.subcommand(App::new("upgrade-data").about("Upgrade the internal data format.")),
.subcommand(
Command::new("upgrade-data").about("Upgrade the internal data format."),
),
)
.subcommand(
App::new("telemetry")
Command::new("telemetry")
.about("rustup telemetry commands")
.setting(AppSettings::Hidden)
.hide(true)
.setting(AppSettings::DeriveDisplayOrder)
.subcommand(App::new("enable").about("Enable rustup telemetry"))
.subcommand(App::new("disable").about("Disable rustup telemetry"))
.subcommand(App::new("analyze").about("Analyze stored telemetry")),
.subcommand(Command::new("enable").about("Enable rustup telemetry"))
.subcommand(Command::new("disable").about("Disable rustup telemetry"))
.subcommand(Command::new("analyze").about("Analyze stored telemetry")),
)
.subcommand(
App::new("set").about("Alter rustup settings").subcommand(
App::new("default-host")
.about("The triple used to identify toolchains when not specified")
.arg(Arg::new("host_triple").required(true)),
),
Command::new("set")
.about("Alter rustup settings")
.subcommand(
Command::new("default-host")
.about("The triple used to identify toolchains when not specified")
.arg(Arg::new("host_triple").required(true)),
),
)
}

24
third_party/rust/clap/examples/README.md поставляемый
Просмотреть файл

@ -1,14 +1,34 @@
# Examples
- Basic demo: [derive](demo.md)
- Key-value pair arguments: [derive](keyvalue-derive.md)
- Typed arguments: [derive](typed-derive.md)
- Topics:
- Custom `parse()`
- Custom cargo command: [builder](cargo-example.md), [derive](cargo-example-derive.md)
- Topics:
- Subcommands
- Cargo plugins
- git-like interface: [builder](git.md), [derive](git-derive.md)
- Topics:
- Subcommands
- External subcommands
- Optional subcommands
- Default subcommands
- pacman-like interface: [builder](pacman.md)
- Topics:
- Flag subcommands
- Conflicting arguments
- Escaped positionals with `--`: [builder](escaped-positional.md), [derive](escaped-positional-derive.md)
- Multi-call
- busybox: [builder](multicall-busybox.md)
- Topics:
- Subcommands
- hostname: [builder](multicall-hostname.md)
- Topics:
- Subcommands
- repl: [builder](repl.rs)
- Topics:
- Read-Eval-Print Loops / Custom command lines
## Contributing
@ -17,4 +37,4 @@ New examples:
- Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax
- Link the `.md` file from here
See also the general [CONTRIBUTING](../../CONTRIBUTING.md).
See also the general [CONTRIBUTING](../CONTRIBUTING.md).

Просмотреть файл

@ -1,3 +1,5 @@
// Note: this requires the `derive` feature
use clap::Parser;
#[derive(Parser)]

Просмотреть файл

@ -1,15 +1,17 @@
// Note: this requires the `cargo` feature
fn main() {
let app = clap::App::new("cargo")
let cmd = clap::Command::new("cargo")
.bin_name("cargo")
.setting(clap::AppSettings::SubcommandRequired)
.subcommand_required(true)
.subcommand(
clap::app_from_crate!().name("example").arg(
clap::command!("example").arg(
clap::arg!(--"manifest-path" <PATH>)
.required(false)
.allow_invalid_utf8(true),
),
);
let matches = app.get_matches();
let matches = cmd.get_matches();
let matches = match matches.subcommand() {
Some(("example", matches)) => matches,
_ => unreachable!("clap should ensure we don't get here"),

Просмотреть файл

@ -1,14 +1,16 @@
# Derive Reference
1. [Overview](#overview)
2. [Raw Attributes](#raw-attributes)
3. [Magic Attributes](#magic-attributes)
1. [App Attributes](#app-attributes)
2. [Arg Attributes](#arg-attributes)
3. [Arg Types](#arg-types)
2. [Attributes](#attributes)
1. [Terminology](#terminology)
2. [Command Attributes](#command-attributes)
3. [Arg Attributes](#arg-attributes)
4. [Arg Enum Attributes](#arg-enum-attributes)
5. [Possible Value Attributes](#possible-value-attributes)
6. [Doc Comments](#doc-comments)
3. [Arg Types](#arg-types)
4. [Doc Comments](#doc-comments)
5. [Tips](#tips)
6. [Mixing Builder and Derive APIS](#mixing-builder-and-derive-apis)
## Overview
@ -16,7 +18,7 @@ To derive `clap` types, you need to enable the `derive` feature flag.
See [demo.rs](../demo.rs) and [demo.md](../demo.md) for a brief example.
Let's start by breaking down what can go where:
Let's start by breaking down the anatomy of the derive attributes:
```rust
use clap::{Parser, Args, Subcommand, ArgEnum};
@ -26,7 +28,10 @@ use clap::{Parser, Args, Subcommand, ArgEnum};
struct Cli {
/// Doc comment
#[clap(ARG ATTRIBUTE)]
field: Type,
field: UserType,
#[clap(arg_enum, ARG ATTRIBUTE...)]
field: EnumValues,
#[clap(flatten)]
delegate: Struct,
@ -41,7 +46,7 @@ struct Cli {
struct Struct {
/// Doc comment
#[clap(ARG ATTRIBUTE)]
field: Type,
field: UserType,
}
/// Doc comment
@ -57,14 +62,14 @@ enum Command {
Variant2 {
/// Doc comment
#[clap(ARG ATTRIBUTE)]
field: Type,
field: UserType,
}
}
/// Doc comment
#[derive(ArgEnum)]
#[clap(ARG ENUM ATTRIBUTE)]
enum Mode {
enum EnumValues {
/// Doc comment
#[clap(POSSIBLE VALUE ATTRIBUTE)]
Variant1,
@ -78,14 +83,18 @@ fn main() {
- `Parser` parses arguments into a `struct` (arguments) or `enum` (subcommands).
- `Args` allows defining a set of re-usable arguments that get merged into their parent container.
- `Subcommand` defines available subcommands.
- Subcommand arguments can be defined in a struct-variant or automatically flattened with a tuple-variant.
- `ArgEnum` allows parsing a value directly into an `enum`, erroring on unsupported values.
- The derive doesn't work on enums that contain non-unit variants, unless they are skipped
See also the [tutorial](../tutorial_derive/README.md) and [examples](../README.md).
## Raw Attributes
## Attributes
### Terminology
**Raw attributes** are forwarded directly to the underlying `clap` builder. Any
`App`, `Arg`, or `PossibleValue` method can be used as an attribute.
`Command`, `Arg`, or `PossibleValue` method can be used as an attribute.
Raw attributes come in two different syntaxes:
```rust
@ -101,38 +110,46 @@ Raw attributes come in two different syntaxes:
As long as `method_name` is not one of the magical methods - it will be
translated into a mere method call.
## Magic Attributes
**Magic attributes** have post-processing done to them, whether that is
- Providing of defaults
- Special behavior is triggered off of it
### App Attributes
Magic attributes are more constrained in the syntax they support, usually just
`<attr> = <value>` though some use `<attr>(<value>)` instead. See the specific
magic attributes documentation for details. This allows users to access the
raw behavior of an attribute via `<attr>(<value>)` syntax.
These correspond to a `clap::App` which is used for both top-level parsers and
**NOTE:** Some attributes are inferred from [Arg Types](#arg-types) and [Doc
Comments](#doc-comments). Explicit attributes take precedence over inferred
attributes.
### Command Attributes
These correspond to a `clap::Command` which is used for both top-level parsers and
when defining subcommands.
In addition to the raw attributes, the following magic attributes are supported:
- `name = <expr>`: `clap::App::name`
**Magic attributes:**
- `name = <expr>`: `clap::Command::name`
- When not present: [crate `name`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-name-field) (`Parser` container), variant name (`Subcommand` variant)
- `version [= <expr>]`: `clap::App::version`
- `version [= <expr>]`: `clap::Command::version`
- When not present: no version set
- Without `<expr>`: defaults to [crate `version`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field)
- `author [= <expr>]`: `clap::App::author`
- `author [= <expr>]`: `clap::Command::author`
- When not present: no author set
- Without `<expr>`: defaults to [crate `authors`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-authors-field)
- `about [= <expr>]`: `clap::App::about`
- `about [= <expr>]`: `clap::Command::about`
- When not present: [Doc comment summary](#doc-comments)
- Without `<expr>`: [crate `description`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-description-field) (`Parser` container)
- **TIP:** When a doc comment is also present, you most likely want to add
`#[clap(long_about = None)]` to clear the doc comment so only `about`
gets shown with both `-h` and `--help`.
- `long_about = <expr>`: `clap::App::long_about`
- `long_about = <expr>`: `clap::Command::long_about`
- When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing
- `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to `about` / `long_about`
- `help_heading`: `clap::App::help_heading`
- `next_display_order`: `clap::Command::next_display_order`
- `next_help_heading`: `clap::Command::next_help_heading`
- When `flatten`ing `Args`, this is scoped to just the args in this struct and any struct `flatten`ed into it
- `rename_all = <expr>`: Override default field / variant name case conversion for `App::name` / `Arg::name`
- `rename_all = <expr>`: Override default field / variant name case conversion for `Command::name` / `Arg::name`
- When not present: `kebab-case`
- Available values: `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lower`, `UPPER`, `verbatim`
- `rename_all_env = <expr>`: Override default field name case conversion for env variables for `clap::Arg::env`
@ -143,14 +160,17 @@ And for `Subcommand` variants:
- `skip`: Ignore this variant
- `flatten`: Delegates to the variant for more subcommands (must implement `Subcommand`)
- `subcommand`: Nest subcommands under the current set of subcommands (must implement `Subcommand`)
- `external_subcommand`: `clap::AppSettings::AllowExternalSubcommand`
- `external_subcommand`: `clap::Command::allow_external_subcommand(true)`
- Variant must be either `Variant(Vec<String>)` or `Variant(Vec<OsString>)`
**Raw attributes:** Any [`Command` method](https://docs.rs/clap/latest/clap/type.Command.html) can also be used as an attribute, see [Terminology](#terminology) for syntax.
- e.g. `#[clap(arg_required_else_help(true))]` would translate to `cmd.arg_required_else_help(true)`
### Arg Attributes
These correspond to a `clap::Arg`.
In addition to the raw attributes, the following magic attributes are supported:
**Magic attributes**:
- `name = <expr>`: `clap::Arg::new`
- When not present: case-converted field name is used
- `help = <expr>`: `clap::Arg::help`
@ -164,20 +184,23 @@ In addition to the raw attributes, the following magic attributes are supported:
- `long [= <str>]`: `clap::Arg::long`
- When not present: no long set
- Without `<str>`: defaults to the case-converted field name
- `env [= <str>]`: `clap::Arg::env`
- `env [= <str>]`: `clap::Arg::env` (needs `env` feature enabled)
- When not present: no env set
- Without `<str>`: defaults to the case-converted field name
- `flatten`: Delegates to the field for more arguments (must implement `Args`)
- Only `help_heading` can be used with `flatten`. See
[clap-rs/clap#3269](https://github.com/clap-rs/clap/issues/3269) for why
arg attributes are not generally supported.
- **Tip:** Though we do apply a flattened `Args`'s Parent App Attributes, this
makes reuse harder. Generally prefer putting the app attributes on the `Parser`
- **Tip:** Though we do apply a flattened `Args`'s Parent Command Attributes, this
makes reuse harder. Generally prefer putting the cmd attributes on the `Parser`
or on the flattened field.
- `subcommand`: Delegates definition of subcommands to the field (must implement `Subcommand`)
- When `Option<T>`, the subcommand becomes optional
- `from_global`: Read a `clap::Arg::global` argument (raw attribute), regardless of what subcommand you are in
- `parse(<kind> [= <function>])` `clap::Arg::validator`
- `from_global`: Read a `clap::Arg::global` argument (raw attribute), regardless of what subcommand you are in
- `parse(<kind> [= <function>])`: `clap::Arg::validator` and `clap::ArgMatches::values_of_t`
- Default: `try_from_str`
- Warning: for `Path` / `OsString`, be sure to use `try_from_os_str`
- See [Arg Types](#arg-types) for more details
- `arg_enum`: Parse the value using the `ArgEnum` trait
- `skip [= <expr>]`: Ignore this field, filling in with `<expr>`
- Without `<expr>`: fills the field with `Default::default()`
@ -185,14 +208,39 @@ In addition to the raw attributes, the following magic attributes are supported:
- `default_value_t [= <expr>]`: `clap::Arg::default_value` and `clap::Arg::required(false)`
- Requires `std::fmt::Display` or `#[clap(arg_enum)]`
- Without `<expr>`, relies on `Default::default()`
- `default_value_os_t [= <expr>]`: `clap::Arg::default_value_os` and `clap::Arg::required(false)`
- Requires `std::convert::Into<OsString>` or `#[clap(arg_enum)]`
- Without `<expr>`, relies on `Default::default()`
### Arg Types
**Raw attributes:** Any [`Arg` method](https://docs.rs/clap/latest/clap/struct.Arg.html) can also be used as an attribute, see [Terminology](#terminology) for syntax.
- e.g. `#[clap(max_values(3))]` would translate to `arg.max_values(3)`
### Arg Enum Attributes
- `rename_all = <expr>`: Override default field / variant name case conversion for `PossibleValue::new`
- When not present: `kebab-case`
- Available values: `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lower`, `UPPER`, `verbatim`
### Possible Value Attributes
These correspond to a `clap::PossibleValue`.
**Magic attributes**:
- `name = <expr>`: `clap::PossibleValue::new`
- When not present: case-converted field name is used
- `help = <expr>`: `clap::PossibleValue::help`
- When not present: [Doc comment summary](#doc-comments)
**Raw attributes:** Any [`PossibleValue` method](https://docs.rs/clap/latest/clap/struct.PossibleValue.html) can also be used as an attribute, see [Terminology](#terminology) for syntax.
- e.g. `#[clap(alias("foo"))]` would translate to `pv.alias("foo")`
## Arg Types
`clap` assumes some intent based on the type used:
| Type | Effect | Implies |
|---------------------|--------------------------------------|------------------------------------------------------------------|
| `bool` | flag | `#[clap(parser(from_flag))]` |
| `bool` | flag | `#[clap(parse(from_flag))]` |
| `Option<T>` | optional argument | `.takes_value(true).required(false)` |
| `Option<Option<T>>` | optional value for optional argument | `.takes_value(true).required(false).min_values(0).max_values(1)` |
| `T` | required argument | `.takes_value(true).required(!has_default)` |
@ -224,33 +272,20 @@ Notes:
- `from_occurrences`:
- Implies `arg.takes_value(false).multiple_occurrences(true)`
- Reads from `clap::ArgMatches::occurrences_of` rather than a `value_of` function
- Note: operations on values, like `default_value`, are unlikely to do what you want
- `from_flag`
- Implies `arg.takes_value(false)`
- Reads from `clap::ArgMatches::is_present` rather than a `value_of` function
- Note: operations on values, like `default_value`, are unlikely to do what you want
**Warning:**
- To support non-UTF8 paths, you must use `parse(from_os_str)`, otherwise
`clap` will use `clap::ArgMatches::value_of` with `PathBuf::FromStr`.
### Arg Enum Attributes
- `rename_all = <expr>`: Override default field / variant name case conversion for `PossibleValue::new`
- When not present: `kebab-case`
- Available values: `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lower`, `UPPER`, `verbatim`
### Possible Value Attributes
These correspond to a `clap::PossibleValue`.
- `name = <expr>`: `clap::PossibleValue::new`
- When not present: case-converted field name is used
- `help = <expr>`: `clap::PossibleValue::help`
- When not present: [Doc comment summary](#doc-comments)
### Doc Comments
## Doc Comments
In clap, help messages for the whole binary can be specified
via [`App::about`] and [`App::long_about`] while help messages
via [`Command::about`] and [`Command::long_about`] while help messages
for individual arguments can be specified via [`Arg::help`] and [`Arg::long_help`]".
`long_*` variants are used when user calls the program with
@ -283,15 +318,15 @@ struct Foo {
**NOTE:** Attributes have priority over doc comments!
**Top level doc comments always generate `App::about/long_about` calls!**
If you really want to use the `App::about/long_about` methods (you likely don't),
**Top level doc comments always generate `Command::about/long_about` calls!**
If you really want to use the `Command::about/long_about` methods (you likely don't),
use the `about` / `long_about` attributes to override the calls generated from
the doc comment. To clear `long_about`, you can use
`#[clap(long_about = None)]`.
**TIP:** Set `#![deny(missing_docs)]` to catch missing `--help` documentation at compile time.
#### Pre-processing
### Pre-processing
```rust
# use clap::Parser;
@ -317,10 +352,10 @@ A doc comment consists of three parts:
- A blank line (whitespace only)
- Detailed description, all the rest
The summary corresponds with `App::about` / `Arg::help`. When a blank line is
present, the whole doc comment will be passed to `App::long_about` /
`Arg::long_help`. Or in other words, a doc may result in just a `App::about` /
`Arg::help` or `App::about` / `Arg::help` and `App::long_about` /
The summary corresponds with `Command::about` / `Arg::help`. When a blank line is
present, the whole doc comment will be passed to `Command::long_about` /
`Arg::long_help`. Or in other words, a doc may result in just a `Command::about` /
`Arg::help` or `Command::about` / `Arg::help` and `Command::long_about` /
`Arg::long_help`
In addition, when `verbatim_doc_comment` is not present, `clap` applies some preprocessing, including:
@ -349,3 +384,46 @@ them.
- Remove one leading space from each line, even if this attribute is present,
to allow for a space between `///` and the content.
- Remove leading and trailing blank lines
## Tips
- To get access to a `Command` call `CommandFactory::command` (implemented when deriving `Parser`)
- Proactively check for bad `Command` configurations by calling `Command::debug_assert` in a test ([example](../tutorial_derive/05_01_assert.rs))
## Mixing Builder and Derive APIs
The builder and derive APIs do not live in isolation. They can work together, which is especially helpful if some arguments can be specified at compile-time while others must be specified at runtime.
### Using derived arguments in a builder application
*[Jump to source](augment_args.rs)*
When using the derive API, you can `#[clap(flatten)]` a struct deriving `Args` into a struct deriving `Args` or `Parser`. This example shows how you can augment a `Command` instance created using the builder API with `Args` created using the derive API.
It uses the `Args::augment_args` method to add the arguments to the `Command` instance.
Crates such as [clap-verbosity-flag](https://github.com/rust-cli/clap-verbosity-flag) provide structs that implement `Args` or `Parser`. Without the technique shown in this example, it would not be possible to use such crates with the builder API. `augment_args` to the rescue!
### Using derived subcommands in a builder application
*[Jump to source](augment_subcommands.rs)*
When using the derive API, you can use `#[clap(subcommand)]` inside the struct to add subcommands. The type of the field is usually an enum that derived `Parser`. However, you can also add the subcommands in that enum to a `Command` instance created with the builder API.
It uses the `Subcommand::augment_subcommands` method to add the subcommands to the `Command` instance.
### Adding hand-implemented subcommands to a derived application
*[Jump to source](hand_subcommand.rs)*
When using the derive API, you can use `#[clap(subcommand)]` inside the struct to add subcommands. The type of the field is usually an enum that derived `Parser`. However, you can also implement the `Subcommand` trait manually on this enum (or any other type) and it can still be used inside the struct created with the derive API. The implementation of the `Subcommand` trait will use the builder API to add the subcommands to the `Command` instance created behind the scenes for you by the derive API.
Notice how in the previous example we used `augment_subcommands` on an enum that derived `Parser`, whereas now we implement `augment_subcommands` ourselves, but the derive API calls it automatically since we used the `#[clap(subcommand)]` attribute.
### Flattening hand-implemented args into a derived application
*[Jump to source](flatten_hand_args.rs)*
When using the derive API, you can use `#[clap(flatten)]` inside the struct to add arguments as if they were added directly to the containing struct. The type of the field is usually an struct that derived `Args`. However, you can also implement the `Args` trait manually on this struct (or any other type) and it can still be used inside the struct created with the derive API. The implementation of the `Args` trait will use the builder API to add the arguments to the `Command` instance created behind the scenes for you by the derive API.
Notice how in the example 1 we used `augment_args` on the struct that derived `Parser`, whereas now we implement `augment_args` ourselves, but the derive API calls it automatically since we used the `#[clap(flatten)]` attribute.

27
third_party/rust/clap/examples/derive_ref/augment_args.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,27 @@
use clap::{arg, Args as _, Command, FromArgMatches as _, Parser};
#[derive(Parser, Debug)]
struct DerivedArgs {
#[clap(short, long)]
derived: bool,
}
fn main() {
let cli = Command::new("CLI").arg(arg!(-b - -built));
// Augment built args with derived args
let cli = DerivedArgs::augment_args(cli);
let matches = cli.get_matches();
println!("Value of built: {:?}", matches.is_present("built"));
println!(
"Value of derived via ArgMatches: {:?}",
matches.is_present("derived")
);
// Since DerivedArgs implements FromArgMatches, we can extract it from the unstructured ArgMatches.
// This is the main benefit of using derived arguments.
let derived_matches = DerivedArgs::from_arg_matches(&matches)
.map_err(|err| err.exit())
.unwrap();
println!("Value of derived: {:#?}", derived_matches);
}

Просмотреть файл

@ -0,0 +1,21 @@
use clap::{Command, FromArgMatches as _, Parser, Subcommand as _};
#[derive(Parser, Debug)]
enum Subcommands {
Derived {
#[clap(short, long)]
derived_flag: bool,
},
}
fn main() {
let cli = Command::new("Built CLI");
// Augment with derived subcommands
let cli = Subcommands::augment_subcommands(cli);
let matches = cli.get_matches();
let derived_subcommands = Subcommands::from_arg_matches(&matches)
.map_err(|err| err.exit())
.unwrap();
println!("Derived subcommands: {:#?}", derived_subcommands);
}

53
third_party/rust/clap/examples/derive_ref/flatten_hand_args.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,53 @@
use clap::error::Error;
use clap::{Arg, ArgMatches, Args, Command, FromArgMatches, Parser};
#[derive(Debug)]
struct CliArgs {
foo: bool,
bar: bool,
quuz: Option<String>,
}
impl FromArgMatches for CliArgs {
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
Ok(Self {
foo: matches.is_present("foo"),
bar: matches.is_present("bar"),
quuz: matches.value_of("quuz").map(|quuz| quuz.to_owned()),
})
}
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
self.foo |= matches.is_present("foo");
self.bar |= matches.is_present("bar");
if let Some(quuz) = matches.value_of("quuz") {
self.quuz = Some(quuz.to_owned());
}
Ok(())
}
}
impl Args for CliArgs {
fn augment_args(cmd: Command<'_>) -> Command<'_> {
cmd.arg(Arg::new("foo").short('f').long("foo"))
.arg(Arg::new("bar").short('b').long("bar"))
.arg(Arg::new("quuz").short('q').long("quuz").takes_value(true))
}
fn augment_args_for_update(cmd: Command<'_>) -> Command<'_> {
cmd.arg(Arg::new("foo").short('f').long("foo"))
.arg(Arg::new("bar").short('b').long("bar"))
.arg(Arg::new("quuz").short('q').long("quuz").takes_value(true))
}
}
#[derive(Parser, Debug)]
struct Cli {
#[clap(short, long)]
top_level: bool,
#[clap(flatten)]
more_args: CliArgs,
}
fn main() {
let args = Cli::parse();
println!("{:#?}", args);
}

79
third_party/rust/clap/examples/derive_ref/hand_subcommand.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,79 @@
use clap::error::{Error, ErrorKind};
use clap::{ArgMatches, Args as _, Command, FromArgMatches, Parser, Subcommand};
#[derive(Parser, Debug)]
struct AddArgs {
name: Vec<String>,
}
#[derive(Parser, Debug)]
struct RemoveArgs {
#[clap(short, long)]
force: bool,
name: Vec<String>,
}
#[derive(Debug)]
enum CliSub {
Add(AddArgs),
Remove(RemoveArgs),
}
impl FromArgMatches for CliSub {
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
match matches.subcommand() {
Some(("add", args)) => Ok(Self::Add(AddArgs::from_arg_matches(args)?)),
Some(("remove", args)) => Ok(Self::Remove(RemoveArgs::from_arg_matches(args)?)),
Some((_, _)) => Err(Error::raw(
ErrorKind::UnrecognizedSubcommand,
"Valid subcommands are `add` and `remove`",
)),
None => Err(Error::raw(
ErrorKind::MissingSubcommand,
"Valid subcommands are `add` and `remove`",
)),
}
}
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
match matches.subcommand() {
Some(("add", args)) => *self = Self::Add(AddArgs::from_arg_matches(args)?),
Some(("remove", args)) => *self = Self::Remove(RemoveArgs::from_arg_matches(args)?),
Some((_, _)) => {
return Err(Error::raw(
ErrorKind::UnrecognizedSubcommand,
"Valid subcommands are `add` and `remove`",
))
}
None => (),
};
Ok(())
}
}
impl Subcommand for CliSub {
fn augment_subcommands(cmd: Command<'_>) -> Command<'_> {
cmd.subcommand(AddArgs::augment_args(Command::new("add")))
.subcommand(RemoveArgs::augment_args(Command::new("remove")))
.subcommand_required(true)
}
fn augment_subcommands_for_update(cmd: Command<'_>) -> Command<'_> {
cmd.subcommand(AddArgs::augment_args(Command::new("add")))
.subcommand(RemoveArgs::augment_args(Command::new("remove")))
.subcommand_required(true)
}
fn has_subcommand(name: &str) -> bool {
matches!(name, "add" | "remove")
}
}
#[derive(Parser, Debug)]
struct Cli {
#[clap(short, long)]
top_level: bool,
#[clap(subcommand)]
subcommand: CliSub,
}
fn main() {
let args = Cli::parse();
println!("{:#?}", args);
}

256
third_party/rust/clap/examples/derive_ref/interop_tests.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,256 @@
Following are tests for the interop examples in this directory.
## Augment Args
```console
$ interop_augment_args
Value of built: false
Value of derived via ArgMatches: false
Value of derived: DerivedArgs {
derived: false,
}
```
```console
$ interop_augment_args -b --derived
Value of built: true
Value of derived via ArgMatches: true
Value of derived: DerivedArgs {
derived: true,
}
```
```console
$ interop_augment_args -d --built
Value of built: true
Value of derived via ArgMatches: true
Value of derived: DerivedArgs {
derived: true,
}
```
```console
$ interop_augment_args --unknown
? failed
error: Found argument '--unknown' which wasn't expected, or isn't valid in this context
If you tried to supply `--unknown` as a value rather than a flag, use `-- --unknown`
USAGE:
interop_augment_args[EXE] [OPTIONS]
For more information try --help
```
## Augment Subcommands
```console
$ interop_augment_subcommands
? failed
error: A subcommand is required but one was not provided.
```
```console
$ interop_augment_subcommands derived
Derived subcommands: Derived {
derived_flag: false,
}
```
```console
$ interop_augment_subcommands derived --derived-flag
Derived subcommands: Derived {
derived_flag: true,
}
```
```console
$ interop_augment_subcommands derived --unknown
? failed
error: Found argument '--unknown' which wasn't expected, or isn't valid in this context
If you tried to supply `--unknown` as a value rather than a flag, use `-- --unknown`
USAGE:
interop_augment_subcommands[EXE] derived [OPTIONS]
For more information try --help
```
```console
$ interop_augment_subcommands unknown
? failed
error: Found argument 'unknown' which wasn't expected, or isn't valid in this context
USAGE:
interop_augment_subcommands[EXE] [SUBCOMMAND]
For more information try --help
```
## Hand-Implemented Subcommand
```console
$ interop_hand_subcommand
? failed
error: 'interop_hand_subcommand[EXE]' requires a subcommand but one was not provided
USAGE:
interop_hand_subcommand[EXE] [OPTIONS] <SUBCOMMAND>
For more information try --help
```
```console
$ interop_hand_subcommand add
Cli {
top_level: false,
subcommand: Add(
AddArgs {
name: [],
},
),
}
```
```console
$ interop_hand_subcommand add a b c
Cli {
top_level: false,
subcommand: Add(
AddArgs {
name: [
"a",
"b",
"c",
],
},
),
}
```
```console
$ interop_hand_subcommand add --unknown
? failed
error: Found argument '--unknown' which wasn't expected, or isn't valid in this context
If you tried to supply `--unknown` as a value rather than a flag, use `-- --unknown`
USAGE:
interop_hand_subcommand[EXE] add [NAME]...
For more information try --help
```
```console
$ interop_hand_subcommand remove
Cli {
top_level: false,
subcommand: Remove(
RemoveArgs {
force: false,
name: [],
},
),
}
```
```console
$ interop_hand_subcommand remove --force a b c
Cli {
top_level: false,
subcommand: Remove(
RemoveArgs {
force: true,
name: [
"a",
"b",
"c",
],
},
),
}
```
```console
$ interop_hand_subcommand unknown
? failed
error: Found argument 'unknown' which wasn't expected, or isn't valid in this context
USAGE:
interop_hand_subcommand[EXE] [OPTIONS] <SUBCOMMAND>
For more information try --help
```
## Flatten Hand-Implemented Args
```console
$ interop_flatten_hand_args
Cli {
top_level: false,
more_args: CliArgs {
foo: false,
bar: false,
quuz: None,
},
}
```
```console
$ interop_flatten_hand_args -f --bar
Cli {
top_level: false,
more_args: CliArgs {
foo: true,
bar: true,
quuz: None,
},
}
```
```console
$ interop_flatten_hand_args --quuz abc
Cli {
top_level: false,
more_args: CliArgs {
foo: false,
bar: false,
quuz: Some(
"abc",
),
},
}
```
```console
$ interop_flatten_hand_args --unknown
? failed
error: Found argument '--unknown' which wasn't expected, or isn't valid in this context
If you tried to supply `--unknown` as a value rather than a flag, use `-- --unknown`
USAGE:
interop_flatten_hand_args[EXE] [OPTIONS]
For more information try --help
```

Просмотреть файл

@ -1,9 +1,9 @@
// Note: this requires the `cargo` feature
use clap::{app_from_crate, arg};
use clap::{arg, command};
fn main() {
let matches = app_from_crate!()
let matches = command!()
.arg(arg!(eff: -f))
.arg(arg!(pea: -p <PEAR>).required(false))
.arg(

57
third_party/rust/clap/examples/git-derive.md поставляемый
Просмотреть файл

@ -22,6 +22,7 @@ SUBCOMMANDS:
clone Clones repos
help Print this message or the help of the given subcommand(s)
push pushes things
stash
$ git-derive help
git
@ -38,6 +39,7 @@ SUBCOMMANDS:
clone Clones repos
help Print this message or the help of the given subcommand(s)
push pushes things
stash
$ git-derive help add
git-derive[EXE]-add
@ -75,6 +77,61 @@ Adding ["Cargo.toml", "Cargo.lock"]
```
Default subcommand:
```console
$ git-derive stash -h
git-derive[EXE]-stash
USAGE:
git-derive[EXE] stash [OPTIONS]
git-derive[EXE] stash <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-m, --message <MESSAGE>
SUBCOMMANDS:
apply
help Print this message or the help of the given subcommand(s)
pop
push
$ git-derive stash push -h
git-derive[EXE]-stash-push
USAGE:
git-derive[EXE] stash push [OPTIONS]
OPTIONS:
-h, --help Print help information
-m, --message <MESSAGE>
$ git-derive stash pop -h
git-derive[EXE]-stash-pop
USAGE:
git-derive[EXE] stash pop [STASH]
ARGS:
<STASH>
OPTIONS:
-h, --help Print help information
$ git-derive stash -m "Prototype"
Pushing StashPush { message: Some("Prototype") }
$ git-derive stash pop
Popping None
$ git-derive stash push -m "Prototype"
Pushing StashPush { message: Some("Prototype") }
$ git-derive stash pop
Popping None
```
External subcommands:
```console
$ git-derive custom-tool arg1 --foo bar

52
third_party/rust/clap/examples/git-derive.rs поставляемый
Просмотреть файл

@ -3,10 +3,10 @@
use std::ffi::OsString;
use std::path::PathBuf;
use clap::{AppSettings, Parser, Subcommand};
use clap::{Args, Parser, Subcommand};
/// A fictional versioning CLI
#[derive(Parser)]
#[derive(Debug, Parser)]
#[clap(name = "git")]
#[clap(about = "A fictional versioning CLI", long_about = None)]
struct Cli {
@ -14,35 +14,59 @@ struct Cli {
command: Commands,
}
#[derive(Subcommand)]
#[derive(Debug, Subcommand)]
enum Commands {
/// Clones repos
#[clap(setting(AppSettings::ArgRequiredElseHelp))]
#[clap(arg_required_else_help = true)]
Clone {
/// The remote to clone
remote: String,
},
/// pushes things
#[clap(setting(AppSettings::ArgRequiredElseHelp))]
#[clap(arg_required_else_help = true)]
Push {
/// The remote to target
remote: String,
},
/// adds things
#[clap(setting(AppSettings::ArgRequiredElseHelp))]
#[clap(arg_required_else_help = true)]
Add {
/// Stuff to add
#[clap(required = true, parse(from_os_str))]
path: Vec<PathBuf>,
},
Stash(Stash),
#[clap(external_subcommand)]
External(Vec<OsString>),
}
#[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true)]
struct Stash {
#[clap(subcommand)]
command: Option<StashCommands>,
#[clap(flatten)]
push: StashPush,
}
#[derive(Debug, Subcommand)]
enum StashCommands {
Push(StashPush),
Pop { stash: Option<String> },
Apply { stash: Option<String> },
}
#[derive(Debug, Args)]
struct StashPush {
#[clap(short, long)]
message: Option<String>,
}
fn main() {
let args = Cli::parse();
match &args.command {
match args.command {
Commands::Clone { remote } => {
println!("Cloning {}", remote);
}
@ -52,6 +76,20 @@ fn main() {
Commands::Add { path } => {
println!("Adding {:?}", path);
}
Commands::Stash(stash) => {
let stash_cmd = stash.command.unwrap_or(StashCommands::Push(stash.push));
match stash_cmd {
StashCommands::Push(push) => {
println!("Pushing {:?}", push);
}
StashCommands::Pop { stash } => {
println!("Popping {:?}", stash);
}
StashCommands::Apply { stash } => {
println!("Applying {:?}", stash);
}
}
}
Commands::External(args) => {
println!("Calling out to {:?} with {:?}", &args[0], &args[1..]);
}

57
third_party/rust/clap/examples/git.md поставляемый
Просмотреть файл

@ -20,6 +20,7 @@ SUBCOMMANDS:
clone Clones repos
help Print this message or the help of the given subcommand(s)
push pushes things
stash
$ git help
git
@ -36,6 +37,7 @@ SUBCOMMANDS:
clone Clones repos
help Print this message or the help of the given subcommand(s)
push pushes things
stash
$ git help add
git[EXE]-add
@ -73,6 +75,61 @@ Adding ["Cargo.toml", "Cargo.lock"]
```
Default subcommand:
```console
$ git stash -h
git[EXE]-stash
USAGE:
git[EXE] stash [OPTIONS]
git[EXE] stash <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-m, --message <MESSAGE>
SUBCOMMANDS:
apply
help Print this message or the help of the given subcommand(s)
pop
push
$ git stash push -h
git[EXE]-stash-push
USAGE:
git[EXE] stash push [OPTIONS]
OPTIONS:
-h, --help Print help information
-m, --message <MESSAGE>
$ git stash pop -h
git[EXE]-stash-pop
USAGE:
git[EXE] stash pop [STASH]
ARGS:
<STASH>
OPTIONS:
-h, --help Print help information
$ git stash -m "Prototype"
Pushing Some("Prototype")
$ git stash pop
Popping None
$ git stash push -m "Prototype"
Pushing Some("Prototype")
$ git stash pop
Popping None
```
External subcommands:
```console
$ git custom-tool arg1 --foo bar

64
third_party/rust/clap/examples/git.rs поставляемый
Просмотреть файл

@ -1,32 +1,50 @@
// Note: this requires the `cargo` feature
use std::path::PathBuf;
use clap::{arg, App, AppSettings};
use clap::{arg, Command};
fn main() {
let matches = App::new("git")
fn cli() -> Command<'static> {
Command::new("git")
.about("A fictional versioning CLI")
.setting(AppSettings::SubcommandRequiredElseHelp)
.setting(AppSettings::AllowExternalSubcommands)
.setting(AppSettings::AllowInvalidUtf8ForExternalSubcommands)
.subcommand_required(true)
.arg_required_else_help(true)
.allow_external_subcommands(true)
.allow_invalid_utf8_for_external_subcommands(true)
.subcommand(
App::new("clone")
Command::new("clone")
.about("Clones repos")
.arg(arg!(<REMOTE> "The remote to clone"))
.setting(AppSettings::ArgRequiredElseHelp),
.arg_required_else_help(true),
)
.subcommand(
App::new("push")
Command::new("push")
.about("pushes things")
.arg(arg!(<REMOTE> "The remote to target"))
.setting(AppSettings::ArgRequiredElseHelp),
.arg_required_else_help(true),
)
.subcommand(
App::new("add")
Command::new("add")
.about("adds things")
.setting(AppSettings::ArgRequiredElseHelp)
.arg_required_else_help(true)
.arg(arg!(<PATH> ... "Stuff to add").allow_invalid_utf8(true)),
)
.get_matches();
.subcommand(
Command::new("stash")
.args_conflicts_with_subcommands(true)
.args(push_args())
.subcommand(Command::new("push").args(push_args()))
.subcommand(Command::new("pop").arg(arg!([STASH])))
.subcommand(Command::new("apply").arg(arg!([STASH]))),
)
}
fn push_args() -> Vec<clap::Arg<'static>> {
vec![arg!(-m --message <MESSAGE>).required(false)]
}
fn main() {
let matches = cli().get_matches();
match matches.subcommand() {
Some(("clone", sub_matches)) => {
@ -49,6 +67,26 @@ fn main() {
.collect::<Vec<_>>();
println!("Adding {:?}", paths);
}
Some(("stash", sub_matches)) => {
let stash_command = sub_matches.subcommand().unwrap_or(("push", sub_matches));
match stash_command {
("apply", sub_matches) => {
let stash = sub_matches.value_of("STASH");
println!("Applying {:?}", stash);
}
("pop", sub_matches) => {
let stash = sub_matches.value_of("STASH");
println!("Popping {:?}", stash);
}
("push", sub_matches) => {
let message = sub_matches.value_of("message");
println!("Pushing {:?}", message);
}
(name, _) => {
unreachable!("Unsupported subcommand `{}`", name)
}
}
}
Some((ext, sub_matches)) => {
let args = sub_matches
.values_of_os("")

Просмотреть файл

@ -1,31 +0,0 @@
*Jump to [source](keyvalue-derive.rs)*
**This requires enabling the `derive` feature flag.**
```console
$ keyvalue-derive --help
clap
USAGE:
keyvalue-derive[EXE] [OPTIONS]
OPTIONS:
-D <DEFINES>
-h, --help Print help information
$ keyvalue-derive -D Foo=10 -D Alice=30
Args { defines: [("Foo", 10), ("Alice", 30)] }
$ keyvalue-derive -D Foo
? failed
error: Invalid value for '-D <DEFINES>': invalid KEY=value: no `=` found in `Foo`
For more information try --help
$ keyvalue-derive -D Foo=Bar
? failed
error: Invalid value for '-D <DEFINES>': invalid digit found in string
For more information try --help
```

Просмотреть файл

@ -2,7 +2,7 @@
Example of a busybox-style multicall program
See the documentation for clap::AppSettings::Multicall for rationale.
See the documentation for `clap::Command::multicall` for rationale.
This example omits every command except true and false,
which are the most trivial to implement,

Просмотреть файл

@ -1,20 +1,22 @@
// Note: this requires the `unstable-multicall` feature
use std::process::exit;
use clap::{App, AppSettings, Arg};
use clap::{Arg, Command};
fn applet_commands() -> [App<'static>; 2] {
fn applet_commands() -> [Command<'static>; 2] {
[
App::new("true").about("does nothing successfully"),
App::new("false").about("does nothing unsuccessfully"),
Command::new("true").about("does nothing successfully"),
Command::new("false").about("does nothing unsuccessfully"),
]
}
fn main() {
let app = App::new(env!("CARGO_CRATE_NAME"))
.setting(AppSettings::Multicall)
let cmd = Command::new(env!("CARGO_CRATE_NAME"))
.multicall(true)
.subcommand(
App::new("busybox")
.setting(AppSettings::ArgRequiredElseHelp)
Command::new("busybox")
.arg_required_else_help(true)
.subcommand_value_name("APPLET")
.subcommand_help_heading("APPLETS")
.arg(
@ -24,13 +26,13 @@ fn main() {
.exclusive(true)
.takes_value(true)
.default_missing_value("/usr/local/bin")
.use_delimiter(false),
.use_value_delimiter(false),
)
.subcommands(applet_commands()),
)
.subcommands(applet_commands());
let matches = app.get_matches();
let matches = cmd.get_matches();
let mut subcommand = matches.subcommand();
if let Some(("busybox", cmd)) = subcommand {
if cmd.occurrences_of("install") > 0 {

Просмотреть файл

@ -2,7 +2,7 @@
Example of a `hostname-style` multicall program
See the documentation for clap::AppSettings::Multicall for rationale.
See the documentation for `clap::Command::multicall` for rationale.
This example omits the implementation of displaying address config

Просмотреть файл

@ -1,16 +1,17 @@
use clap::{App, AppSettings};
// Note: this requires the `unstable-multicall` feature
use clap::Command;
fn main() {
let app = App::new(env!("CARGO_CRATE_NAME"))
.setting(AppSettings::ArgRequiredElseHelp)
let cmd = Command::new(env!("CARGO_CRATE_NAME"))
.multicall(true)
.arg_required_else_help(true)
.subcommand_value_name("APPLET")
.subcommand_help_heading("APPLETS")
.subcommand(App::new("hostname").about("show hostname part of FQDN"))
.subcommand(App::new("dnsdomainname").about("show domain name part of FQDN"));
.subcommand(Command::new("hostname").about("show hostname part of FQDN"))
.subcommand(Command::new("dnsdomainname").about("show domain name part of FQDN"));
let app = app.setting(AppSettings::Multicall);
match app.get_matches().subcommand_name() {
match cmd.get_matches().subcommand_name() {
Some("hostname") => println!("www"),
Some("dnsdomainname") => println!("example.com"),
_ => unreachable!("parser should ensure only valid subcommand names are used"),

49
third_party/rust/clap/examples/pacman.md поставляемый
Просмотреть файл

@ -34,5 +34,54 @@ Searching for name...
```
*(users can "stack" short subcommands with short flags or with other short flag subcommands)*
In the help, this looks like:
```console
$ pacman -h
pacman 5.2.1
Pacman Development Team
package manager utility
USAGE:
pacman[EXE] <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
query -Q --query Query the package database.
sync -S --sync Synchronize packages.
$ pacman -S -h
pacman[EXE]-sync
Synchronize packages.
USAGE:
pacman[EXE] {sync|--sync|-S} [OPTIONS] [--] [package]...
ARGS:
<package>... packages
OPTIONS:
-h, --help Print help information
-i, --info view package information
-s, --search <search>... search remote repositories for matching strings
```
And errors:
```console
$ pacman -S -s foo -i bar
? failed
error: The argument '--search <search>...' cannot be used with '--info'
USAGE:
pacman[EXE] {sync|--sync|-S} --search <search>... <package>...
For more information try --help
```
**NOTE:** Keep in mind that subcommands, flags, and long flags are *case sensitive*: `-Q` and `-q` are different flags/subcommands. For example, you can have both `-Q` subcommand and `-q` flag, and they will be properly disambiguated.
Let's make a quick program to illustrate.

11
third_party/rust/clap/examples/pacman.rs поставляемый
Просмотреть файл

@ -1,16 +1,17 @@
use clap::{App, AppSettings, Arg};
use clap::{Arg, Command};
fn main() {
let matches = App::new("pacman")
let matches = Command::new("pacman")
.about("package manager utility")
.version("5.2.1")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand_required(true)
.arg_required_else_help(true)
.author("Pacman Development Team")
// Query subcommand
//
// Only a few of its arguments are implemented below.
.subcommand(
App::new("query")
Command::new("query")
.short_flag('Q')
.long_flag("query")
.about("Query the package database.")
@ -37,7 +38,7 @@ fn main() {
//
// Only a few of its arguments are implemented below.
.subcommand(
App::new("sync")
Command::new("sync")
.short_flag('S')
.long_flag("sync")
.about("Synchronize packages.")

94
third_party/rust/clap/examples/repl.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,94 @@
// Note: this requires the `unstable-multicall` feature
use std::io::Write;
use clap::Command;
fn main() -> Result<(), String> {
loop {
let line = readline()?;
let line = line.trim();
if line.is_empty() {
continue;
}
match respond(line) {
Ok(quit) => {
if quit {
break;
}
}
Err(err) => {
write!(std::io::stdout(), "{}", err).map_err(|e| e.to_string())?;
std::io::stdout().flush().map_err(|e| e.to_string())?;
}
}
}
Ok(())
}
fn respond(line: &str) -> Result<bool, String> {
let args = shlex::split(line).ok_or("error: Invalid quoting")?;
let matches = cli()
.try_get_matches_from(&args)
.map_err(|e| e.to_string())?;
match matches.subcommand() {
Some(("ping", _matches)) => {
write!(std::io::stdout(), "Pong").map_err(|e| e.to_string())?;
std::io::stdout().flush().map_err(|e| e.to_string())?;
}
Some(("quit", _matches)) => {
write!(std::io::stdout(), "Exiting ...").map_err(|e| e.to_string())?;
std::io::stdout().flush().map_err(|e| e.to_string())?;
return Ok(true);
}
Some((name, _matches)) => unimplemented!("{}", name),
None => unreachable!("subcommand required"),
}
Ok(false)
}
fn cli() -> Command<'static> {
// strip out usage
const PARSER_TEMPLATE: &str = "\
{all-args}
";
// strip out name/version
const APPLET_TEMPLATE: &str = "\
{about-with-newline}\n\
{usage-heading}\n {usage}\n\
\n\
{all-args}{after-help}\
";
Command::new("repl")
.multicall(true)
.arg_required_else_help(true)
.subcommand_required(true)
.subcommand_value_name("APPLET")
.subcommand_help_heading("APPLETS")
.help_template(PARSER_TEMPLATE)
.subcommand(
Command::new("ping")
.about("Get a response")
.help_template(APPLET_TEMPLATE),
)
.subcommand(
Command::new("quit")
.alias("exit")
.about("Quit the REPL")
.help_template(APPLET_TEMPLATE),
)
}
fn readline() -> Result<String, String> {
write!(std::io::stdout(), "$ ").map_err(|e| e.to_string())?;
std::io::stdout().flush().map_err(|e| e.to_string())?;
let mut buffer = String::new();
std::io::stdin()
.read_line(&mut buffer)
.map_err(|e| e.to_string())?;
Ok(buffer)
}

Просмотреть файл

@ -1,8 +1,10 @@
use clap::{app_from_crate, arg, App};
// Note: this requires the `cargo` feature
use clap::{arg, command, Command};
use std::path::Path;
fn main() {
let matches = app_from_crate!()
let matches = command!()
.arg(arg!([name] "Optional name to operate on"))
.arg(
arg!(
@ -17,7 +19,7 @@ fn main() {
-d --debug ... "Turn debugging information on"
))
.subcommand(
App::new("test")
Command::new("test")
.about("does testing things")
.arg(arg!(-l --list "lists test values")),
)
@ -43,7 +45,7 @@ fn main() {
}
// You can check for the existence of subcommands, and if found use their
// matches just as you would the top level app
// matches just as you would the top level cmd
if let Some(matches) = matches.subcommand_matches("test") {
// "$ myapp test" was run
if matches.is_present("list") {

Просмотреть файл

@ -1,10 +1,12 @@
use clap::{app_from_crate, arg, AppSettings};
// Note: this requires the `cargo` feature
use clap::{arg, command, AppSettings};
fn main() {
let matches = app_from_crate!()
.global_setting(AppSettings::AllArgsOverrideSelf)
let matches = command!()
.args_override_self(true)
.global_setting(AppSettings::DeriveDisplayOrder)
.global_setting(AppSettings::AllowNegativeNumbers)
.allow_negative_numbers(true)
.arg(arg!(--two <VALUE>))
.arg(arg!(--one <VALUE>))
.get_matches();

Просмотреть файл

@ -1,7 +1,7 @@
use clap::{arg, App};
use clap::{arg, Command};
fn main() {
let matches = App::new("MyApp")
let matches = Command::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")

Просмотреть файл

@ -1,7 +1,9 @@
use clap::{app_from_crate, arg};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = app_from_crate!()
let matches = command!()
.arg(arg!(--two <VALUE>))
.arg(arg!(--one <VALUE>))
.get_matches();

Просмотреть файл

@ -1,7 +1,9 @@
use clap::{app_from_crate, arg};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = app_from_crate!().arg(arg!(-v - -verbose)).get_matches();
let matches = command!().arg(arg!(-v - -verbose)).get_matches();
println!("verbose: {:?}", matches.is_present("verbose"));
}

Просмотреть файл

@ -1,7 +1,9 @@
use clap::{app_from_crate, arg};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = app_from_crate!().arg(arg!(-v --verbose ...)).get_matches();
let matches = command!().arg(arg!(-v --verbose ...)).get_matches();
println!("verbose: {:?}", matches.occurrences_of("verbose"));
}

Просмотреть файл

@ -1,7 +1,9 @@
use clap::{app_from_crate, arg};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = app_from_crate!()
let matches = command!()
.arg(arg!(-n --name <NAME>).required(false))
.get_matches();

Просмотреть файл

@ -1,7 +1,9 @@
use clap::{app_from_crate, arg};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = app_from_crate!().arg(arg!([NAME])).get_matches();
let matches = command!().arg(arg!([NAME])).get_matches();
println!("NAME: {:?}", matches.value_of("NAME"));
}

Просмотреть файл

@ -1,12 +1,14 @@
use clap::{app_from_crate, arg, App, AppSettings};
// Note: this requires the `cargo` feature
use clap::{arg, command, Command};
fn main() {
let matches = app_from_crate!()
.global_setting(AppSettings::PropagateVersion)
.global_setting(AppSettings::UseLongFormatForHelpSubcommand)
.setting(AppSettings::SubcommandRequiredElseHelp)
let matches = command!()
.propagate_version(true)
.subcommand_required(true)
.arg_required_else_help(true)
.subcommand(
App::new("add")
Command::new("add")
.about("Adds files to myapp")
.arg(arg!([NAME])),
)
@ -17,6 +19,6 @@ fn main() {
"'myapp add' was used, name is: {:?}",
sub_matches.value_of("NAME")
),
_ => unreachable!(),
_ => unreachable!("Exhausted list of subcommands and subcommand_required prevents `None`"),
}
}

Просмотреть файл

@ -1,7 +1,9 @@
use clap::{app_from_crate, arg};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = app_from_crate!()
let matches = command!()
.arg(arg!([NAME]).default_value("alice"))
.get_matches();

Просмотреть файл

@ -1,4 +1,6 @@
use clap::{app_from_crate, arg, ArgEnum, PossibleValue};
// Note: this requires the `cargo` feature
use clap::{arg, command, ArgEnum, PossibleValue};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ArgEnum)]
enum Mode {
@ -37,7 +39,7 @@ impl std::str::FromStr for Mode {
}
fn main() {
let matches = app_from_crate!()
let matches = command!()
.arg(
arg!(<MODE>)
.help("What mode to run the program in")

Просмотреть файл

@ -1,7 +1,9 @@
use clap::{app_from_crate, arg};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = app_from_crate!()
let matches = command!()
.arg(
arg!(<MODE>)
.help("What mode to run the program in")

19
third_party/rust/clap/examples/tutorial_builder/04_02_parse.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,19 @@
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = command!()
.arg(
arg!(<PORT>)
.help("Network port to use")
.validator(|s| s.parse::<usize>()),
)
.get_matches();
// Note, it's safe to call unwrap() because the arg is required
let port: usize = matches
.value_of_t("PORT")
.expect("'PORT' is required and parsing will fail if its missing");
println!("PORT = {}", port);
}

Просмотреть файл

@ -1,11 +1,15 @@
use clap::{app_from_crate, arg};
// Note: this requires the `cargo` feature
use std::ops::RangeInclusive;
use clap::{arg, command};
fn main() {
let matches = app_from_crate!()
let matches = command!()
.arg(
arg!(<PORT>)
.help("Network port to use")
.validator(|s| s.parse::<usize>()),
.validator(port_in_range),
)
.get_matches();
@ -15,3 +19,20 @@ fn main() {
.expect("'PORT' is required and parsing will fail if its missing");
println!("PORT = {}", port);
}
const PORT_RANGE: RangeInclusive<usize> = 1..=65535;
fn port_in_range(s: &str) -> Result<(), String> {
let port: usize = s
.parse()
.map_err(|_| format!("`{}` isn't a port number", s))?;
if PORT_RANGE.contains(&port) {
Ok(())
} else {
Err(format!(
"Port not in range {}-{}",
PORT_RANGE.start(),
PORT_RANGE.end()
))
}
}

Просмотреть файл

@ -1,8 +1,10 @@
use clap::{app_from_crate, arg, ArgGroup};
// Note: this requires the `cargo` feature
use clap::{arg, command, ArgGroup};
fn main() {
// Create application like normal
let matches = app_from_crate!()
let matches = command!()
// Add the version arguments
.arg(arg!(--"set-ver" <VER> "set version manually").required(false))
.arg(arg!(--major "auto inc major"))

Просмотреть файл

@ -1,8 +1,10 @@
use clap::{app_from_crate, arg, ErrorKind};
// Note: this requires the `cargo` feature
use clap::{arg, command, ErrorKind};
fn main() {
// Create application like normal
let mut app = app_from_crate!()
let mut cmd = command!()
// Add the version arguments
.arg(arg!(--"set-ver" <VER> "set version manually").required(false))
.arg(arg!(--major "auto inc major"))
@ -15,7 +17,7 @@ fn main() {
// Now let's assume we have a -c [config] argument which requires one of
// (but **not** both) the "input" arguments
.arg(arg!(config: -c <CONFIG>).required(false));
let matches = app.get_matches_mut();
let matches = cmd.get_matches_mut();
// Let's assume the old version 1.2.3
let mut major = 1;
@ -26,7 +28,7 @@ fn main() {
let version = if let Some(ver) = matches.value_of("set-ver") {
if matches.is_present("major") || matches.is_present("minor") || matches.is_present("patch")
{
app.error(
cmd.error(
ErrorKind::ArgumentConflict,
"Can't do relative and absolute version change",
)
@ -45,9 +47,9 @@ fn main() {
(false, true, false) => minor += 1,
(false, false, true) => patch += 1,
_ => {
app.error(
cmd.error(
ErrorKind::ArgumentConflict,
"Cam only modify one version field",
"Can only modify one version field",
)
.exit();
}
@ -63,7 +65,7 @@ fn main() {
.value_of("INPUT_FILE")
.or_else(|| matches.value_of("spec-in"))
.unwrap_or_else(|| {
app.error(
cmd.error(
ErrorKind::MissingRequiredArgument,
"INPUT_FILE or --spec-in is required when using --config",
)

Просмотреть файл

@ -1,7 +1,9 @@
use clap::{app_from_crate, arg};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = app().get_matches();
let matches = cmd().get_matches();
// Note, it's safe to call unwrap() because the arg is required
let port: usize = matches
@ -10,8 +12,8 @@ fn main() {
println!("PORT = {}", port);
}
fn app() -> clap::App<'static> {
app_from_crate!().arg(
fn cmd() -> clap::Command<'static> {
command!().arg(
arg!(<PORT>)
.help("Network port to use")
.validator(|s| s.parse::<usize>()),
@ -20,5 +22,5 @@ fn app() -> clap::App<'static> {
#[test]
fn verify_app() {
app().debug_assert();
cmd().debug_assert();
}

Просмотреть файл

@ -5,9 +5,9 @@
1. [Quick Start](#quick-start)
2. [Configuring the Parser](#configuring-the-parser)
3. [Adding Arguments](#adding-arguments)
1. [Flags](#flags)
1. [Positionals](#positionals)
2. [Options](#options)
3. [Positionals](#positionals)
3. [Flags](#flags)
4. [Subcommands](#subcommands)
5. [Defaults](#defaults)
4. Validation
@ -63,7 +63,7 @@ Not printing testing lists...
## Configuring the Parser
You use the `App` the start building a parser.
You use the `Command` the start building a parser.
[Example:](02_apps.rs)
```console
@ -86,7 +86,7 @@ MyApp 1.0
```
You can use `app_from_crate!()` to fill these fields in from your `Cargo.toml`
You can use `command!()` to fill these fields in from your `Cargo.toml`
file. **This requires the `cargo` feature flag.**
[Example:](02_crate.rs)
@ -109,9 +109,7 @@ clap [..]
```
You can use `AppSettings` to change the application level behavior of clap. You
can apply the setting to the top level command (`app.setting()`) or to it and
all subcommands (`app.global_setting()`).
You can use `Command` methods to change the application level behavior of clap.
[Example:](02_app_settings.rs)
```console
@ -136,9 +134,78 @@ one: "-3"
## Adding Arguments
### Positionals
You can have users specify values by their position on the command-line:
[Example:](03_03_positional.rs)
```console
$ 03_03_positional --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_03_positional[EXE] [NAME]
ARGS:
<NAME>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 03_03_positional
NAME: None
$ 03_03_positional bob
NAME: Some("bob")
```
### Options
You can name your arguments with a flag:
- Order doesn't matter
- They can be optional
- Intent is clearer
[Example:](03_02_option.rs)
```console
$ 03_02_option --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_02_option[EXE] [OPTIONS]
OPTIONS:
-h, --help Print help information
-n, --name <NAME>
-V, --version Print version information
$ 03_02_option
name: None
$ 03_02_option --name bob
name: Some("bob")
$ 03_02_option --name=bob
name: Some("bob")
$ 03_02_option -n bob
name: Some("bob")
$ 03_02_option -n=bob
name: Some("bob")
$ 03_02_option -nbob
name: Some("bob")
```
### Flags
Flags are switches that can be on/off:
Flags can also be switches that can be on/off:
[Example:](03_01_flag_bool.rs)
```console
@ -198,96 +265,14 @@ verbose: 2
```
### Options
Flags can also accept a value.
[Example:](03_02_option.rs)
```console
$ 03_02_option --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_02_option[EXE] [OPTIONS]
OPTIONS:
-h, --help Print help information
-n, --name <NAME>
-V, --version Print version information
$ 03_02_option
name: None
$ 03_02_option --name bob
name: Some("bob")
$ 03_02_option --name=bob
name: Some("bob")
$ 03_02_option -n bob
name: Some("bob")
$ 03_02_option -n=bob
name: Some("bob")
$ 03_02_option -nbob
name: Some("bob")
```
### Positionals
Or you can have users specify values by their position on the command-line:
[Example:](03_03_positional.rs)
```console
$ 03_03_positional --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_03_positional[EXE] [NAME]
ARGS:
<NAME>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 03_03_positional
NAME: None
$ 03_03_positional bob
NAME: Some("bob")
```
### Subcommands
Subcommands are defined as `App`s that get added via `App::subcommand`. Each
Subcommands are defined as `Command`s that get added via `Command::subcommand`. Each
instance of a Subcommand can have its own version, author(s), Args, and even its own
subcommands.
[Example:](03_04_subcommands.rs)
```console
$ 03_04_subcommands
? failed
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_04_subcommands[EXE] <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
add Adds files to myapp
help Print this message or the help of the given subcommand(s)
$ 03_04_subcommands help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
@ -322,7 +307,27 @@ $ 03_04_subcommands add bob
```
Because we set `AppSettings::PropagateVersion`:
Because we set `Command::arg_required_else_help`:
```console
$ 03_04_subcommands
? failed
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_04_subcommands[EXE] <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
add Adds files to myapp
help Print this message or the help of the given subcommand(s)
```
Because we set `Command::propagate_version`:
```console
$ 03_04_subcommands --version
clap [..]
@ -445,7 +450,36 @@ For more information try --help
### Validated values
More generally, you can validate and parse into any data type.
More generally, you can parse into any data type.
[Example:](04_02_parse.rs)
```console
$ 04_02_parse --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
04_02_parse[EXE] <PORT>
ARGS:
<PORT> Network port to use
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 04_02_parse 22
PORT = 22
$ 04_02_parse foobar
? failed
error: Invalid value "foobar" for '<PORT>': invalid digit found in string
For more information try --help
```
A custom validator can be used to improve the error messages or provide additional validation:
[Example:](04_02_validate.rs)
```console
@ -468,7 +502,13 @@ PORT = 22
$ 04_02_validate foobar
? failed
error: Invalid value for '<PORT>': invalid digit found in string
error: Invalid value "foobar" for '<PORT>': `foobar` isn't a port number
For more information try --help
$ 04_02_validate 0
? failed
error: Invalid value "0" for '<PORT>': Port not in range 1-65535
For more information try --help
@ -574,7 +614,7 @@ OPTIONS:
$ 04_04_custom
? failed
error: Cam only modify one version field
error: Can only modify one version field
USAGE:
04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
@ -586,7 +626,7 @@ Version: 2.2.3
$ 04_04_custom --major --minor
? failed
error: Cam only modify one version field
error: Can only modify one version field
USAGE:
04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
@ -611,11 +651,13 @@ Doing work using input input.txt and config config.toml
## Tips
- Proactively check for bad `App` configurations by calling `App::debug_assert` ([example](05_01_assert.rs))
- For more complex demonstration of features, see our [examples](../README.md).
- Proactively check for bad `Command` configurations by calling `Command::debug_assert` in a test ([example](05_01_assert.rs))
## Contributing
New example code:
- Please update the corresponding section in the [derive tutorial](../tutorial_derive/README.md)
- Building: They must be added to [Cargo.toml](../../Cargo.toml) with the appropriate `required-features`.
- Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax (generally they'll go in here).

Просмотреть файл

@ -52,7 +52,7 @@ fn main() {
}
// You can check for the existence of subcommands, and if found use their
// matches just as you would the top level app
// matches just as you would the top level cmd
match &cli.command {
Some(Commands::Test { list }) => {
if *list {

Просмотреть файл

@ -2,9 +2,9 @@ use clap::{AppSettings, Parser};
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
#[clap(global_setting(AppSettings::AllArgsOverrideSelf))]
#[clap(args_override_self = true)]
#[clap(allow_negative_numbers = true)]
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
#[clap(global_setting(AppSettings::AllowNegativeNumbers))]
struct Cli {
#[clap(long)]
two: String,

Просмотреть файл

@ -1,9 +1,8 @@
use clap::{AppSettings, Parser, Subcommand};
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
#[clap(global_setting(AppSettings::PropagateVersion))]
#[clap(global_setting(AppSettings::UseLongFormatForHelpSubcommand))]
#[clap(propagate_version = true)]
struct Cli {
#[clap(subcommand)]
command: Commands,
@ -19,7 +18,7 @@ fn main() {
let cli = Cli::parse();
// You can check for the existence of subcommands, and if found use their
// matches just as you would the top level app
// matches just as you would the top level cmd
match &cli.command {
Commands::Add { name } => {
println!("'myapp add' was used, name is: {:?}", name)

Просмотреть файл

@ -0,0 +1,32 @@
use clap::{Args, Parser, Subcommand};
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
#[clap(propagate_version = true)]
struct Cli {
#[clap(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Adds files to myapp
Add(Add),
}
#[derive(Args)]
struct Add {
name: Option<String>,
}
fn main() {
let cli = Cli::parse();
// You can check for the existence of subcommands, and if found use their
// matches just as you would the top level cmd
match &cli.command {
Commands::Add(name) => {
println!("'myapp add' was used, name is: {:?}", name.name)
}
}
}

15
third_party/rust/clap/examples/tutorial_derive/04_02_parse.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,15 @@
use clap::Parser;
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
struct Cli {
/// Network port to use
#[clap(parse(try_from_str))]
port: usize,
}
fn main() {
let cli = Cli::parse();
println!("PORT = {}", cli.port);
}

Просмотреть файл

@ -1,10 +1,12 @@
use std::ops::RangeInclusive;
use clap::Parser;
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
struct Cli {
/// Network port to use
#[clap(parse(try_from_str))]
#[clap(parse(try_from_str=port_in_range))]
port: usize,
}
@ -13,3 +15,20 @@ fn main() {
println!("PORT = {}", cli.port);
}
const PORT_RANGE: RangeInclusive<usize> = 1..=65535;
fn port_in_range(s: &str) -> Result<usize, String> {
let port: usize = s
.parse()
.map_err(|_| format!("`{}` isn't a port number", s))?;
if PORT_RANGE.contains(&port) {
Ok(port)
} else {
Err(format!(
"Port not in range {}-{}",
PORT_RANGE.start(),
PORT_RANGE.end()
))
}
}

Просмотреть файл

@ -1,4 +1,4 @@
use clap::{ErrorKind, IntoApp, Parser};
use clap::{CommandFactory, ErrorKind, Parser};
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
@ -41,8 +41,8 @@ fn main() {
// See if --set-ver was used to set the version manually
let version = if let Some(ver) = cli.set_ver.as_deref() {
if cli.major || cli.minor || cli.patch {
let mut app = Cli::into_app();
app.error(
let mut cmd = Cli::command();
cmd.error(
ErrorKind::ArgumentConflict,
"Can't do relative and absolute version change",
)
@ -57,10 +57,10 @@ fn main() {
(false, true, false) => minor += 1,
(false, false, true) => patch += 1,
_ => {
let mut app = Cli::into_app();
app.error(
let mut cmd = Cli::command();
cmd.error(
ErrorKind::ArgumentConflict,
"Cam only modify one version field",
"Can only modify one version field",
)
.exit();
}
@ -80,8 +80,8 @@ fn main() {
// 'or' is preferred to 'or_else' here since `Option::as_deref` is 'const'
.or(cli.spec_in.as_deref())
.unwrap_or_else(|| {
let mut app = Cli::into_app();
app.error(
let mut cmd = Cli::command();
cmd.error(
ErrorKind::MissingRequiredArgument,
"INPUT_FILE or --spec-in is required when using --config",
)

Просмотреть файл

@ -16,6 +16,6 @@ fn main() {
#[test]
fn verify_app() {
use clap::IntoApp;
Cli::into_app().debug_assert()
use clap::CommandFactory;
Cli::command().debug_assert()
}

Просмотреть файл

@ -5,9 +5,9 @@
1. [Quick Start](#quick-start)
2. [Configuring the Parser](#configuring-the-parser)
3. [Adding Arguments](#adding-arguments)
1. [Flags](#flags)
1. [Positionals](#positionals)
2. [Options](#options)
3. [Positionals](#positionals)
3. [Flags](#flags)
4. [Subcommands](#subcommands)
5. [Defaults](#defaults)
4. Validation
@ -66,7 +66,7 @@ In addition to this tutorial, see the [derive reference](../derive_ref/README.md
## Configuring the Parser
You use the `App` the start building a parser.
You use derive `Parser` the start building a parser.
[Example:](02_apps.rs)
```console
@ -89,7 +89,7 @@ MyApp 1.0
```
You can use `app_from_crate!()` to fill these fields in from your `Cargo.toml` file.
You can use `#[clap(author, version, about)]` attribute defaults to fill these fields in from your `Cargo.toml` file.
[Example:](02_crate.rs)
```console
@ -111,9 +111,7 @@ clap [..]
```
You can use `AppSettings` to change the application level behavior of clap. You
can apply the setting to the top level command (`app.setting()`) or to it and
all subcommands (`app.global_setting()`).
You can use attributes to change the application level behavior of clap. Any `Command` builder function can be used as an attribute.
[Example:](02_app_settings.rs)
```console
@ -138,71 +136,44 @@ one: "-3"
## Adding Arguments
### Flags
### Positionals
Flags are switches that can be on/off:
You can have users specify values by their position on the command-line:
[Example:](03_01_flag_bool.rs)
[Example:](03_03_positional.rs)
```console
$ 03_01_flag_bool_derive --help
$ 03_03_positional_derive --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_01_flag_bool_derive[EXE] [OPTIONS]
03_03_positional_derive[EXE] [NAME]
ARGS:
<NAME>
OPTIONS:
-h, --help Print help information
-v, --verbose
-V, --version Print version information
$ 03_01_flag_bool_derive
verbose: false
$ 03_03_positional_derive
name: None
$ 03_01_flag_bool_derive --verbose
verbose: true
$ 03_01_flag_bool_derive --verbose --verbose
? failed
error: The argument '--verbose' was provided more than once, but cannot be used multiple times
USAGE:
03_01_flag_bool_derive[EXE] [OPTIONS]
For more information try --help
```
Or counted.
[Example:](03_01_flag_count.rs)
```console
$ 03_01_flag_count_derive --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_01_flag_count_derive[EXE] [OPTIONS]
OPTIONS:
-h, --help Print help information
-v, --verbose
-V, --version Print version information
$ 03_01_flag_count_derive
verbose: 0
$ 03_01_flag_count_derive --verbose
verbose: 1
$ 03_01_flag_count_derive --verbose --verbose
verbose: 2
$ 03_03_positional_derive bob
name: Some("bob")
```
### Options
Flags can also accept a value.
You can name your arguments with a flag:
- Order doesn't matter
- They can be optional
- Intent is clearer
The `#[clap(short = 'c')]` and `#[clap(long = "name")]` attributes that define
the flags are `Arg` methods that are derived from the field name when no value
is specified (`#[clap(short)]` and `#[clap(long)]`).
[Example:](03_02_option.rs)
```console
@ -238,58 +209,78 @@ name: Some("bob")
```
### Positionals
### Flags
Or you can have users specify values by their position on the command-line:
Flags can also be switches that can be on/off. This is enabled via the
`#[clap(parse(from_flag)]` attribute though this is implied when the field is a
`bool`.
[Example:](03_03_positional.rs)
[Example:](03_01_flag_bool.rs)
```console
$ 03_03_positional_derive --help
$ 03_01_flag_bool_derive --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_03_positional_derive[EXE] [NAME]
ARGS:
<NAME>
03_01_flag_bool_derive[EXE] [OPTIONS]
OPTIONS:
-h, --help Print help information
-v, --verbose
-V, --version Print version information
$ 03_03_positional_derive
name: None
$ 03_01_flag_bool_derive
verbose: false
$ 03_03_positional_derive bob
name: Some("bob")
$ 03_01_flag_bool_derive --verbose
verbose: true
$ 03_01_flag_bool_derive --verbose --verbose
? failed
error: The argument '--verbose' was provided more than once, but cannot be used multiple times
USAGE:
03_01_flag_bool_derive[EXE] [OPTIONS]
For more information try --help
```
Or counted with `#[clap(parse(from_occurrences))]`:
[Example:](03_01_flag_count.rs)
```console
$ 03_01_flag_count_derive --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_01_flag_count_derive[EXE] [OPTIONS]
OPTIONS:
-h, --help Print help information
-v, --verbose
-V, --version Print version information
$ 03_01_flag_count_derive
verbose: 0
$ 03_01_flag_count_derive --verbose
verbose: 1
$ 03_01_flag_count_derive --verbose --verbose
verbose: 2
```
### Subcommands
Subcommands are defined as `App`s that get added via `App::subcommand`. Each
Subcommands are derived with `#[derive(Subcommand)]` and be added via `#[clap(subcommand)]` attribute. Each
instance of a Subcommand can have its own version, author(s), Args, and even its own
subcommands.
[Example:](03_04_subcommands.rs)
```console
$ 03_04_subcommands_derive
? failed
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_04_subcommands_derive[EXE] <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
add Adds files to myapp
help Print this message or the help of the given subcommand(s)
$ 03_04_subcommands_derive help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
@ -324,7 +315,31 @@ $ 03_04_subcommands_derive add bob
```
Because we set `AppSettings::PropagateVersion`:
Above, we used a struct-variant to define the `add` subcommand. Alternatively,
you can
[use a struct for your subcommand's arguments](03_04_subcommands_alt.rs).
Because we used `command: Commands` instead of `command: Option<Commands>`:
```console
$ 03_04_subcommands_derive
? failed
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_04_subcommands_derive[EXE] <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
add Adds files to myapp
help Print this message or the help of the given subcommand(s)
```
Because we added `#[clap(propagate_version = true)]`:
```console
$ 03_04_subcommands_derive --version
clap [..]
@ -337,8 +352,8 @@ $ 03_04_subcommands_derive add --version
### Defaults
We've previously showed that arguments can be `required` or optional. When
optional, you work with a `Option` and can `unwrap_or`. Alternatively, you can
set `Arg::default_value`.
optional, you work with an `Option` and can `unwrap_or`. Alternatively, you can
set `#[clap(default_value_t)]`.
[Example:](03_05_default_values.rs)
```console
@ -413,6 +428,35 @@ For more information try --help
More generally, you can validate and parse into any data type.
[Example:](04_02_parse.rs)
```console
$ 04_02_parse_derive --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
04_02_parse_derive[EXE] <PORT>
ARGS:
<PORT> Network port to use
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 04_02_parse_derive 22
PORT = 22
$ 04_02_parse_derive foobar
? failed
error: Invalid value "foobar" for '<PORT>': invalid digit found in string
For more information try --help
```
A custom parser can be used to improve the error messages or provide additional validation:
[Example:](04_02_validate.rs)
```console
$ 04_02_validate_derive --help
@ -434,7 +478,13 @@ PORT = 22
$ 04_02_validate_derive foobar
? failed
error: Invalid value for '<PORT>': invalid digit found in string
error: Invalid value "foobar" for '<PORT>': `foobar` isn't a port number
For more information try --help
$ 04_02_validate_derive 0
? failed
error: Invalid value "0" for '<PORT>': Port not in range 1-65535
For more information try --help
@ -540,7 +590,7 @@ OPTIONS:
$ 04_04_custom_derive
? failed
error: Cam only modify one version field
error: Can only modify one version field
USAGE:
clap [OPTIONS] [INPUT_FILE]
@ -552,7 +602,7 @@ Version: 2.2.3
$ 04_04_custom_derive --major --minor
? failed
error: Cam only modify one version field
error: Can only modify one version field
USAGE:
clap [OPTIONS] [INPUT_FILE]
@ -577,11 +627,15 @@ Doing work using input input.txt and config config.toml
## Tips
- Proactively check for bad `App` configurations by calling `App::debug_assert` ([example](05_01_assert.rs))
- For more complex demonstration of features, see our [examples](../README.md).
- See the [derive reference](../derive_ref/README.md) to understand how to use
anything in the [builder API](https://docs.rs/clap/) in the derive API.
- Proactively check for bad `Command` configurations by calling `Command::debug_assert` in a test ([example](05_01_assert.rs))
## Contributing
New example code:
- Please update the corresponding section in the [builder tutorial](../tutorial_builder/README.md)
- Building: They must be added to [Cargo.toml](../../Cargo.toml) with the appropriate `required-features`.
- Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax (generally they'll go in here).

86
third_party/rust/clap/examples/typed-derive.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,86 @@
*Jump to [source](typed-derive.rs)*
**This requires enabling the `derive` feature flag.**
Help:
```console
$ typed-derive --help
clap
USAGE:
typed-derive[EXE] [OPTIONS]
OPTIONS:
--bind <BIND> Handle IP addresses
-D <DEFINES> Hand-written parser for tuples
-h, --help Print help information
-I <DIR> Allow invalid UTF-8 paths
-O <OPTIMIZATION> Implicitly using `std::str::FromStr`
--sleep <SLEEP> Allow human-readable durations
```
Optimization-level (number)
```console
$ typed-derive -O 1
Args { optimization: Some(1), include: None, bind: None, sleep: None, defines: [] }
$ typed-derive -O plaid
? failed
error: Invalid value "plaid" for '-O <OPTIMIZATION>': invalid digit found in string
For more information try --help
```
Include (path)
```console
$ typed-derive -I../hello
Args { optimization: None, include: Some("../hello"), bind: None, sleep: None, defines: [] }
```
IP Address
```console
$ typed-derive --bind 192.0.0.1
Args { optimization: None, include: None, bind: Some(192.0.0.1), sleep: None, defines: [] }
$ typed-derive --bind localhost
? failed
error: Invalid value "localhost" for '--bind <BIND>': invalid IP address syntax
For more information try --help
```
Time
```console
$ typed-derive --sleep 10s
Args { optimization: None, include: None, bind: None, sleep: Some(Duration(10s)), defines: [] }
$ typed-derive --sleep forever
? failed
error: Invalid value "forever" for '--sleep <SLEEP>': expected number at 0
For more information try --help
```
Defines (key-value pairs)
```console
$ typed-derive -D Foo=10 -D Alice=30
Args { optimization: None, include: None, bind: None, sleep: None, defines: [("Foo", 10), ("Alice", 30)] }
$ typed-derive -D Foo
? failed
error: Invalid value "Foo" for '-D <DEFINES>': invalid KEY=value: no `=` found in `Foo`
For more information try --help
$ typed-derive -D Foo=Bar
? failed
error: Invalid value "Foo=Bar" for '-D <DEFINES>': invalid digit found in string
For more information try --help
```

Просмотреть файл

@ -5,6 +5,23 @@ use std::error::Error;
#[derive(Parser, Debug)]
struct Args {
/// Implicitly using `std::str::FromStr`
#[clap(short = 'O')]
optimization: Option<usize>,
/// Allow invalid UTF-8 paths
#[clap(short = 'I', parse(from_os_str), value_name = "DIR", value_hint = clap::ValueHint::DirPath)]
include: Option<std::path::PathBuf>,
/// Handle IP addresses
#[clap(long)]
bind: Option<std::net::IpAddr>,
/// Allow human-readable durations
#[clap(long)]
sleep: Option<humantime::Duration>,
/// Hand-written parser for tuples
#[clap(short = 'D', parse(try_from_str = parse_key_val), multiple_occurrences(true))]
defines: Vec<(String, i32)>,
}

14
third_party/rust/clap/src/bin/stdio-fixture.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
fn main() {
let cmd = clap::Command::new("stdio-fixture")
.version("1.0")
.long_version("1.0 - a2132c")
.arg_required_else_help(true)
.subcommand(clap::Command::new("more"))
.arg(
clap::Arg::new("verbose")
.long("verbose")
.help("log")
.long_help("more log"),
);
cmd.get_matches();
}

Просмотреть файл

@ -1,582 +0,0 @@
use crate::{
build::arg::{debug_asserts::assert_arg, ArgProvider},
mkeymap::KeyType,
util::Id,
App, AppSettings, Arg, ArgSettings, ValueHint,
};
use std::cmp::Ordering;
pub(crate) fn assert_app(app: &App) {
debug!("App::_debug_asserts");
let mut short_flags = vec![];
let mut long_flags = vec![];
// Invalid version flag settings
if app.version.is_none() && app.long_version.is_none() {
// PropagateVersion is meaningless if there is no version
assert!(
!app.settings.is_set(AppSettings::PropagateVersion),
"App {}: No version information via App::version or App::long_version to propagate",
app.get_name(),
);
// Used `App::mut_arg("version", ..) but did not provide any version information to display
let has_mutated_version = app
.args
.args()
.any(|x| x.id == Id::version_hash() && x.provider == ArgProvider::GeneratedMutated);
if has_mutated_version {
assert!(app.settings.is_set(AppSettings::NoAutoVersion),
"App {}: Used App::mut_arg(\"version\", ..) without providing App::version, App::long_version or using AppSettings::NoAutoVersion"
,app.get_name()
);
}
}
for sc in &app.subcommands {
if let Some(s) = sc.short_flag.as_ref() {
short_flags.push(Flag::App(format!("-{}", s), &sc.name));
}
for (short_alias, _) in &sc.short_flag_aliases {
short_flags.push(Flag::App(format!("-{}", short_alias), &sc.name));
}
if let Some(l) = sc.long_flag.as_ref() {
long_flags.push(Flag::App(format!("--{}", l), &sc.name));
}
for (long_alias, _) in &sc.long_flag_aliases {
long_flags.push(Flag::App(format!("--{}", long_alias), &sc.name));
}
}
for arg in app.args.args() {
assert_arg(arg);
if let Some(s) = arg.short.as_ref() {
short_flags.push(Flag::Arg(format!("-{}", s), &*arg.name));
}
for (short_alias, _) in &arg.short_aliases {
short_flags.push(Flag::Arg(format!("-{}", short_alias), arg.name));
}
if let Some(l) = arg.long.as_ref() {
long_flags.push(Flag::Arg(format!("--{}", l), &*arg.name));
}
for (long_alias, _) in &arg.aliases {
long_flags.push(Flag::Arg(format!("--{}", long_alias), arg.name));
}
// Name conflicts
assert!(
app.two_args_of(|x| x.id == arg.id).is_none(),
"App {}: Argument names must be unique, but '{}' is in use by more than one argument or group",
app.get_name(),
arg.name,
);
// Long conflicts
if let Some(l) = arg.long {
if let Some((first, second)) = app.two_args_of(|x| x.long == Some(l)) {
panic!(
"App {}: Long option names must be unique for each argument, \
but '--{}' is in use by both '{}' and '{}'",
app.get_name(),
l,
first.name,
second.name
)
}
}
// Short conflicts
if let Some(s) = arg.short {
if let Some((first, second)) = app.two_args_of(|x| x.short == Some(s)) {
panic!(
"App {}: Short option names must be unique for each argument, \
but '-{}' is in use by both '{}' and '{}'",
app.get_name(),
s,
first.name,
second.name
)
}
}
// Index conflicts
if let Some(idx) = arg.index {
if let Some((first, second)) =
app.two_args_of(|x| x.is_positional() && x.index == Some(idx))
{
panic!(
"App {}: Argument '{}' has the same index as '{}' \
and they are both positional arguments\n\n\t \
Use Arg::multiple_values(true) to allow one \
positional argument to take multiple values",
app.get_name(),
first.name,
second.name
)
}
}
// requires, r_if, r_unless
for req in &arg.requires {
assert!(
app.id_exists(&req.1),
"App {}: Argument or group '{:?}' specified in 'requires*' for '{}' does not exist",
app.get_name(),
req.1,
arg.name,
);
}
for req in &arg.r_ifs {
assert!(
app.id_exists(&req.0),
"App {}: Argument or group '{:?}' specified in 'required_if_eq*' for '{}' does not exist",
app.get_name(),
req.0,
arg.name
);
}
for req in &arg.r_ifs_all {
assert!(
app.id_exists(&req.0),
"App {}: Argument or group '{:?}' specified in 'required_if_eq_all' for '{}' does not exist",
app.get_name(),
req.0,
arg.name
);
}
for req in &arg.r_unless {
assert!(
app.id_exists(req),
"App {}: Argument or group '{:?}' specified in 'required_unless*' for '{}' does not exist",
app.get_name(),
req,
arg.name,
);
}
// blacklist
for req in &arg.blacklist {
assert!(
app.id_exists(req),
"App {}: Argument or group '{:?}' specified in 'conflicts_with*' for '{}' does not exist",
app.get_name(),
req,
arg.name,
);
}
if arg.is_set(ArgSettings::Last) {
assert!(
arg.long.is_none(),
"App {}: Flags or Options cannot have last(true) set. '{}' has both a long and last(true) set.",
app.get_name(),
arg.name
);
assert!(
arg.short.is_none(),
"App {}: Flags or Options cannot have last(true) set. '{}' has both a short and last(true) set.",
app.get_name(),
arg.name
);
}
assert!(
!(arg.is_set(ArgSettings::Required) && arg.get_global()),
"App {}: Global arguments cannot be required.\n\n\t'{}' is marked as both global and required",
app.get_name(),
arg.name
);
// validators
assert!(
arg.validator.is_none() || arg.validator_os.is_none(),
"App {}: Argument '{}' has both `validator` and `validator_os` set which is not allowed",
app.get_name(),
arg.name
);
if arg.value_hint == ValueHint::CommandWithArguments {
assert!(
arg.is_positional(),
"App {}: Argument '{}' has hint CommandWithArguments and must be positional.",
app.get_name(),
arg.name
);
assert!(
app.is_set(AppSettings::TrailingVarArg),
"App {}: Positional argument '{}' has hint CommandWithArguments, so App must have TrailingVarArg set.",
app.get_name(),
arg.name
);
}
}
for group in &app.groups {
// Name conflicts
assert!(
app.groups.iter().filter(|x| x.id == group.id).count() < 2,
"App {}: Argument group name must be unique\n\n\t'{}' is already in use",
app.get_name(),
group.name,
);
// Groups should not have naming conflicts with Args
assert!(
!app.args.args().any(|x| x.id == group.id),
"App {}: Argument group name '{}' must not conflict with argument name",
app.get_name(),
group.name,
);
// Required groups should have at least one arg without default values
if group.required && !group.args.is_empty() {
assert!(
group.args.iter().any(|arg| {
app.args
.args()
.any(|x| x.id == *arg && x.default_vals.is_empty())
}),
"App {}: Argument group '{}' is required but all of it's arguments have a default value.",
app.get_name(),
group.name
)
}
for arg in &group.args {
// Args listed inside groups should exist
assert!(
app.args.args().any(|x| x.id == *arg),
"App {}: Argument group '{}' contains non-existent argument '{:?}'",
app.get_name(),
group.name,
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");
_verify_positionals(app);
if let Some(help_template) = app.template {
assert!(
!help_template.contains("{flags}"),
"App {}: {}",
app.get_name(),
"`{flags}` template variable was removed in clap3, they are now included in `{options}`",
);
assert!(
!help_template.contains("{unified}"),
"App {}: {}",
app.get_name(),
"`{unified}` template variable was removed in clap3, use `{options}` instead"
);
}
app._panic_on_missing_help(app.g_settings.is_set(AppSettings::HelpExpected));
assert_app_flags(app);
}
#[derive(Eq)]
enum Flag<'a> {
App(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> {
use Flag::*;
match (self, other) {
(App(s1, _), App(s2, _))
| (Arg(s1, _), Arg(s2, _))
| (App(s1, _), Arg(s2, _))
| (Arg(s1, _), App(s2, _)) => {
if s1 == s2 {
Some(Ordering::Equal)
} else {
s1.partial_cmp(s2)
}
}
}
}
}
impl Ord for Flag<'_> {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
fn detect_duplicate_flags(flags: &[Flag], short_or_long: &str) {
use Flag::*;
for (one, two) in find_duplicates(flags) {
match (one, two) {
(App(flag, one), App(_, another)) if one != another => panic!(
"the '{}' {} flag is specified for both '{}' and '{}' subcommands",
flag, short_or_long, one, another
),
(Arg(flag, one), Arg(_, another)) if one != another => panic!(
"{} option names must be unique, but '{}' is in use by both '{}' and '{}'",
short_or_long, flag, one, another
),
(Arg(flag, arg), App(_, sub)) | (App(flag, sub), Arg(_, arg)) => panic!(
"the '{}' {} flag for the '{}' argument conflicts with the short flag \
for '{}' subcommand",
flag, short_or_long, arg, sub
),
_ => {}
}
}
}
/// 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(app: &App) {
use AppSettings::*;
macro_rules! checker {
($a:ident requires $($b:ident)|+) => {
if app.is_set($a) {
let mut s = String::new();
$(
if !app.is_set($b) {
s.push_str(&format!(" AppSettings::{} is required when AppSettings::{} is set.\n", std::stringify!($b), std::stringify!($a)));
}
)+
if !s.is_empty() {
panic!("{}", s)
}
}
};
($a:ident conflicts $($b:ident)|+) => {
if app.is_set($a) {
let mut s = String::new();
$(
if app.is_set($b) {
s.push_str(&format!(" AppSettings::{} conflicts with AppSettings::{}.\n", std::stringify!($b), std::stringify!($a)));
}
)+
if !s.is_empty() {
panic!("{}\n{}", app.get_name(), s)
}
}
};
}
checker!(AllowInvalidUtf8ForExternalSubcommands requires AllowExternalSubcommands);
#[cfg(feature = "unstable-multicall")]
checker!(Multicall conflicts NoBinaryName);
}
#[cfg(debug_assertions)]
fn _verify_positionals(app: &App) -> bool {
debug!("App::_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 = app
.args
.keys()
.filter_map(|x| {
if let KeyType::Position(n) = x {
Some(*n)
} else {
None
}
})
.max()
.unwrap_or(0);
let num_p = app.args.keys().filter(|x| x.is_position()).count();
assert!(
highest_idx == num_p,
"Found positional argument whose index is {} but there \
are only {} positional arguments defined",
highest_idx,
num_p
);
// Next we verify that only the highest index has takes multiple arguments (if any)
let only_highest = |a: &Arg| a.is_multiple() && (a.index.unwrap_or(0) != highest_idx);
if app.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 = &app.args[&KeyType::Position(highest_idx)];
let second_to_last = &app.args[&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_set(ArgSettings::Required)
|| (second_to_last.terminator.is_some() || second_to_last.is_set(ArgSettings::Last))
|| last.is_set(ArgSettings::Last);
assert!(
ok,
"When using a positional argument with .multiple_values(true) that is *not the \
last* positional argument, the last positional argument (i.e. the one \
with the highest index) *must* have .required(true) or .last(true) set."
);
// We make sure if the second to last is Multiple the last is ArgSettings::Last
let ok = second_to_last.is_multiple() || last.is_set(ArgSettings::Last);
assert!(
ok,
"Only the last positional argument, or second to last positional \
argument may be set to .multiple_values(true)"
);
// Next we check how many have both Multiple and not a specific number of values set
let count = app
.get_positionals()
.filter(|p| {
p.settings.is_set(ArgSettings::MultipleOccurrences)
|| (p.settings.is_set(ArgSettings::MultipleValues) && p.num_vals.is_none())
})
.count();
let ok = count <= 1
|| (last.is_set(ArgSettings::Last)
&& last.is_multiple()
&& second_to_last.is_multiple()
&& count == 2);
assert!(
ok,
"Only one positional argument with .multiple_values(true) set is allowed per \
command, unless the second one also has .last(true) set"
);
}
let mut found = false;
if app.is_set(AppSettings::AllowMissingPositional) {
// 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 app.get_positionals() {
if foundx2 && !p.is_set(ArgSettings::Required) {
assert!(
p.is_set(ArgSettings::Required),
"Found non-required positional argument with a lower \
index than a required positional argument by two or more: {:?} \
index {:?}",
p.name,
p.index
);
} else if p.is_set(ArgSettings::Required) && !p.is_set(ArgSettings::Last) {
// 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;
continue;
} 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| app.args.get(&n)) {
if found {
assert!(
p.is_set(ArgSettings::Required),
"Found non-required positional argument with a lower \
index than a required positional argument: {:?} index {:?}",
p.name,
p.index
);
} else if p.is_set(ArgSettings::Required) && !p.is_set(ArgSettings::Last) {
// 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;
continue;
}
}
}
assert!(
app.get_positionals()
.filter(|p| p.is_set(ArgSettings::Last))
.count()
< 2,
"Only one positional argument may have last(true) set. Found two."
);
if app
.get_positionals()
.any(|p| p.is_set(ArgSettings::Last) && p.is_set(ArgSettings::Required))
&& app.has_subcommands()
&& !app.is_set(AppSettings::SubcommandsNegateReqs)
{
panic!(
"Having a required positional argument with .last(true) set *and* child \
subcommands without setting SubcommandsNegateReqs isn't compatible."
);
}
true
}

1366
third_party/rust/clap/src/build/app/settings.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

63
third_party/rust/clap/src/build/app/tests.rs поставляемый
Просмотреть файл

@ -1,63 +0,0 @@
use crate::{App, AppSettings};
#[test]
fn propagate_version() {
let mut app = App::new("test")
.setting(AppSettings::PropagateVersion)
.version("1.1")
.subcommand(App::new("sub1"));
app._propagate();
assert_eq!(app.subcommands[0].version, Some("1.1"));
}
#[test]
fn global_setting() {
let mut app = App::new("test")
.global_setting(AppSettings::AllowHyphenValues)
.subcommand(App::new("subcmd"));
app._propagate();
assert!(app
.subcommands
.iter()
.find(|s| s.name == "subcmd")
.unwrap()
.is_set(AppSettings::AllowHyphenValues));
}
#[test]
fn global_settings() {
let mut app = App::new("test")
.global_setting(AppSettings::AllowHyphenValues)
.global_setting(AppSettings::TrailingVarArg)
.subcommand(App::new("subcmd"));
app._propagate();
assert!(app
.subcommands
.iter()
.find(|s| s.name == "subcmd")
.unwrap()
.is_set(AppSettings::AllowHyphenValues));
assert!(app
.subcommands
.iter()
.find(|s| s.name == "subcmd")
.unwrap()
.is_set(AppSettings::TrailingVarArg));
}
// This test will *fail to compile* if App is not Send + Sync
#[test]
fn app_send_sync() {
fn foo<T: Send + Sync>(_: T) {}
foo(App::new("test"))
}
#[test]
fn issue_2090() {
let mut app = App::new("app")
.global_setting(AppSettings::DisableVersionFlag)
.subcommand(App::new("sub"));
app._build();
assert!(app.subcommands[0].is_set(AppSettings::DisableVersionFlag));
}

765
third_party/rust/clap/src/build/app_settings.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,765 @@
#![allow(deprecated)]
// Std
use std::ops::BitOr;
#[cfg(feature = "yaml")]
use std::str::FromStr;
#[allow(unused)]
use crate::Arg;
#[allow(unused)]
use crate::Command;
// Third party
use bitflags::bitflags;
#[doc(hidden)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct AppFlags(Flags);
impl Default for AppFlags {
fn default() -> Self {
AppFlags(Flags::COLOR_AUTO)
}
}
/// Application level settings, which affect how [`Command`] operates
///
/// **NOTE:** When these settings are used, they apply only to current command, and are *not*
/// propagated down or up through child or parent subcommands
///
/// [`Command`]: crate::Command
#[derive(Debug, PartialEq, Copy, Clone)]
#[non_exhaustive]
pub enum AppSettings {
/// Deprecated, replaced with [`Command::ignore_errors`]
#[deprecated(since = "3.1.0", note = "Replaced with `Command::ignore_errors`")]
IgnoreErrors,
/// Deprecated, replace
/// ```rust,no_run
/// let cmd = clap::Command::new("cmd")
/// .global_setting(clap::AppSettings::WaitOnError)
/// .arg(clap::arg!(--flag));
/// let m = cmd.get_matches();
/// ```
/// with
/// ```rust
/// let cmd = clap::Command::new("cmd")
/// .arg(clap::arg!(--flag));
/// let m = match cmd.try_get_matches() {
/// Ok(m) => m,
/// Err(err) => {
/// if err.use_stderr() {
/// let _ = err.print();
///
/// eprintln!("\nPress [ENTER] / [RETURN] to continue...");
/// use std::io::BufRead;
/// let mut s = String::new();
/// let i = std::io::stdin();
/// i.lock().read_line(&mut s).unwrap();
///
/// std::process::exit(2);
/// } else {
/// let _ = err.print();
/// std::process::exit(0);
/// }
/// }
/// };
/// ```
#[deprecated(
since = "3.1.0",
note = "See documentation for how to hand-implement this"
)]
WaitOnError,
/// Deprecated, replaced with [`Command::allow_hyphen_values`] and
/// [`Arg::is_allow_hyphen_values_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::allow_hyphen_values` and `Arg::is_allow_hyphen_values_set`"
)]
AllowHyphenValues,
/// Deprecated, replaced with [`Command::allow_negative_numbers`] and
/// [`Command::is_allow_negative_numbers_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::allow_negative_numbers` and `Command::is_allow_negative_numbers_set`"
)]
AllowNegativeNumbers,
/// Deprecated, replaced with [`Command::args_override_self`]
#[deprecated(since = "3.1.0", note = "Replaced with `Command::args_override_self`")]
AllArgsOverrideSelf,
/// Deprecated, replaced with [`Command::allow_missing_positional`] and
/// [`Command::is_allow_missing_positional_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::allow_missing_positional` and `Command::is_allow_missing_positional_set`"
)]
AllowMissingPositional,
/// Deprecated, replaced with [`Command::trailing_var_arg`] and [`Command::is_trailing_var_arg_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::trailing_var_arg` and `Command::is_trailing_var_arg_set`"
)]
TrailingVarArg,
/// Deprecated, replaced with [`Command::dont_delimit_trailing_values`] and
/// [`Command::is_dont_delimit_trailing_values_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::dont_delimit_trailing_values` and `Command::is_dont_delimit_trailing_values_set`"
)]
DontDelimitTrailingValues,
/// Deprecated, replaced with [`Command::infer_long_args`]
#[deprecated(since = "3.1.0", note = "Replaced with `Command::infer_long_args`")]
InferLongArgs,
/// Deprecated, replaced with [`Command::infer_subcommands`]
#[deprecated(since = "3.1.0", note = "Replaced with `Command::infer_subcommands`")]
InferSubcommands,
/// Deprecated, replaced with [`Command::subcommand_required`] and
/// [`Command::is_subcommand_required_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::subcommand_required` and `Command::is_subcommand_required_set`"
)]
SubcommandRequired,
/// Deprecated, replaced with [`Command::subcommand_required`] combined with
/// [`Command::arg_required_else_help`].
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::subcommand_required` combined with `Command::arg_required_else_help`"
)]
SubcommandRequiredElseHelp,
/// Deprecated, replaced with [`Command::allow_external_subcommands`] and
/// [`Command::is_allow_external_subcommands_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::allow_external_subcommands` and `Command::is_allow_external_subcommands_set`"
)]
AllowExternalSubcommands,
/// Deprecated, replaced with [`Command::multicall`] and [`Command::is_multicall_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::multicall` and `Command::is_multicall_set`"
)]
#[cfg(feature = "unstable-multicall")]
Multicall,
/// Deprecated, replaced with [`Command::allow_invalid_utf8_for_external_subcommands`] and [`Command::is_allow_invalid_utf8_for_external_subcommands_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::allow_invalid_utf8_for_external_subcommands` and `Command::is_allow_invalid_utf8_for_external_subcommands_set`"
)]
AllowInvalidUtf8ForExternalSubcommands,
/// Deprecated, this is now the default
#[deprecated(since = "3.1.0", note = "This is now the default")]
UseLongFormatForHelpSubcommand,
/// Deprecated, replaced with [`Command::subcommand_negates_reqs`] and
/// [`Command::is_subcommand_negates_reqs_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::subcommand_negates_reqs` and `Command::is_subcommand_negates_reqs_set`"
)]
SubcommandsNegateReqs,
/// Deprecated, replaced with [`Command::args_conflicts_with_subcommands`] and
/// [`Command::is_args_conflicts_with_subcommands_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::args_conflicts_with_subcommands` and `Command::is_args_conflicts_with_subcommands_set`"
)]
ArgsNegateSubcommands,
/// Deprecated, replaced with [`Command::subcommand_precedence_over_arg`] and
/// [`Command::is_subcommand_precedence_over_arg_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::subcommand_precedence_over_arg` and `Command::is_subcommand_precedence_over_arg_set`"
)]
SubcommandPrecedenceOverArg,
/// Deprecated, replaced with [`Command::arg_required_else_help`] and
/// [`Command::is_arg_required_else_help_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::arg_required_else_help` and `Command::is_arg_required_else_help_set`"
)]
ArgRequiredElseHelp,
/// Displays the arguments and [`subcommands`] in the help message in the order that they were
/// declared in, and not alphabetically which is the default.
///
/// To override the declaration order, see [`Arg::display_order`] and [`Command::display_order`].
///
/// # Examples
///
/// ```no_run
/// # use clap::{Command, Arg, AppSettings};
/// Command::new("myprog")
/// .global_setting(AppSettings::DeriveDisplayOrder)
/// .get_matches();
/// ```
///
/// [`subcommands`]: crate::Command::subcommand()
/// [`Arg::display_order`]: crate::Arg::display_order
/// [`Command::display_order`]: crate::Command::display_order
DeriveDisplayOrder,
/// Deprecated, replaced with [`Command::dont_collapse_args_in_usage`] and
/// [`Command::is_dont_collapse_args_in_usage_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::dont_collapse_args_in_usage` and `Command::is_dont_collapse_args_in_usage_set`"
)]
DontCollapseArgsInUsage,
/// Deprecated, replaced with [`Command::next_line_help`] and [`Command::is_next_line_help_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::next_line_help` and `Command::is_next_line_help_set`"
)]
NextLineHelp,
/// Deprecated, replaced with [`Command::disable_colored_help`] and
/// [`Command::is_disable_colored_help_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::disable_colored_help` and `Command::is_disable_colored_help_set`"
)]
DisableColoredHelp,
/// Deprecated, replaced with [`Command::disable_help_flag`] and [`Command::is_disable_help_flag_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::disable_help_flag` and `Command::is_disable_help_flag_set`"
)]
DisableHelpFlag,
/// Deprecated, replaced with [`Command::disable_help_subcommand`] and
/// [`Command::is_disable_help_subcommand_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::disable_help_subcommand` and `Command::is_disable_help_subcommand_set`"
)]
DisableHelpSubcommand,
/// Deprecated, replaced with [`Command::disable_version_flag`] and
/// [`Command::is_disable_version_flag_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::disable_version_flag` and `Command::is_disable_version_flag_set`"
)]
DisableVersionFlag,
/// Deprecated, replaced with [`Command::propagate_version`] and [`Command::is_propagate_version_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::propagate_version` and `Command::is_propagate_version_set`"
)]
PropagateVersion,
/// Deprecated, replaced with [`Command::hide`] and [`Command::is_hide_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::hide` and `Command::is_hide_set`"
)]
Hidden,
/// Deprecated, replaced with [`Command::hide_possible_values`] and
/// [`Arg::is_hide_possible_values_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Command::hide_possible_values` and `Arg::is_hide_possible_values_set`"
)]
HidePossibleValues,
/// Deprecated, replaced with [`Command::help_expected`]
#[deprecated(since = "3.1.0", note = "Replaced with `Command::help_expected`")]
HelpExpected,
/// Deprecated, replaced with [`Command::no_binary_name`]
#[deprecated(since = "3.1.0", note = "Replaced with `Command::no_binary_name`")]
NoBinaryName,
/// Treat the auto-generated `-h, --help` flags like any other flag, and *not* print the help
/// message.
///
/// This allows one to handle printing of the help message manually.
///
/// ```rust
/// # use clap::{Command, AppSettings};
/// let result = Command::new("myprog")
/// .setting(AppSettings::NoAutoHelp)
/// .try_get_matches_from("myprog --help".split(" "));
///
/// // Normally, if `--help` is used clap prints the help message and returns an
/// // ErrorKind::DisplayHelp
/// //
/// // However, `--help` was treated like a normal flag
///
/// assert!(result.is_ok());
/// assert!(result.unwrap().is_present("help"));
/// ```
NoAutoHelp,
/// Treat the auto-generated `-V, --version` flags like any other flag, and
/// *not* print the version message.
///
/// This allows one to handle printing of the version message manually.
///
/// ```rust
/// # use clap::{Command, AppSettings};
/// let result = Command::new("myprog")
/// .version("3.0")
/// .setting(AppSettings::NoAutoVersion)
/// .try_get_matches_from("myprog --version".split(" "));
///
/// // Normally, if `--version` is used clap prints the version message and returns an
/// // ErrorKind::DisplayVersion
/// //
/// // However, `--version` was treated like a normal flag
///
/// assert!(result.is_ok());
/// assert!(result.unwrap().is_present("version"));
/// ```
NoAutoVersion,
/// Deprecated, replaced with [`AppSettings::AllowHyphenValues`]
#[deprecated(
since = "3.0.0",
note = "Replaced with `AppSettings::AllowHyphenValues`"
)]
#[doc(hidden)]
AllowLeadingHyphen,
/// Deprecated, this is now the default, see [`AppSettings::AllowInvalidUtf8ForExternalSubcommands`] and [`ArgSettings::AllowInvalidUtf8`][crate::ArgSettings::AllowInvalidUtf8] for the opposite.
#[deprecated(
since = "3.0.0",
note = "This is now the default see `AppSettings::AllowInvalidUtf8ForExternalSubcommands` and `ArgSettings::AllowInvalidUtf8` for the opposite."
)]
#[doc(hidden)]
StrictUtf8,
/// Deprecated, this is now the default
#[deprecated(since = "3.0.0", note = "This is now the default")]
#[doc(hidden)]
UnifiedHelpMessage,
/// Deprecated, this is now the default
#[deprecated(since = "3.0.0", note = "This is now the default")]
#[doc(hidden)]
ColoredHelp,
/// Deprecated, see [`Command::color`][crate::Command::color]
#[deprecated(since = "3.0.0", note = "Replaced with `Command::color`")]
#[doc(hidden)]
ColorAuto,
/// Deprecated, replaced with [`Command::color`][crate::Command::color]
#[deprecated(since = "3.0.0", note = "Replaced with `Command::color`")]
#[doc(hidden)]
ColorAlways,
/// Deprecated, replaced with [`Command::color`][crate::Command::color]
#[deprecated(since = "3.0.0", note = "Replaced with `Command::color`")]
#[doc(hidden)]
ColorNever,
/// Deprecated, replaced with [`AppSettings::DisableHelpFlag`]
#[deprecated(since = "3.0.0", note = "Replaced with `AppSettings::DisableHelpFlag`")]
#[doc(hidden)]
DisableHelpFlags,
/// Deprecated, replaced with [`AppSettings::DisableVersionFlag`]
#[deprecated(
since = "3.0.0",
note = "Replaced with `AppSettings::DisableVersionFlag`"
)]
#[doc(hidden)]
DisableVersion,
/// Deprecated, replaced with [`AppSettings::PropagateVersion`]
#[deprecated(
since = "3.0.0",
note = "Replaced with `AppSettings::PropagateVersion`"
)]
#[doc(hidden)]
GlobalVersion,
/// Deprecated, replaced with [`AppSettings::HidePossibleValues`]
#[deprecated(
since = "3.0.0",
note = "Replaced with AppSettings::HidePossibleValues"
)]
#[doc(hidden)]
HidePossibleValuesInHelp,
/// Deprecated, this is now the default
#[deprecated(since = "3.0.0", note = "This is now the default")]
#[doc(hidden)]
UnifiedHelp,
/// If the cmd is already built, used for caching.
#[doc(hidden)]
Built,
/// If the cmd's bin name is already built, used for caching.
#[doc(hidden)]
BinNameBuilt,
}
bitflags! {
struct Flags: u64 {
const SC_NEGATE_REQS = 1;
const SC_REQUIRED = 1 << 1;
const ARG_REQUIRED_ELSE_HELP = 1 << 2;
const PROPAGATE_VERSION = 1 << 3;
const DISABLE_VERSION_FOR_SC = 1 << 4;
const WAIT_ON_ERROR = 1 << 6;
const SC_REQUIRED_ELSE_HELP = 1 << 7;
const NO_AUTO_HELP = 1 << 8;
const NO_AUTO_VERSION = 1 << 9;
const DISABLE_VERSION_FLAG = 1 << 10;
const HIDDEN = 1 << 11;
const TRAILING_VARARG = 1 << 12;
const NO_BIN_NAME = 1 << 13;
const ALLOW_UNK_SC = 1 << 14;
const SC_UTF8_NONE = 1 << 15;
const LEADING_HYPHEN = 1 << 16;
const NO_POS_VALUES = 1 << 17;
const NEXT_LINE_HELP = 1 << 18;
const DERIVE_DISP_ORDER = 1 << 19;
const DISABLE_COLORED_HELP = 1 << 20;
const COLOR_ALWAYS = 1 << 21;
const COLOR_AUTO = 1 << 22;
const COLOR_NEVER = 1 << 23;
const DONT_DELIM_TRAIL = 1 << 24;
const ALLOW_NEG_NUMS = 1 << 25;
const DISABLE_HELP_SC = 1 << 27;
const DONT_COLLAPSE_ARGS = 1 << 28;
const ARGS_NEGATE_SCS = 1 << 29;
const PROPAGATE_VALS_DOWN = 1 << 30;
const ALLOW_MISSING_POS = 1 << 31;
const TRAILING_VALUES = 1 << 32;
const BUILT = 1 << 33;
const BIN_NAME_BUILT = 1 << 34;
const VALID_ARG_FOUND = 1 << 35;
const INFER_SUBCOMMANDS = 1 << 36;
const CONTAINS_LAST = 1 << 37;
const ARGS_OVERRIDE_SELF = 1 << 38;
const HELP_REQUIRED = 1 << 39;
const SUBCOMMAND_PRECEDENCE_OVER_ARG = 1 << 40;
const DISABLE_HELP_FLAG = 1 << 41;
const USE_LONG_FORMAT_FOR_HELP_SC = 1 << 42;
const INFER_LONG_ARGS = 1 << 43;
const IGNORE_ERRORS = 1 << 44;
#[cfg(feature = "unstable-multicall")]
const MULTICALL = 1 << 45;
const NO_OP = 0;
}
}
impl_settings! { AppSettings, AppFlags,
ArgRequiredElseHelp
=> Flags::ARG_REQUIRED_ELSE_HELP,
SubcommandPrecedenceOverArg
=> Flags::SUBCOMMAND_PRECEDENCE_OVER_ARG,
ArgsNegateSubcommands
=> Flags::ARGS_NEGATE_SCS,
AllowExternalSubcommands
=> Flags::ALLOW_UNK_SC,
StrictUtf8
=> Flags::NO_OP,
AllowInvalidUtf8ForExternalSubcommands
=> Flags::SC_UTF8_NONE,
AllowHyphenValues
=> Flags::LEADING_HYPHEN,
AllowLeadingHyphen
=> Flags::LEADING_HYPHEN,
AllowNegativeNumbers
=> Flags::ALLOW_NEG_NUMS,
AllowMissingPositional
=> Flags::ALLOW_MISSING_POS,
UnifiedHelpMessage
=> Flags::NO_OP,
ColoredHelp
=> Flags::NO_OP,
ColorAlways
=> Flags::COLOR_ALWAYS,
ColorAuto
=> Flags::COLOR_AUTO,
ColorNever
=> Flags::COLOR_NEVER,
DontDelimitTrailingValues
=> Flags::DONT_DELIM_TRAIL,
DontCollapseArgsInUsage
=> Flags::DONT_COLLAPSE_ARGS,
DeriveDisplayOrder
=> Flags::DERIVE_DISP_ORDER,
DisableColoredHelp
=> Flags::DISABLE_COLORED_HELP,
DisableHelpSubcommand
=> Flags::DISABLE_HELP_SC,
DisableHelpFlag
=> Flags::DISABLE_HELP_FLAG,
DisableHelpFlags
=> Flags::DISABLE_HELP_FLAG,
DisableVersionFlag
=> Flags::DISABLE_VERSION_FLAG,
DisableVersion
=> Flags::DISABLE_VERSION_FLAG,
PropagateVersion
=> Flags::PROPAGATE_VERSION,
GlobalVersion
=> Flags::PROPAGATE_VERSION,
HidePossibleValues
=> Flags::NO_POS_VALUES,
HidePossibleValuesInHelp
=> Flags::NO_POS_VALUES,
HelpExpected
=> Flags::HELP_REQUIRED,
Hidden
=> Flags::HIDDEN,
#[cfg(feature = "unstable-multicall")]
Multicall
=> Flags::MULTICALL,
NoAutoHelp
=> Flags::NO_AUTO_HELP,
NoAutoVersion
=> Flags::NO_AUTO_VERSION,
NoBinaryName
=> Flags::NO_BIN_NAME,
SubcommandsNegateReqs
=> Flags::SC_NEGATE_REQS,
SubcommandRequired
=> Flags::SC_REQUIRED,
SubcommandRequiredElseHelp
=> Flags::SC_REQUIRED_ELSE_HELP,
UseLongFormatForHelpSubcommand
=> Flags::USE_LONG_FORMAT_FOR_HELP_SC,
TrailingVarArg
=> Flags::TRAILING_VARARG,
UnifiedHelp => Flags::NO_OP,
NextLineHelp
=> Flags::NEXT_LINE_HELP,
IgnoreErrors
=> Flags::IGNORE_ERRORS,
WaitOnError
=> Flags::WAIT_ON_ERROR,
Built
=> Flags::BUILT,
BinNameBuilt
=> Flags::BIN_NAME_BUILT,
InferSubcommands
=> Flags::INFER_SUBCOMMANDS,
AllArgsOverrideSelf
=> Flags::ARGS_OVERRIDE_SELF,
InferLongArgs
=> Flags::INFER_LONG_ARGS
}
/// Deprecated in [Issue #3087](https://github.com/clap-rs/clap/issues/3087), maybe [`clap::Parser`][crate::Parser] would fit your use case?
#[cfg(feature = "yaml")]
impl FromStr for AppSettings {
type Err = String;
fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
#[allow(deprecated)]
#[allow(unreachable_patterns)]
match &*s.to_ascii_lowercase() {
"argrequiredelsehelp" => Ok(AppSettings::ArgRequiredElseHelp),
"subcommandprecedenceoverarg" => Ok(AppSettings::SubcommandPrecedenceOverArg),
"argsnegatesubcommands" => Ok(AppSettings::ArgsNegateSubcommands),
"allowexternalsubcommands" => Ok(AppSettings::AllowExternalSubcommands),
"strictutf8" => Ok(AppSettings::StrictUtf8),
"allowinvalidutf8forexternalsubcommands" => {
Ok(AppSettings::AllowInvalidUtf8ForExternalSubcommands)
}
"allowhyphenvalues" => Ok(AppSettings::AllowHyphenValues),
"allowleadinghyphen" => Ok(AppSettings::AllowLeadingHyphen),
"allownegativenumbers" => Ok(AppSettings::AllowNegativeNumbers),
"allowmissingpositional" => Ok(AppSettings::AllowMissingPositional),
"unifiedhelpmessage" => Ok(AppSettings::UnifiedHelpMessage),
"coloredhelp" => Ok(AppSettings::ColoredHelp),
"coloralways" => Ok(AppSettings::ColorAlways),
"colorauto" => Ok(AppSettings::ColorAuto),
"colornever" => Ok(AppSettings::ColorNever),
"dontdelimittrailingvalues" => Ok(AppSettings::DontDelimitTrailingValues),
"dontcollapseargsinusage" => Ok(AppSettings::DontCollapseArgsInUsage),
"derivedisplayorder" => Ok(AppSettings::DeriveDisplayOrder),
"disablecoloredhelp" => Ok(AppSettings::DisableColoredHelp),
"disablehelpsubcommand" => Ok(AppSettings::DisableHelpSubcommand),
"disablehelpflag" => Ok(AppSettings::DisableHelpFlag),
"disablehelpflags" => Ok(AppSettings::DisableHelpFlags),
"disableversionflag" => Ok(AppSettings::DisableVersionFlag),
"disableversion" => Ok(AppSettings::DisableVersion),
"propagateversion" => Ok(AppSettings::PropagateVersion),
"propagateversion" => Ok(AppSettings::GlobalVersion),
"hidepossiblevalues" => Ok(AppSettings::HidePossibleValues),
"hidepossiblevaluesinhelp" => Ok(AppSettings::HidePossibleValuesInHelp),
"helpexpected" => Ok(AppSettings::HelpExpected),
"hidden" => Ok(AppSettings::Hidden),
"noautohelp" => Ok(AppSettings::NoAutoHelp),
"noautoversion" => Ok(AppSettings::NoAutoVersion),
"nobinaryname" => Ok(AppSettings::NoBinaryName),
"subcommandsnegatereqs" => Ok(AppSettings::SubcommandsNegateReqs),
"subcommandrequired" => Ok(AppSettings::SubcommandRequired),
"subcommandrequiredelsehelp" => Ok(AppSettings::SubcommandRequiredElseHelp),
"uselongformatforhelpsubcommand" => Ok(AppSettings::UseLongFormatForHelpSubcommand),
"trailingvararg" => Ok(AppSettings::TrailingVarArg),
"unifiedhelp" => Ok(AppSettings::UnifiedHelp),
"nextlinehelp" => Ok(AppSettings::NextLineHelp),
"ignoreerrors" => Ok(AppSettings::IgnoreErrors),
"waitonerror" => Ok(AppSettings::WaitOnError),
"built" => Ok(AppSettings::Built),
"binnamebuilt" => Ok(AppSettings::BinNameBuilt),
"infersubcommands" => Ok(AppSettings::InferSubcommands),
"allargsoverrideself" => Ok(AppSettings::AllArgsOverrideSelf),
"inferlongargs" => Ok(AppSettings::InferLongArgs),
_ => Err(format!("unknown AppSetting: `{}`", s)),
}
}
}
#[cfg(test)]
mod test {
#[allow(clippy::cognitive_complexity)]
#[test]
#[cfg(feature = "yaml")]
fn app_settings_fromstr() {
use super::AppSettings;
assert_eq!(
"disablehelpflag".parse::<AppSettings>().unwrap(),
AppSettings::DisableHelpFlag
);
assert_eq!(
"argsnegatesubcommands".parse::<AppSettings>().unwrap(),
AppSettings::ArgsNegateSubcommands
);
assert_eq!(
"argrequiredelsehelp".parse::<AppSettings>().unwrap(),
AppSettings::ArgRequiredElseHelp
);
assert_eq!(
"subcommandprecedenceoverarg"
.parse::<AppSettings>()
.unwrap(),
AppSettings::SubcommandPrecedenceOverArg
);
assert_eq!(
"allowexternalsubcommands".parse::<AppSettings>().unwrap(),
AppSettings::AllowExternalSubcommands
);
assert_eq!(
"allowinvalidutf8forexternalsubcommands"
.parse::<AppSettings>()
.unwrap(),
AppSettings::AllowInvalidUtf8ForExternalSubcommands
);
assert_eq!(
"allowhyphenvalues".parse::<AppSettings>().unwrap(),
AppSettings::AllowHyphenValues
);
assert_eq!(
"allownegativenumbers".parse::<AppSettings>().unwrap(),
AppSettings::AllowNegativeNumbers
);
assert_eq!(
"disablehelpsubcommand".parse::<AppSettings>().unwrap(),
AppSettings::DisableHelpSubcommand
);
assert_eq!(
"disableversionflag".parse::<AppSettings>().unwrap(),
AppSettings::DisableVersionFlag
);
assert_eq!(
"dontcollapseargsinusage".parse::<AppSettings>().unwrap(),
AppSettings::DontCollapseArgsInUsage
);
assert_eq!(
"dontdelimittrailingvalues".parse::<AppSettings>().unwrap(),
AppSettings::DontDelimitTrailingValues
);
assert_eq!(
"derivedisplayorder".parse::<AppSettings>().unwrap(),
AppSettings::DeriveDisplayOrder
);
assert_eq!(
"disablecoloredhelp".parse::<AppSettings>().unwrap(),
AppSettings::DisableColoredHelp
);
assert_eq!(
"propagateversion".parse::<AppSettings>().unwrap(),
AppSettings::PropagateVersion
);
assert_eq!(
"hidden".parse::<AppSettings>().unwrap(),
AppSettings::Hidden
);
assert_eq!(
"hidepossiblevalues".parse::<AppSettings>().unwrap(),
AppSettings::HidePossibleValues
);
assert_eq!(
"helpexpected".parse::<AppSettings>().unwrap(),
AppSettings::HelpExpected
);
assert_eq!(
"nobinaryname".parse::<AppSettings>().unwrap(),
AppSettings::NoBinaryName
);
assert_eq!(
"nextlinehelp".parse::<AppSettings>().unwrap(),
AppSettings::NextLineHelp
);
assert_eq!(
"subcommandsnegatereqs".parse::<AppSettings>().unwrap(),
AppSettings::SubcommandsNegateReqs
);
assert_eq!(
"subcommandrequired".parse::<AppSettings>().unwrap(),
AppSettings::SubcommandRequired
);
assert_eq!(
"subcommandrequiredelsehelp".parse::<AppSettings>().unwrap(),
AppSettings::SubcommandRequiredElseHelp
);
assert_eq!(
"uselongformatforhelpsubcommand"
.parse::<AppSettings>()
.unwrap(),
AppSettings::UseLongFormatForHelpSubcommand
);
assert_eq!(
"trailingvararg".parse::<AppSettings>().unwrap(),
AppSettings::TrailingVarArg
);
assert_eq!(
"waitonerror".parse::<AppSettings>().unwrap(),
AppSettings::WaitOnError
);
assert_eq!("built".parse::<AppSettings>().unwrap(), AppSettings::Built);
assert_eq!(
"binnamebuilt".parse::<AppSettings>().unwrap(),
AppSettings::BinNameBuilt
);
assert_eq!(
"infersubcommands".parse::<AppSettings>().unwrap(),
AppSettings::InferSubcommands
);
assert!("hahahaha".parse::<AppSettings>().is_err());
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,80 +0,0 @@
use crate::{Arg, ArgSettings, ValueHint};
pub(crate) fn assert_arg(arg: &Arg) {
debug!("Arg::_debug_asserts:{}", arg.name);
// Self conflict
// TODO: this check should be recursive
assert!(
!arg.blacklist.iter().any(|x| *x == arg.id),
"Argument '{}' cannot conflict with itself",
arg.name,
);
if arg.value_hint != ValueHint::Unknown {
assert!(
arg.is_set(ArgSettings::TakesValue),
"Argument '{}' has value hint but takes no value",
arg.name
);
if arg.value_hint == ValueHint::CommandWithArguments {
assert!(
arg.is_set(ArgSettings::MultipleValues),
"Argument '{}' uses hint CommandWithArguments and must accept multiple values",
arg.name
)
}
}
if arg.index.is_some() {
assert!(
arg.is_positional(),
"Argument '{}' is a positional argument and can't have short or long name versions",
arg.name
);
}
if arg.is_set(ArgSettings::Required) {
assert!(
arg.default_vals.is_empty(),
"Argument '{}' is required and can't have a default value",
arg.name
);
}
assert_arg_flags(arg);
}
fn assert_arg_flags(arg: &Arg) {
use ArgSettings::*;
macro_rules! checker {
($a:ident requires $($b:ident)|+) => {
if arg.is_set($a) {
let mut s = String::new();
$(
if !arg.is_set($b) {
s.push_str(&format!(" ArgSettings::{} is required when ArgSettings::{} is set.\n", std::stringify!($b), std::stringify!($a)));
}
)+
if !s.is_empty() {
panic!("Argument {:?}\n{}", arg.get_name(), s)
}
}
}
}
checker!(ForbidEmptyValues requires TakesValue);
checker!(RequireDelimiter requires TakesValue | UseValueDelimiter);
checker!(HidePossibleValues requires TakesValue);
checker!(AllowHyphenValues requires TakesValue);
checker!(RequireEquals requires TakesValue);
checker!(Last requires TakesValue);
checker!(HideDefaultValue requires TakesValue);
checker!(MultipleValues requires TakesValue);
checker!(IgnoreCase requires TakesValue);
checker!(AllowInvalidUtf8 requires TakesValue);
}

Просмотреть файл

@ -1,8 +0,0 @@
use crate::Arg;
// 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"))
}

103
third_party/rust/clap/src/build/arg_group.rs поставляемый
Просмотреть файл

@ -16,7 +16,7 @@ use yaml_rust::Yaml;
///
/// You can also do things such as name an entire `ArgGroup` as a [conflict] or [requirement] for
/// another argument, meaning any of the arguments that belong to that group will cause a failure
/// if present, or must present respectively.
/// if present, or must be present respectively.
///
/// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
/// present out of a given set. Imagine that you had multiple arguments, and you want one of them
@ -37,8 +37,8 @@ use yaml_rust::Yaml;
/// the arguments from the specified group is present at runtime.
///
/// ```rust
/// # use clap::{App, arg, ArgGroup, ErrorKind};
/// let result = App::new("app")
/// # use clap::{Command, arg, ArgGroup, ErrorKind};
/// let result = Command::new("cmd")
/// .arg(arg!(--"set-ver" <ver> "set the version manually").required(false))
/// .arg(arg!(--major "auto increase major"))
/// .arg(arg!(--minor "auto increase minor"))
@ -46,17 +46,17 @@ use yaml_rust::Yaml;
/// .group(ArgGroup::new("vers")
/// .args(&["set-ver", "major", "minor", "patch"])
/// .required(true))
/// .try_get_matches_from(vec!["app", "--major", "--patch"]);
/// .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);
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
/// ```
/// This next example shows a passing parse of the same scenario
///
/// ```rust
/// # use clap::{App, arg, ArgGroup};
/// let result = App::new("app")
/// # use clap::{Command, arg, ArgGroup};
/// let result = Command::new("cmd")
/// .arg(arg!(--"set-ver" <ver> "set the version manually").required(false))
/// .arg(arg!(--major "auto increase major"))
/// .arg(arg!(--minor "auto increase minor"))
@ -64,7 +64,7 @@ use yaml_rust::Yaml;
/// .group(ArgGroup::new("vers")
/// .args(&["set-ver", "major", "minor","patch"])
/// .required(true))
/// .try_get_matches_from(vec!["app", "--major"]);
/// .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...
@ -104,12 +104,12 @@ impl<'help> ArgGroup<'help> {
/// # Examples
///
/// ```rust
/// # use clap::{App, ArgGroup};
/// # use clap::{Command, ArgGroup};
/// ArgGroup::new("config")
/// # ;
/// ```
pub fn new<S: Into<&'help str>>(n: S) -> Self {
ArgGroup::default().name(n)
ArgGroup::default().id(n)
}
/// Sets the group name.
@ -117,24 +117,30 @@ impl<'help> ArgGroup<'help> {
/// # Examples
///
/// ```rust
/// # use clap::{App, ArgGroup};
/// # use clap::{Command, ArgGroup};
/// ArgGroup::default().name("config")
/// # ;
/// ```
#[must_use]
pub fn name<S: Into<&'help str>>(mut self, n: S) -> Self {
pub fn id<S: Into<&'help str>>(mut self, n: S) -> Self {
self.name = n.into();
self.id = Id::from(&self.name);
self.id = Id::from(self.name);
self
}
/// Deprecated, replaced with [`ArgGroup::id`]
#[deprecated(since = "3.1.0", note = "Replaced with `ArgGroup::id`")]
pub fn name<S: Into<&'help str>>(self, n: S) -> Self {
self.id(n)
}
/// Adds an [argument] to this group by name
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, ArgGroup};
/// let m = App::new("myprog")
/// # use clap::{Command, Arg, ArgGroup};
/// let m = Command::new("myprog")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("color")
@ -160,8 +166,8 @@ impl<'help> ArgGroup<'help> {
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, ArgGroup};
/// let m = App::new("myprog")
/// # use clap::{Command, Arg, ArgGroup};
/// let m = Command::new("myprog")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("color")
@ -191,8 +197,8 @@ impl<'help> ArgGroup<'help> {
/// group
///
/// ```rust
/// # use clap::{App, Arg, ArgGroup};
/// let m = App::new("myprog")
/// # use clap::{Command, Arg, ArgGroup};
/// let m = Command::new("myprog")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("color")
@ -208,8 +214,8 @@ impl<'help> ArgGroup<'help> {
/// an error if more than one of the args in the group was used.
///
/// ```rust
/// # use clap::{App, Arg, ArgGroup, ErrorKind};
/// let result = App::new("myprog")
/// # use clap::{Command, Arg, ArgGroup, ErrorKind};
/// let result = Command::new("myprog")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("color")
@ -220,7 +226,7 @@ impl<'help> ArgGroup<'help> {
/// // 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);
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
/// ```
///
/// [`Arg`]: crate::Arg
@ -236,7 +242,7 @@ impl<'help> ArgGroup<'help> {
/// 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>`.
///
/// **NOTE:** This setting only applies to the current [`App`] / [`Subcommand`]s, and not
/// **NOTE:** This setting only applies to the current [`Command`] / [`Subcommand`]s, and not
/// globally.
///
/// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with
@ -244,14 +250,11 @@ impl<'help> ArgGroup<'help> {
/// 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."
///
/// **NOTE:** An argument is considered present when there is a
/// [`Arg::default_value`](crate::Arg::default_value)
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, ArgGroup, ErrorKind};
/// let result = App::new("myprog")
/// # use clap::{Command, Arg, ArgGroup, ErrorKind};
/// let result = Command::new("myprog")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("color")
@ -263,12 +266,12 @@ impl<'help> ArgGroup<'help> {
/// // 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);
/// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
/// ```
///
/// [`Subcommand`]: crate::Subcommand
/// [`ArgGroup::multiple`]: ArgGroup::multiple()
/// [`App`]: crate::App
/// [`Command`]: crate::Command
#[inline]
#[must_use]
pub fn required(mut self, yes: bool) -> Self {
@ -282,16 +285,13 @@ impl<'help> ArgGroup<'help> {
/// [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.
///
/// **NOTE:** An argument is considered present when there is a
/// [`Arg::default_value`](crate::Arg::default_value)
///
/// **NOTE:** The name provided may be an argument or group name
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, ArgGroup, ErrorKind};
/// let result = App::new("myprog")
/// # use clap::{Command, Arg, ArgGroup, ErrorKind};
/// let result = Command::new("myprog")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("color")
@ -306,7 +306,7 @@ impl<'help> ArgGroup<'help> {
/// // error
/// assert!(result.is_err());
/// let err = result.unwrap_err();
/// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
/// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
/// ```
/// [required group]: ArgGroup::required()
/// [argument requirement rules]: crate::Arg::requires()
@ -324,14 +324,11 @@ impl<'help> ArgGroup<'help> {
///
/// **NOTE:** The names provided may be an argument or group name
///
/// **NOTE:** An argument is considered present when there is a
/// [`Arg::default_value`](crate::Arg::default_value)
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, ArgGroup, ErrorKind};
/// let result = App::new("myprog")
/// # use clap::{Command, Arg, ArgGroup, ErrorKind};
/// let result = Command::new("myprog")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("color")
@ -348,7 +345,7 @@ impl<'help> ArgGroup<'help> {
/// // yet we only used "-d" it's an error
/// assert!(result.is_err());
/// let err = result.unwrap_err();
/// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
/// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
/// ```
/// [required group]: ArgGroup::required()
/// [argument requirement rules]: crate::Arg::requires_all()
@ -368,14 +365,11 @@ impl<'help> ArgGroup<'help> {
///
/// **NOTE:** The name provided may be an argument, or group name
///
/// **NOTE:** An argument is considered present when there is a
/// [`Arg::default_value`](crate::Arg::default_value)
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, ArgGroup, ErrorKind};
/// let result = App::new("myprog")
/// # use clap::{Command, Arg, ArgGroup, ErrorKind};
/// let result = Command::new("myprog")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("color")
@ -389,7 +383,7 @@ impl<'help> ArgGroup<'help> {
/// // 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);
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
/// ```
/// [argument exclusion rules]: crate::Arg::conflicts_with()
#[must_use]
@ -405,14 +399,11 @@ impl<'help> ArgGroup<'help> {
///
/// **NOTE:** The names provided may be an argument, or group name
///
/// **NOTE:** An argument is considered present when there is a
/// [`Arg::default_value`](crate::Arg::default_value)
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, ArgGroup, ErrorKind};
/// let result = App::new("myprog")
/// # use clap::{Command, Arg, ArgGroup, ErrorKind};
/// let result = Command::new("myprog")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("color")
@ -429,7 +420,7 @@ impl<'help> ArgGroup<'help> {
/// // it's an error
/// assert!(result.is_err());
/// let err = result.unwrap_err();
/// assert_eq!(err.kind, ErrorKind::ArgumentConflict);
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
/// ```
///
/// [argument exclusion rules]: crate::Arg::conflicts_with_all()
@ -443,6 +434,7 @@ impl<'help> ArgGroup<'help> {
/// Deprecated, replaced with [`ArgGroup::new`]
#[deprecated(since = "3.0.0", note = "Replaced with `ArgGroup::new`")]
#[doc(hidden)]
pub fn with_name<S: Into<&'help str>>(n: S) -> Self {
Self::new(n)
}
@ -453,6 +445,7 @@ impl<'help> ArgGroup<'help> {
since = "3.0.0",
note = "Maybe clap::Parser would fit your use case? (Issue #3087)"
)]
#[doc(hidden)]
pub fn from_yaml(yaml: &'help Yaml) -> Self {
Self::from(yaml)
}
@ -510,7 +503,7 @@ impl<'help> From<&'help Yaml> for ArgGroup<'help> {
"conflicts_with" => yaml_vec_or_str!(a, v, conflicts_with),
"name" => {
if let Some(ys) = v.as_str() {
a = a.name(ys);
a = a.id(ys);
}
a
}

14
third_party/rust/clap/src/build/arg_predicate.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum ArgPredicate<'help> {
IsPresent,
Equals(&'help std::ffi::OsStr),
}
impl<'help> From<Option<&'help std::ffi::OsStr>> for ArgPredicate<'help> {
fn from(other: Option<&'help std::ffi::OsStr>) -> Self {
match other {
Some(other) => Self::Equals(other),
None => Self::IsPresent,
}
}
}

Просмотреть файл

@ -1,3 +1,5 @@
#![allow(deprecated)]
// Std
use std::ops::BitOr;
#[cfg(feature = "yaml")]
@ -6,6 +8,9 @@ use std::str::FromStr;
// Third party
use bitflags::bitflags;
#[allow(unused)]
use crate::Arg;
#[doc(hidden)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ArgFlags(Flags);
@ -27,11 +32,24 @@ impl Default for ArgFlags {
#[derive(Debug, PartialEq, Copy, Clone)]
#[non_exhaustive]
pub enum ArgSettings {
/// Specifies that an arg must be used
/// Deprecated, replaced with [`Arg::required`] and [`Arg::is_required_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::required` and `Arg::is_required_set`"
)]
Required,
/// Allows an arg to accept multiple values
/// Deprecated, replaced with [`Arg::multiple_values`] and [`Arg::is_multiple_values_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::multiple_values` and `Arg::`is_multiple_values_set`"
)]
MultipleValues,
/// Allows an arg to appear multiple times
/// Deprecated, replaced with [`Arg::multiple_occurrences`] and
/// [`Arg::is_multiple_occurrences_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::multiple_occurrences` and `Arg::is_multiple_occurrences_set`"
)]
MultipleOccurrences,
/// Deprecated, see [`ArgSettings::MultipleOccurrences`] (most likely what you want) and
/// [`ArgSettings::MultipleValues`]
@ -39,59 +57,139 @@ pub enum ArgSettings {
since = "3.0.0",
note = "Split into `ArgSettings::MultipleOccurrences` (most likely what you want) and `ArgSettings::MultipleValues`"
)]
#[doc(hidden)]
Multiple,
/// Forbids an arg from accepting empty values such as `""`
/// Deprecated, replaced with [`Arg::forbid_empty_values`] and
/// [`Arg::is_forbid_empty_values_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::forbid_empty_values` and `Arg::is_forbid_empty_values_set`"
)]
ForbidEmptyValues,
/// Sets an arg to be global (i.e. exist in all subcommands)
/// Deprecated, replaced with [`Arg::global`] and [`Arg::is_global_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::global` and `Arg::is_global_set`"
)]
Global,
/// Hides an arg from the help message
/// Deprecated, replaced with [`Arg::hide`] and [`Arg::is_hide_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::hide` and `Arg::is_hide_set`"
)]
Hidden,
/// Allows an argument to take a value (such as `--option value`)
/// Deprecated, replaced with [`Arg::takes_value`] and [`Arg::is_takes_value_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::takes_value` and `Arg::is_takes_value_set`"
)]
TakesValue,
/// Enables a delimiter to break up arguments `--option val1,val2,val3` becomes three values
/// (`val1`, `val2`, and `val3`) instead of the default one (`val1,val2,val3`)
/// Deprecated, replaced with [`Arg::use_value_delimiter`] and
/// [`Arg::is_use_value_delimiter_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::use_value_delimiter` and `Arg::is_use_value_delimiter_set`"
)]
UseValueDelimiter,
/// Tells an arg to display it's help on the line below the arg itself in the help message
/// Deprecated, replaced with [`Arg::next_line_help`] and [`Arg::is_next_line_help_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::next_line_help` and `Arg::is_next_line_help_set`"
)]
NextLineHelp,
/// Says that arg *must* use a delimiter to separate values
/// Deprecated, replaced with [`Arg::require_value_delimiter`] and
/// [`Arg::is_require_value_delimiter_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::require_value_delimiter` and `Arg::is_require_value_delimiter_set`"
)]
RequireDelimiter,
/// Hides the possible values from the help message
/// Deprecated, replaced with [`Arg::hide_possible_values`] and
/// [`Arg::is_hide_possible_values_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::hide_possible_values` and `Arg::is_hide_possible_values_set`"
)]
HidePossibleValues,
/// Allows values that start with a hyphen
/// Deprecated, replaced with [`Arg::allow_hyphen_values`] and
/// [`Arg::is_allow_hyphen_values_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::allow_hyphen_values` and `Arg::is_allow_hyphen_values_set`"
)]
AllowHyphenValues,
/// Deprecated, replaced with [`ArgSettings::AllowHyphenValues`]
#[deprecated(
since = "3.0.0",
note = "Replaced with `ArgSettings::AllowHyphenValues`"
)]
#[doc(hidden)]
AllowLeadingHyphen,
/// Requires that an equals be used to provide a value to an option such as `--option=value`
/// Deprecated, replaced with [`Arg::require_equals`] and [`Arg::is_require_equals_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::require_equals` and `Arg::is_require_equals_set`"
)]
RequireEquals,
/// Says that a positional arg will be the last positional, and requires `--` to be accessed.
/// It can also be accessed early (i.e. before other positionals) by providing `--`
/// Deprecated, replaced with [`Arg::last`] and [`Arg::is_last_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::last` and `Arg::is_last_set`"
)]
Last,
/// Hides the default value from the help message
/// Deprecated, replaced with [`Arg::hide_default_value`] and [`Arg::is_hide_default_value_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::hide_default_value` and `Arg::is_hide_default_value_set`"
)]
HideDefaultValue,
/// Possible values become case insensitive
/// Deprecated, replaced with [`Arg::ignore_case`] and [`Arg::is_ignore_case_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::ignore_case` and `Arg::is_ignore_case_set`"
)]
IgnoreCase,
/// Deprecated, replaced with [`ArgSettings::IgnoreCase`]
#[deprecated(since = "3.0.0", note = "Replaced with `ArgSettings::IgnoreCase`")]
#[doc(hidden)]
CaseInsensitive,
/// Hides environment variable arguments from the help message
/// Deprecated, replaced with [`Arg::hide_env`] and [`Arg::is_hide_env_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::hide_env` and `Arg::is_hide_env_set`"
)]
#[cfg(feature = "env")]
HideEnv,
/// Hides any values currently assigned to ENV variables in the help message (good for sensitive
/// information)
/// Deprecated, replaced with [`Arg::hide_env_values`] and [`Arg::is_hide_env_values_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::hide_env_values` and `Arg::is_hide_env_values_set`"
)]
#[cfg(feature = "env")]
HideEnvValues,
/// The argument should **not** be shown in short help text
/// Deprecated, replaced with [`Arg::hide_short_help`] and [`Arg::is_hide_short_help_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::hide_short_help` and `Arg::is_hide_short_help_set`"
)]
HiddenShortHelp,
/// The argument should **not** be shown in long help text
/// Deprecated, replaced with [`Arg::hide_long_help`] and [`Arg::is_hide_long_help_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::hide_long_help` and `Arg::is_hide_long_help_set`"
)]
HiddenLongHelp,
/// Specifies that option values that are invalid UTF-8 should *not* be treated as an error.
/// Deprecated, replaced with [`Arg::allow_invalid_utf8`] and [`Arg::is_allow_invalid_utf8_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::allow_invalid_utf8` and `Arg::is_allow_invalid_utf8_set`"
)]
AllowInvalidUtf8,
/// Specifies that option should exist on its own.
/// Having any other arguments present at runtime is an error.
/// Deprecated, replaced with [`Arg::exclusive`] and [`Arg::is_exclusive_set`]
#[deprecated(
since = "3.1.0",
note = "Replaced with `Arg::exclusive` and `Arg::is_exclusive_set`"
)]
Exclusive,
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

815
third_party/rust/clap/src/build/debug_asserts.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,815 @@
use std::cmp::Ordering;
use clap_lex::RawOsStr;
use crate::build::arg::ArgProvider;
use crate::mkeymap::KeyType;
use crate::util::Id;
use crate::{AppSettings, 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 has_mutated_version = cmd
.get_arguments()
.any(|x| x.id == Id::version_hash() && x.provider == ArgProvider::GeneratedMutated);
if has_mutated_version {
assert!(cmd.is_set(AppSettings::NoAutoVersion),
"Command {}: Used Command::mut_arg(\"version\", ..) without providing Command::version, Command::long_version or using AppSettings::NoAutoVersion"
,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() {
#[cfg(feature = "unstable-v4")]
{
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);
#[cfg(feature = "unstable-multicall")]
{
assert!(
!cmd.is_multicall_set(),
"Command {}: Arguments like {} cannot be set on a multicall command",
cmd.get_name(),
arg.name
);
}
if let Some(s) = arg.short.as_ref() {
short_flags.push(Flag::Arg(format!("-{}", s), &*arg.name));
}
for (short_alias, _) in &arg.short_aliases {
short_flags.push(Flag::Arg(format!("-{}", short_alias), arg.name));
}
if let Some(l) = arg.long.as_ref() {
#[cfg(feature = "unstable-v4")]
{
assert!(!l.starts_with('-'), "Argument {}: long {:?} must not start with a `-`, that will be handled by the parser", arg.name, l);
}
long_flags.push(Flag::Arg(format!("--{}", l), &*arg.name));
}
for (long_alias, _) in &arg.aliases {
long_flags.push(Flag::Arg(format!("--{}", long_alias), arg.name));
}
// Name conflicts
assert!(
cmd.two_args_of(|x| x.id == arg.id).is_none(),
"Command {}: Argument names must be unique, but '{}' is in use by more than one argument or group",
cmd.get_name(),
arg.name,
);
// Long conflicts
if let Some(l) = arg.long {
if let Some((first, second)) = cmd.two_args_of(|x| x.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.name,
second.name
)
}
}
// Short conflicts
if let Some(s) = arg.short {
if let Some((first, second)) = cmd.two_args_of(|x| x.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.name,
second.name
)
}
}
// Index conflicts
if let Some(idx) = arg.index {
if let Some((first, second)) =
cmd.two_args_of(|x| x.is_positional() && x.index == Some(idx))
{
panic!(
"Command {}: Argument '{}' has the same index as '{}' \
and they are both positional arguments\n\n\t \
Use Arg::multiple_values(true) to allow one \
positional argument to take multiple values",
cmd.get_name(),
first.name,
second.name
)
}
}
// requires, r_if, r_unless
for req in &arg.requires {
assert!(
cmd.id_exists(&req.1),
"Command {}: Argument or group '{:?}' specified in 'requires*' for '{}' does not exist",
cmd.get_name(),
req.1,
arg.name,
);
}
for req in &arg.r_ifs {
#[cfg(feature = "unstable-v4")]
{
assert!(
!arg.is_required_set(),
"Argument {}: `required` conflicts with `required_if_eq*`",
arg.name
);
}
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.name
);
}
for req in &arg.r_ifs_all {
#[cfg(feature = "unstable-v4")]
{
assert!(
!arg.is_required_set(),
"Argument {}: `required` conflicts with `required_if_eq_all`",
arg.name
);
}
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.name
);
}
for req in &arg.r_unless {
#[cfg(feature = "unstable-v4")]
{
assert!(
!arg.is_required_set(),
"Argument {}: `required` conflicts with `required_unless*`",
arg.name
);
}
assert!(
cmd.id_exists(req),
"Command {}: Argument or group '{:?}' specified in 'required_unless*' for '{}' does not exist",
cmd.get_name(),
req,
arg.name,
);
}
for req in &arg.r_unless_all {
#[cfg(feature = "unstable-v4")]
{
assert!(
!arg.is_required_set(),
"Argument {}: `required` conflicts with `required_unless*`",
arg.name
);
}
assert!(
cmd.id_exists(req),
"Command {}: Argument or group '{:?}' specified in 'required_unless*' for '{}' does not exist",
cmd.get_name(),
req,
arg.name,
);
}
// blacklist
for req in &arg.blacklist {
assert!(
cmd.id_exists(req),
"Command {}: Argument or group '{:?}' specified in 'conflicts_with*' for '{}' does not exist",
cmd.get_name(),
req,
arg.name,
);
}
if arg.is_last_set() {
assert!(
arg.long.is_none(),
"Command {}: Flags or Options cannot have last(true) set. '{}' has both a long and last(true) set.",
cmd.get_name(),
arg.name
);
assert!(
arg.short.is_none(),
"Command {}: Flags or Options cannot have last(true) set. '{}' has both a short and last(true) set.",
cmd.get_name(),
arg.name
);
}
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.name
);
// validators
assert!(
arg.validator.is_none() || arg.validator_os.is_none(),
"Command {}: Argument '{}' has both `validator` and `validator_os` set which is not allowed",
cmd.get_name(),
arg.name
);
if arg.value_hint == ValueHint::CommandWithArguments {
assert!(
arg.is_positional(),
"Command {}: Argument '{}' has hint CommandWithArguments and must be positional.",
cmd.get_name(),
arg.name
);
assert!(
cmd.is_trailing_var_arg_set(),
"Command {}: Positional argument '{}' has hint CommandWithArguments, so Command must have TrailingVarArg set.",
cmd.get_name(),
arg.name
);
}
}
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.name,
);
// Groups should not have naming conflicts with Args
assert!(
!cmd.get_arguments().any(|x| x.id == group.id),
"Command {}: Argument group name '{}' must not conflict with argument name",
cmd.get_name(),
group.name,
);
for arg in &group.args {
// Args listed inside groups should exist
assert!(
cmd.get_arguments().any(|x| x.id == *arg),
"Command {}: Argument group '{}' contains non-existent argument '{:?}'",
cmd.get_name(),
group.name,
arg
);
}
// Required groups should have at least one arg without default values
if group.required && !group.args.is_empty() {
assert!(
group.args.iter().any(|arg| {
cmd.get_arguments()
.any(|x| x.id == *arg && x.default_vals.is_empty())
}),
"Command {}: Argument group '{}' is required but all of it's arguments have a default value.",
cmd.get_name(),
group.name
)
}
}
// 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");
_verify_positionals(cmd);
if let Some(help_template) = cmd.get_help_template() {
assert!(
!help_template.contains("{flags}"),
"Command {}: {}",
cmd.get_name(),
"`{flags}` template variable was removed in clap3, they are now included in `{options}`",
);
assert!(
!help_template.contains("{unified}"),
"Command {}: {}",
cmd.get_name(),
"`{unified}` template variable was removed in clap3, use `{options}` instead"
);
}
cmd._panic_on_missing_help(cmd.is_help_expected_set());
assert_app_flags(cmd);
}
#[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> {
use Flag::*;
match (self, other) {
(Command(s1, _), Command(s2, _))
| (Arg(s1, _), Arg(s2, _))
| (Command(s1, _), Arg(s2, _))
| (Arg(s1, _), Command(s2, _)) => {
if s1 == s2 {
Some(Ordering::Equal)
} else {
s1.partial_cmp(s2)
}
}
}
}
}
impl Ord for Flag<'_> {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
fn detect_duplicate_flags(flags: &[Flag], short_or_long: &str) {
use Flag::*;
for (one, two) in find_duplicates(flags) {
match (one, two) {
(Command(flag, one), Command(_, another)) if one != another => panic!(
"the '{}' {} flag is specified for both '{}' and '{}' subcommands",
flag, short_or_long, one, another
),
(Arg(flag, one), Arg(_, another)) if one != another => panic!(
"{} option names must be unique, but '{}' is in use by both '{}' and '{}'",
short_or_long, flag, one, another
),
(Arg(flag, arg), Command(_, sub)) | (Command(flag, sub), Arg(_, arg)) => panic!(
"the '{}' {} flag for the '{}' argument conflicts with the short flag \
for '{}' subcommand",
flag, short_or_long, arg, sub
),
_ => {}
}
}
}
/// 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 requires $($b:ident)|+) => {
if cmd.$a() {
let mut s = String::new();
$(
if !cmd.$b() {
s.push_str(&format!(" AppSettings::{} is required when AppSettings::{} is set.\n", std::stringify!($b), std::stringify!($a)));
}
)+
if !s.is_empty() {
panic!("{}", s)
}
}
};
($a:ident conflicts $($b:ident)|+) => {
if cmd.$a() {
let mut s = String::new();
$(
if cmd.$b() {
s.push_str(&format!(" AppSettings::{} conflicts with AppSettings::{}.\n", std::stringify!($b), std::stringify!($a)));
}
)+
if !s.is_empty() {
panic!("{}\n{}", cmd.get_name(), s)
}
}
};
}
checker!(is_allow_invalid_utf8_for_external_subcommands_set requires is_allow_external_subcommands_set);
#[cfg(feature = "unstable-multicall")]
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 {} but there \
are only {} positional arguments defined",
highest_idx,
num_p
);
// Next we verify that only the highest index has takes multiple arguments (if any)
let only_highest = |a: &Arg| a.is_multiple() && (a.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,
"When using a positional argument with .multiple_values(true) that is *not the \
last* positional argument, the last positional argument (i.e. the one \
with the highest index) *must* have .required(true) or .last(true) set."
);
// 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 .multiple_values(true)"
);
// 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_occurrences_set()
|| (p.is_multiple_values_set() && p.num_vals.is_none())
})
.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 .multiple_values(true) 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.name,
p.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;
continue;
} 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.name,
p.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;
continue;
}
}
}
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.name);
// Self conflict
// TODO: this check should be recursive
assert!(
!arg.blacklist.iter().any(|x| *x == arg.id),
"Argument '{}' cannot conflict with itself",
arg.name,
);
if arg.value_hint != ValueHint::Unknown {
assert!(
arg.is_takes_value_set(),
"Argument '{}' has value hint but takes no value",
arg.name
);
if arg.value_hint == ValueHint::CommandWithArguments {
assert!(
arg.is_multiple_values_set(),
"Argument '{}' uses hint CommandWithArguments and must accept multiple values",
arg.name
)
}
}
if arg.index.is_some() {
assert!(
arg.is_positional(),
"Argument '{}' is a positional argument and can't have short or long name versions",
arg.name
);
}
if arg.is_required_set() {
assert!(
arg.default_vals.is_empty(),
"Argument '{}' is required and can't have a default value",
arg.name
);
}
#[cfg(feature = "unstable-v4")]
{
let num_vals = arg.get_num_vals().unwrap_or(usize::MAX);
let num_val_names = arg.get_value_names().unwrap_or(&[]).len();
if num_vals < num_val_names {
panic!(
"Argument {}: Too many value names ({}) compared to number_of_values ({})",
arg.name, num_val_names, num_vals
);
}
}
assert_arg_flags(arg);
assert_defaults(arg, "default_value", arg.default_vals.iter().copied());
assert_defaults(
arg,
"default_missing_value",
arg.default_missing_vals.iter().copied(),
);
assert_defaults(
arg,
"default_value_if",
arg.default_vals_ifs
.iter()
.filter_map(|(_, _, default)| *default),
);
}
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() {
s.push_str(&format!(" Arg::{} is required when Arg::{} is set.\n", std::stringify!($b), std::stringify!($a)));
}
)+
if !s.is_empty() {
panic!("Argument {:?}\n{}", arg.get_id(), s)
}
}
}
}
checker!(is_forbid_empty_values_set requires is_takes_value_set);
checker!(is_require_value_delimiter_set requires is_takes_value_set);
checker!(is_require_value_delimiter_set requires is_use_value_delimiter_set);
checker!(is_hide_possible_values_set requires is_takes_value_set);
checker!(is_allow_hyphen_values_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);
checker!(is_allow_invalid_utf8_set requires is_takes_value_set);
}
fn assert_defaults<'d>(
arg: &Arg,
field: &'static str,
defaults: impl IntoIterator<Item = &'d std::ffi::OsStr>,
) {
for default_os in defaults {
if let Some(default_s) = default_os.to_str() {
if !arg.possible_vals.is_empty() {
if let Some(delim) = arg.get_value_delimiter() {
for part in default_s.split(delim) {
assert!(
arg.possible_vals.iter().any(|possible_val| {
possible_val.matches(part, arg.is_ignore_case_set())
}),
"Argument `{}`'s {}={} doesn't match possible values",
arg.name,
field,
part
)
}
} else {
assert!(
arg.possible_vals.iter().any(|possible_val| {
possible_val.matches(default_s, arg.is_ignore_case_set())
}),
"Argument `{}`'s {}={} doesn't match possible values",
arg.name,
field,
default_s
);
}
}
if let Some(validator) = arg.validator.as_ref() {
let mut validator = validator.lock().unwrap();
if let Some(delim) = arg.get_value_delimiter() {
for part in default_s.split(delim) {
if let Err(err) = validator(part) {
panic!(
"Argument `{}`'s {}={} failed validation: {}",
arg.name, field, part, err
);
}
}
} else if let Err(err) = validator(default_s) {
panic!(
"Argument `{}`'s {}={} failed validation: {}",
arg.name, field, default_s, err
);
}
}
}
if let Some(validator) = arg.validator_os.as_ref() {
let mut validator = validator.lock().unwrap();
if let Some(delim) = arg.get_value_delimiter() {
let default_os = RawOsStr::new(default_os);
for part in default_os.split(delim) {
if let Err(err) = validator(&part.to_os_str()) {
panic!(
"Argument `{}`'s {}={:?} failed validation: {}",
arg.name, field, part, err
);
}
}
} else if let Err(err) = validator(default_os) {
panic!(
"Argument `{}`'s {}={:?} failed validation: {}",
arg.name, field, default_os, err
);
}
}
}
}

40
third_party/rust/clap/src/build/mod.rs поставляемый
Просмотреть файл

@ -1,14 +1,38 @@
#[macro_use]
mod macros;
pub mod app;
pub mod arg;
mod app_settings;
mod arg;
mod arg_group;
mod arg_predicate;
mod arg_settings;
mod command;
mod possible_value;
mod usage_parser;
mod value_hint;
pub use self::{
app::{App, AppFlags, AppSettings},
arg::{Arg, ArgFlags, ArgSettings, PossibleValue, ValueHint},
arg_group::ArgGroup,
};
#[cfg(feature = "regex")]
mod regex;
#[cfg(debug_assertions)]
mod debug_asserts;
#[cfg(test)]
mod tests;
pub use app_settings::{AppFlags, AppSettings};
pub use arg::Arg;
pub use arg_group::ArgGroup;
pub use arg_settings::{ArgFlags, ArgSettings};
pub use command::Command;
pub use possible_value::PossibleValue;
pub use value_hint::ValueHint;
#[allow(deprecated)]
pub use command::App;
#[cfg(feature = "regex")]
pub use self::regex::RegexRef;
pub(crate) use arg::display_arg_val;
pub(crate) use arg_predicate::ArgPredicate;

Просмотреть файл

@ -1,4 +1,4 @@
use std::iter;
use std::{borrow::Cow, iter};
use crate::util::eq_ignore_case;
@ -26,10 +26,10 @@ use crate::util::eq_ignore_case;
/// [help]: PossibleValue::help()
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct PossibleValue<'help> {
pub(crate) name: &'help str,
pub(crate) help: Option<&'help str>,
pub(crate) aliases: Vec<&'help str>, // (name, visible)
pub(crate) hide: bool,
name: &'help str,
help: Option<&'help str>,
aliases: Vec<&'help str>, // (name, visible)
hide: bool,
}
impl<'help> PossibleValue<'help> {
@ -148,13 +148,41 @@ impl<'help> PossibleValue<'help> {
self.help
}
/// Should the value be hidden from help messages and completion
/// Get the help specified for this argument, if any and the argument
/// value is not hidden
#[inline]
#[cfg(feature = "unstable-v4")]
pub(crate) fn get_visible_help(&self) -> Option<&'help str> {
if !self.hide {
self.help
} else {
None
}
}
/// Deprecated, replaced with [`PossibleValue::is_hide_set`]
#[inline]
#[deprecated(since = "3.1.0", note = "Replaced with `PossibleValue::is_hide_set`")]
pub fn is_hidden(&self) -> bool {
self.is_hide_set()
}
/// 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
#[deprecated(
since = "3.1.4",
note = "Use `PossibleValue::is_hide_set` and `PossibleValue::get_name`"
)]
pub fn get_visible_name(&self) -> Option<&'help str> {
if self.hide {
None
@ -163,6 +191,20 @@ impl<'help> PossibleValue<'help> {
}
}
/// Get the name if argument value is not hidden, `None` otherwise,
/// but wrapped in quotes if it contains whitespace
pub(crate) fn get_visible_quoted_name(&self) -> Option<Cow<'help, str>> {
if !self.hide {
Some(if self.name.contains(char::is_whitespace) {
format!("{:?}", self.name).into()
} else {
self.name.into()
})
} else {
None
}
}
/// Returns all valid values of the argument value.
///
/// Namely the name and all aliases.

Просмотреть файл

56
third_party/rust/clap/src/build/tests.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,56 @@
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();
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"))
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -24,7 +24,7 @@ use std::str::FromStr;
///
/// [^1]: fish completions currently only support named arguments (e.g. -o or --opt), not
/// positional arguments.
#[derive(Debug, PartialEq, Copy, Clone)]
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
#[non_exhaustive]
pub enum ValueHint {
/// Default value if hint is not specified. Follows shell default behavior, which is usually
@ -48,11 +48,11 @@ pub enum ValueHint {
/// common when writing shell wrappers that execute anther command, for example `sudo` or `env`.
///
/// This hint is special, the argument must be a positional argument and have
/// [`.multiple_values(true)`] and App must use [`AppSettings::TrailingVarArg`]. The result is that the
/// [`.multiple_values(true)`] 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.
///
/// [`AppSettings::TrailingVarArg`]: crate::AppSettings::TrailingVarArg
/// [`Command::trailing_var_arg(true)`]: crate::Command::trailing_var_arg
/// [`.multiple_values(true)`]: crate::Arg::multiple_values()
CommandWithArguments,
/// Name of a local operating system user.

132
third_party/rust/clap/src/derive.rs поставляемый
Просмотреть файл

@ -1,18 +1,18 @@
//! This module contains traits that are usable with the `#[derive(...)].`
//! macros in [`clap_derive`].
use crate::{App, ArgMatches, Error, PossibleValue};
use crate::{ArgMatches, Command, Error, PossibleValue};
use std::ffi::OsString;
/// Parse command-line arguments into `Self`.
///
/// The primary one-stop-shop trait used to create an instance of a `clap`
/// [`App`], conduct the parsing, and turn the resulting [`ArgMatches`] back
/// [`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`] +
/// [`IntoApp`] which uses those two underlying traits to build the two
/// [`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).
@ -20,7 +20,7 @@ use std::ffi::OsString;
/// See also [`Subcommand`] and [`Args`].
///
/// See the
/// [derive reference](https://github.com/clap-rs/clap/blob/v3.0.10/examples/derive_ref/README.md)
/// [derive reference](https://github.com/clap-rs/clap/blob/v3.1.18/examples/derive_ref/README.md)
/// for attributes and best practices.
///
/// **NOTE:** Deriving requires the `derive` feature flag
@ -46,11 +46,11 @@ use std::ffi::OsString;
/// }
/// ```
///
/// The equivalent [`App`] struct + `From` implementation:
/// The equivalent [`Command`] struct + `From` implementation:
///
/// ```rust
/// # use clap::{App, Arg, ArgMatches};
/// App::new("demo")
/// # use clap::{Command, Arg, ArgMatches};
/// Command::new("demo")
/// .about("My super CLI")
/// .arg(Arg::new("verbose")
/// .long("verbose")
@ -76,10 +76,10 @@ use std::ffi::OsString;
/// }
/// ```
///
pub trait Parser: FromArgMatches + IntoApp + Sized {
pub trait Parser: FromArgMatches + CommandFactory + Sized {
/// Parse from `std::env::args_os()`, exit on error
fn parse() -> Self {
let matches = <Self as IntoApp>::into_app().get_matches();
let matches = <Self as CommandFactory>::command().get_matches();
let res =
<Self as FromArgMatches>::from_arg_matches(&matches).map_err(format_error::<Self>);
match res {
@ -94,7 +94,7 @@ pub trait Parser: FromArgMatches + IntoApp + Sized {
/// Parse from `std::env::args_os()`, return Err on error.
fn try_parse() -> Result<Self, Error> {
let matches = <Self as IntoApp>::into_app().try_get_matches()?;
let matches = <Self as CommandFactory>::command().try_get_matches()?;
<Self as FromArgMatches>::from_arg_matches(&matches).map_err(format_error::<Self>)
}
@ -104,7 +104,7 @@ pub trait Parser: FromArgMatches + IntoApp + Sized {
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
let matches = <Self as IntoApp>::into_app().get_matches_from(itr);
let matches = <Self as CommandFactory>::command().get_matches_from(itr);
let res =
<Self as FromArgMatches>::from_arg_matches(&matches).map_err(format_error::<Self>);
match res {
@ -123,7 +123,7 @@ pub trait Parser: FromArgMatches + IntoApp + Sized {
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
let matches = <Self as IntoApp>::into_app().try_get_matches_from(itr)?;
let matches = <Self as CommandFactory>::command().try_get_matches_from(itr)?;
<Self as FromArgMatches>::from_arg_matches(&matches).map_err(format_error::<Self>)
}
@ -133,7 +133,7 @@ pub trait Parser: FromArgMatches + IntoApp + Sized {
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
let matches = <Self as IntoApp>::into_app_for_update().get_matches_from(itr);
let matches = <Self as CommandFactory>::command_for_update().get_matches_from(itr);
let res = <Self as FromArgMatches>::update_from_arg_matches(self, &matches)
.map_err(format_error::<Self>);
if let Err(e) = res {
@ -149,19 +149,20 @@ pub trait Parser: FromArgMatches + IntoApp + Sized {
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
let matches = <Self as IntoApp>::into_app_for_update().try_get_matches_from(itr)?;
let matches = <Self as CommandFactory>::command_for_update().try_get_matches_from(itr)?;
<Self as FromArgMatches>::update_from_arg_matches(self, &matches)
.map_err(format_error::<Self>)
}
/// Deprecated, `StructOpt::clap` replaced with [`IntoApp::into_app`] (derive as part of
/// Deprecated, `StructOpt::clap` replaced with [`IntoCommand::command`] (derive as part of
/// [`Parser`])
#[deprecated(
since = "3.0.0",
note = "`StructOpt::clap` is replaced with `IntoApp::into_app` (derived as part of `Parser`)"
note = "`StructOpt::clap` is replaced with `IntoCommand::command` (derived as part of `Parser`)"
)]
fn clap<'help>() -> App<'help> {
<Self as IntoApp>::into_app()
#[doc(hidden)]
fn clap<'help>() -> Command<'help> {
<Self as CommandFactory>::command()
}
/// Deprecated, `StructOpt::from_clap` replaced with [`FromArgMatches::from_arg_matches`] (derive as part of
@ -170,6 +171,7 @@ pub trait Parser: FromArgMatches + IntoApp + Sized {
since = "3.0.0",
note = "`StructOpt::from_clap` is replaced with `FromArgMatches::from_arg_matches` (derived as part of `Parser`)"
)]
#[doc(hidden)]
fn from_clap(matches: &ArgMatches) -> Self {
<Self as FromArgMatches>::from_arg_matches(matches).unwrap()
}
@ -179,6 +181,7 @@ pub trait Parser: FromArgMatches + IntoApp + Sized {
since = "3.0.0",
note = "`StructOpt::from_args` is replaced with `Parser::parse` (note the change in derives)"
)]
#[doc(hidden)]
fn from_args() -> Self {
Self::parse()
}
@ -188,6 +191,7 @@ pub trait Parser: FromArgMatches + IntoApp + Sized {
since = "3.0.0",
note = "`StructOpt::from_args_safe` is replaced with `Parser::try_parse` (note the change in derives)"
)]
#[doc(hidden)]
fn from_args_safe() -> Result<Self, Error> {
Self::try_parse()
}
@ -197,6 +201,7 @@ pub trait Parser: FromArgMatches + IntoApp + Sized {
since = "3.0.0",
note = "`StructOpt::from_iter` is replaced with `Parser::parse_from` (note the change in derives)"
)]
#[doc(hidden)]
fn from_iter<I, T>(itr: I) -> Self
where
I: IntoIterator<Item = T>,
@ -211,6 +216,7 @@ pub trait Parser: FromArgMatches + IntoApp + Sized {
since = "3.0.0",
note = "`StructOpt::from_iter_safe` is replaced with `Parser::try_parse_from` (note the change in derives)"
)]
#[doc(hidden)]
fn from_iter_safe<I, T>(itr: I) -> Result<Self, Error>
where
I: IntoIterator<Item = T>,
@ -220,18 +226,33 @@ pub trait Parser: FromArgMatches + IntoApp + Sized {
}
}
/// Create an [`App`] relevant for a user-defined container.
/// Create a [`Command`] relevant for a user-defined container.
///
/// Derived as part of [`Parser`].
pub trait IntoApp: Sized {
/// Build an [`App`] that can instantiate `Self`.
pub trait CommandFactory: Sized {
/// Build a [`Command`] that can instantiate `Self`.
///
/// See [`FromArgMatches::from_arg_matches`] for instantiating `Self`.
fn into_app<'help>() -> App<'help>;
/// Build an [`App`] that can update `self`.
fn command<'help>() -> Command<'help> {
#[allow(deprecated)]
Self::into_app()
}
/// Deprecated, replaced with `CommandFactory::command`
#[deprecated(since = "3.1.0", note = "Replaced with `CommandFactory::command")]
fn into_app<'help>() -> Command<'help>;
/// Build a [`Command`] that can update `self`.
///
/// See [`FromArgMatches::update_from_arg_matches`] for updating `self`.
fn into_app_for_update<'help>() -> App<'help>;
fn command_for_update<'help>() -> Command<'help> {
#[allow(deprecated)]
Self::into_app_for_update()
}
/// Deprecated, replaced with `CommandFactory::command_for_update`
#[deprecated(
since = "3.1.0",
note = "Replaced with `CommandFactory::command_for_update"
)]
fn into_app_for_update<'help>() -> Command<'help>;
}
/// Converts an instance of [`ArgMatches`] to a user-defined container.
@ -285,7 +306,7 @@ pub trait FromArgMatches: Sized {
/// - `Variant(ChildArgs)`: No attribute is used with enum variants that impl `Args`.
///
/// See the
/// [derive reference](https://github.com/clap-rs/clap/blob/v3.0.10/examples/derive_ref/README.md)
/// [derive reference](https://github.com/clap-rs/clap/blob/v3.1.18/examples/derive_ref/README.md)
/// for attributes and best practices.
///
/// **NOTE:** Deriving requires the `derive` feature flag
@ -307,16 +328,16 @@ pub trait FromArgMatches: Sized {
/// }
/// ```
pub trait Args: FromArgMatches + Sized {
/// Append to [`App`] so it can instantiate `Self`.
/// Append to [`Command`] so it can instantiate `Self`.
///
/// See also [`IntoApp`].
fn augment_args(app: App<'_>) -> App<'_>;
/// Append to [`App`] so it can update `self`.
/// See also [`CommandFactory`].
fn augment_args(cmd: Command<'_>) -> Command<'_>;
/// Append to [`Command`] so it can update `self`.
///
/// This is used to implement `#[clap(flatten)]`
///
/// See also [`IntoApp`].
fn augment_args_for_update(app: App<'_>) -> App<'_>;
/// See also [`CommandFactory`].
fn augment_args_for_update(cmd: Command<'_>) -> Command<'_>;
}
/// Parse a sub-command into a user-defined enum.
@ -329,7 +350,7 @@ pub trait Args: FromArgMatches + Sized {
/// `Subcommand`.
///
/// See the
/// [derive reference](https://github.com/clap-rs/clap/blob/v3.0.10/examples/derive_ref/README.md)
/// [derive reference](https://github.com/clap-rs/clap/blob/v3.1.18/examples/derive_ref/README.md)
/// for attributes and best practices.
///
/// **NOTE:** Deriving requires the `derive` feature flag
@ -351,16 +372,16 @@ pub trait Args: FromArgMatches + Sized {
/// }
/// ```
pub trait Subcommand: FromArgMatches + Sized {
/// Append to [`App`] so it can instantiate `Self`.
/// Append to [`Command`] so it can instantiate `Self`.
///
/// See also [`IntoApp`].
fn augment_subcommands(app: App<'_>) -> App<'_>;
/// Append to [`App`] so it can update `self`.
/// See also [`CommandFactory`].
fn augment_subcommands(cmd: Command<'_>) -> Command<'_>;
/// Append to [`Command`] so it can update `self`.
///
/// This is used to implement `#[clap(flatten)]`
///
/// See also [`IntoApp`].
fn augment_subcommands_for_update(app: App<'_>) -> App<'_>;
/// See also [`CommandFactory`].
fn augment_subcommands_for_update(cmd: Command<'_>) -> Command<'_>;
/// Test whether `Self` can parse a specific subcommand
fn has_subcommand(name: &str) -> bool;
}
@ -373,7 +394,7 @@ pub trait Subcommand: FromArgMatches + Sized {
/// - Allowing using the `#[clap(default_value_t)]` attribute without implementing `Display`.
///
/// See the
/// [derive reference](https://github.com/clap-rs/clap/blob/v3.0.10/examples/derive_ref/README.md)
/// [derive reference](https://github.com/clap-rs/clap/blob/v3.1.18/examples/derive_ref/README.md)
/// for attributes and best practices.
///
/// **NOTE:** Deriving requires the `derive` feature flag
@ -445,12 +466,13 @@ impl<T: Parser> Parser for Box<T> {
}
}
impl<T: IntoApp> IntoApp for Box<T> {
fn into_app<'help>() -> App<'help> {
<T as IntoApp>::into_app()
#[allow(deprecated)]
impl<T: CommandFactory> CommandFactory for Box<T> {
fn into_app<'help>() -> Command<'help> {
<T as CommandFactory>::into_app()
}
fn into_app_for_update<'help>() -> App<'help> {
<T as IntoApp>::into_app_for_update()
fn into_app_for_update<'help>() -> Command<'help> {
<T as CommandFactory>::into_app_for_update()
}
}
@ -464,27 +486,27 @@ impl<T: FromArgMatches> FromArgMatches for Box<T> {
}
impl<T: Args> Args for Box<T> {
fn augment_args(app: App<'_>) -> App<'_> {
<T as Args>::augment_args(app)
fn augment_args(cmd: Command<'_>) -> Command<'_> {
<T as Args>::augment_args(cmd)
}
fn augment_args_for_update(app: App<'_>) -> App<'_> {
<T as Args>::augment_args_for_update(app)
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(app: App<'_>) -> App<'_> {
<T as Subcommand>::augment_subcommands(app)
fn augment_subcommands(cmd: Command<'_>) -> Command<'_> {
<T as Subcommand>::augment_subcommands(cmd)
}
fn augment_subcommands_for_update(app: App<'_>) -> App<'_> {
<T as Subcommand>::augment_subcommands_for_update(app)
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: IntoApp>(err: crate::Error) -> crate::Error {
let mut app = I::into_app();
err.format(&mut app)
fn format_error<I: CommandFactory>(err: crate::Error) -> crate::Error {
let mut cmd = I::command();
err.format(&mut cmd)
}

55
third_party/rust/clap/src/error/context.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,55 @@
/// Semantics for a piece of error information
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum ContextKind {
/// The cause of the error
InvalidSubcommand,
/// The cause of the error
InvalidArg,
/// Existing arguments
PriorArg,
/// Accepted values
ValidValue,
/// Rejected values
InvalidValue,
/// Number of values present
ActualNumValues,
/// Number of allowed values
ExpectedNumValues,
/// Minimum number of allowed values
MinValues,
/// Number of occurrences present
ActualNumOccurrences,
/// Maximum number of allowed occurrences
MaxOccurrences,
/// 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,
/// A usage string
Usage,
/// An opaque message to the user
Custom,
}
/// A piece of error information
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
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
Number(isize),
}

441
third_party/rust/clap/src/error/kind.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,441 @@
/// Command line argument parser kind of error
#[derive(Debug, Copy, Clone, PartialEq)]
#[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::{Command, Arg, ErrorKind};
/// let result = Command::new("prog")
/// .arg(Arg::new("speed")
/// .possible_value("fast")
/// .possible_value("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::{Command, arg, 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
///
#[cfg_attr(not(feature = "suggestions"), doc = " ```no_run")]
#[cfg_attr(feature = "suggestions", doc = " ```")]
/// # use clap::{Command, Arg, 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 provides an unrecognized [`Subcommand`] which either
/// doesn't meet the threshold for being similar enough to an existing subcommand,
/// or the 'suggestions' feature is disabled.
/// Otherwise the more detailed [`InvalidSubcommand`] error is returned.
///
/// This error typically happens when passing additional subcommand names to the `help`
/// subcommand. Otherwise, the more general [`UnknownArgument`] error is used.
///
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg, 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", "help", "nothing"]);
/// assert!(result.is_err());
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::UnrecognizedSubcommand);
/// ```
///
/// [`Subcommand`]: crate::Subcommand
/// [`InvalidSubcommand`]: ErrorKind::InvalidSubcommand
/// [`UnknownArgument`]: ErrorKind::UnknownArgument
UnrecognizedSubcommand,
/// Occurs when the user provides an empty value for an option that does not allow empty
/// values.
///
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg, ErrorKind};
/// let res = Command::new("prog")
/// .arg(Arg::new("color")
/// .takes_value(true)
/// .forbid_empty_values(true)
/// .long("color"))
/// .try_get_matches_from(vec!["prog", "--color="]);
/// assert!(res.is_err());
/// assert_eq!(res.unwrap_err().kind(), ErrorKind::EmptyValue);
/// ```
EmptyValue,
/// Occurs when the user doesn't use equals for an option that requires equal
/// sign to provide values.
///
/// ```rust
/// # use clap::{Command, Arg, ErrorKind};
/// let res = Command::new("prog")
/// .arg(Arg::new("color")
/// .takes_value(true)
/// .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::{Command, Arg, ErrorKind};
/// 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")
/// .validator(is_numeric))
/// .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::max_values`].
///
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg, ErrorKind};
/// let result = Command::new("prog")
/// .arg(Arg::new("arg")
/// .max_values(2))
/// .try_get_matches_from(vec!["prog", "too", "many", "values"]);
/// assert!(result.is_err());
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooManyValues);
/// ```
/// [`Arg::max_values`]: crate::Arg::max_values()
TooManyValues,
/// Occurs when the user provides fewer values for an argument than were defined by setting
/// [`Arg::min_values`].
///
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg, ErrorKind};
/// let result = Command::new("prog")
/// .arg(Arg::new("some_opt")
/// .long("opt")
/// .min_values(3))
/// .try_get_matches_from(vec!["prog", "--opt", "too", "few"]);
/// assert!(result.is_err());
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooFewValues);
/// ```
/// [`Arg::min_values`]: crate::Arg::min_values()
TooFewValues,
/// Occurs when a user provides more occurrences for an argument than were defined by setting
/// [`Arg::max_occurrences`].
///
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg, ErrorKind};
/// let result = Command::new("prog")
/// .arg(Arg::new("verbosity")
/// .short('v')
/// .max_occurrences(2))
/// .try_get_matches_from(vec!["prog", "-vvv"]);
/// assert!(result.is_err());
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooManyOccurrences);
/// ```
/// [`Arg::max_occurrences`]: crate::Arg::max_occurrences()
TooManyOccurrences,
/// Occurs when the user provides a different number of values for an argument than what's
/// been defined by setting [`Arg::number_of_values`] or than was implicitly set by
/// [`Arg::value_names`].
///
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg, ErrorKind};
/// let result = Command::new("prog")
/// .arg(Arg::new("some_opt")
/// .long("opt")
/// .takes_value(true)
/// .number_of_values(2))
/// .try_get_matches_from(vec!["prog", "--opt", "wrong"]);
/// assert!(result.is_err());
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::WrongNumberOfValues);
/// ```
///
/// [`Arg::number_of_values`]: crate::Arg::number_of_values()
/// [`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::{Command, Arg, ErrorKind};
/// let result = Command::new("prog")
/// .arg(Arg::new("debug")
/// .long("debug")
/// .conflicts_with("color"))
/// .arg(Arg::new("color")
/// .long("color"))
/// .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::{Command, Arg, 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::{Command, 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 multiple values to an argument which doesn't allow that.
///
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg, ErrorKind};
/// let result = Command::new("prog")
/// .arg(Arg::new("debug")
/// .long("debug")
/// .multiple_occurrences(false))
/// .try_get_matches_from(vec!["prog", "--debug", "--debug"]);
/// assert!(result.is_err());
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::UnexpectedMultipleUsage);
/// ```
UnexpectedMultipleUsage,
/// Occurs when the user provides a value containing invalid UTF-8.
///
/// To allow arbitrary data
/// - Set [`Arg::allow_invalid_utf8`] for argument values
/// - Set [`Command::allow_invalid_utf8_for_external_subcommands`] for external-subcommand
/// values
///
/// # Platform Specific
///
/// Non-Windows platforms only (such as Linux, Unix, OSX, etc.)
///
/// # Examples
///
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{Command, Arg, ErrorKind};
/// # use std::os::unix::ffi::OsStringExt;
/// # use std::ffi::OsString;
/// let result = Command::new("prog")
/// .arg(Arg::new("utf8")
/// .short('u')
/// .takes_value(true))
/// .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);
/// ```
///
/// [`Arg::allow_invalid_utf8`]: crate::Arg::allow_invalid_utf8
/// [`Command::allow_invalid_utf8_for_external_subcommands`]: crate::Command::allow_invalid_utf8_for_external_subcommands
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
/// # use clap::{Command, Arg, 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::{Command, Arg, 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::{Command, Arg, 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,
/// Occurs when using the [`ArgMatches::value_of_t`] and friends to convert an argument value
/// into type `T`, but the argument you requested wasn't used. I.e. you asked for an argument
/// with name `config` to be converted, but `config` wasn't used by the user.
///
/// [`ArgMatches::value_of_t`]: crate::ArgMatches::value_of_t()
ArgumentNotFound,
/// 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("Found an argument which wasn't expected or isn't valid in this context")
}
Self::InvalidSubcommand => Some("A subcommand wasn't recognized"),
Self::UnrecognizedSubcommand => Some("A subcommand wasn't recognized"),
Self::EmptyValue => Some("An argument requires a value but none was supplied"),
Self::NoEquals => Some("Equal is needed when assigning values to one of the arguments"),
Self::ValueValidation => Some("Invalid for for one of the arguments"),
Self::TooManyValues => Some("An argument received an unexpected value"),
Self::TooFewValues => Some("An argument requires more values"),
Self::TooManyOccurrences => Some("An argument occurred too many times"),
Self::WrongNumberOfValues => Some("An argument received too many or too few values"),
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::UnexpectedMultipleUsage => {
Some("An argument was provided more than once but cannot be used multiple times")
}
Self::InvalidUtf8 => Some("Invalid UTF-8 was detected in one or more arguments"),
Self::DisplayHelp => None,
Self::DisplayHelpOnMissingArgumentOrSubcommand => None,
Self::DisplayVersion => None,
Self::ArgumentNotFound => Some("An argument wasn't found"),
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)
}
}

1181
third_party/rust/clap/src/error/mod.rs поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

47
third_party/rust/clap/src/lib.rs поставляемый
Просмотреть файл

@ -26,17 +26,24 @@
#[cfg(not(feature = "std"))]
compile_error!("`std` feature is currently required to build `clap`");
pub use crate::build::Command;
pub use crate::build::{
AppFlags, AppSettings, Arg, ArgFlags, ArgGroup, ArgSettings, PossibleValue, ValueHint,
};
pub use crate::error::Error;
pub use crate::parse::{ArgMatches, Indices, OsValues, ValueSource, Values};
#[cfg(feature = "color")]
pub use crate::util::color::ColorChoice;
pub use crate::{
build::{
App, AppFlags, AppSettings, Arg, ArgFlags, ArgGroup, ArgSettings, PossibleValue, ValueHint,
},
parse::errors::{Error, ErrorKind, Result},
parse::{ArgMatches, Indices, OsValues, Values},
};
#[cfg(not(feature = "color"))]
#[allow(unused_imports)]
pub(crate) use crate::util::color::ColorChoice;
pub use crate::derive::{ArgEnum, Args, FromArgMatches, IntoApp, Parser, Subcommand};
pub use crate::derive::{ArgEnum, Args, CommandFactory, FromArgMatches, Parser, Subcommand};
pub use crate::error::{ErrorKind, Result};
#[allow(deprecated)]
pub use crate::build::App;
#[cfg(feature = "yaml")]
#[doc(hidden)]
@ -44,14 +51,19 @@ pub use crate::derive::{ArgEnum, Args, FromArgMatches, IntoApp, Parser, Subcomma
since = "3.0.0",
note = "Deprecated in Issue #3087, maybe clap::Parser would fit your use case?"
)]
#[doc(hidden)]
pub use yaml_rust::YamlLoader;
#[cfg(feature = "derive")]
#[doc(hidden)]
pub use clap_derive::{self, *};
/// Deprecated, replaced with [`CommandFactory`]
#[deprecated(since = "3.0.0", note = "Replaced with `CommandFactory`")]
pub use CommandFactory as IntoApp;
/// Deprecated, replaced with [`Parser`]
#[deprecated(since = "3.0.0", note = "Replaced with `Parser`")]
#[doc(hidden)]
pub use Parser as StructOpt;
#[cfg(any(feature = "derive", feature = "cargo"))]
@ -65,7 +77,9 @@ mod macros;
mod derive;
#[cfg(feature = "regex")]
pub use crate::build::arg::RegexRef;
pub use crate::build::RegexRef;
pub mod error;
mod build;
mod mkeymap;
@ -77,21 +91,23 @@ const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a
report at https://github.com/clap-rs/clap/issues";
const INVALID_UTF8: &str = "unexpected invalid UTF-8 code point";
/// Deprecated, replaced with [`App::new`], unless you were looking for [Subcommand]
/// Deprecated, replaced with [`Command::new`], unless you were looking for [Subcommand]
#[deprecated(
since = "3.0.0",
note = "Replaced with `App::new` unless you intended the `Subcommand` trait"
note = "Replaced with `Command::new` unless you intended the `Subcommand` trait"
)]
#[doc(hidden)]
#[derive(Debug, Copy, Clone)]
pub struct SubCommand {}
#[allow(deprecated)]
impl SubCommand {
/// Deprecated, replaced with [`App::new`].
/// Deprecated, replaced with [`Command::new`].
/// Did you mean Subcommand (lower-case c)?
#[deprecated(since = "3.0.0", note = "Replaced with `App::new`")]
#[deprecated(since = "3.0.0", note = "Replaced with `Command::new`")]
#[doc(hidden)]
pub fn with_name<'help>(name: &str) -> App<'help> {
App::new(name)
Command::new(name)
}
/// Deprecated in [Issue #3087](https://github.com/clap-rs/clap/issues/3087), maybe [`clap::Parser`][crate::Parser] would fit your use case?
@ -100,8 +116,9 @@ impl SubCommand {
since = "3.0.0",
note = "Deprecated in Issue #3087, maybe clap::Parser would fit your use case?"
)]
#[doc(hidden)]
pub fn from_yaml(yaml: &yaml_rust::Yaml) -> App {
#![allow(deprecated)]
App::from_yaml(yaml)
Command::from_yaml(yaml)
}
}

200
third_party/rust/clap/src/macros.rs поставляемый
Просмотреть файл

@ -4,6 +4,7 @@
since = "3.0.0",
note = "Deprecated in Issue #3087, maybe clap::Parser would fit your use case?"
)]
#[doc(hidden)]
#[macro_export]
macro_rules! load_yaml {
($yaml:expr) => {
@ -15,6 +16,7 @@ macro_rules! load_yaml {
/// Deprecated, replaced with [`ArgMatches::value_of_t`][crate::ArgMatches::value_of_t]
#[macro_export]
#[deprecated(since = "3.0.0", note = "Replaced with `ArgMatches::value_of_t`")]
#[doc(hidden)]
macro_rules! value_t {
($m:ident, $v:expr, $t:ty) => {
$crate::value_t!($m.value_of($v), $t)
@ -30,6 +32,7 @@ macro_rules! value_t {
since = "3.0.0",
note = "Replaced with `ArgMatches::value_of_t_or_exit`"
)]
#[doc(hidden)]
macro_rules! value_t_or_exit {
($m:ident, $v:expr, $t:ty) => {
value_t_or_exit!($m.value_of($v), $t)
@ -42,6 +45,7 @@ macro_rules! value_t_or_exit {
/// Deprecated, replaced with [`ArgMatches::values_of_t`][crate::ArgMatches::value_of_t]
#[macro_export]
#[deprecated(since = "3.0.0", note = "Replaced with `ArgMatches::values_of_t`")]
#[doc(hidden)]
macro_rules! values_t {
($m:ident, $v:expr, $t:ty) => {
values_t!($m.values_of($v), $t)
@ -57,6 +61,7 @@ macro_rules! values_t {
since = "3.0.0",
note = "Replaced with `ArgMatches::values_of_t_or_exit`"
)]
#[doc(hidden)]
macro_rules! values_t_or_exit {
($m:ident, $v:expr, $t:ty) => {
values_t_or_exit!($m.values_of($v), $t)
@ -66,8 +71,18 @@ macro_rules! values_t_or_exit {
};
}
#[deprecated(since = "3.0.0", note = "Replaced with `ArgEnum`")]
#[doc(hidden)]
#[macro_export]
macro_rules! _clap_count_exprs {
() => { 0 };
($e:expr) => { 1 };
($e:expr, $($es:expr),+) => { 1 + $crate::_clap_count_exprs!($($es),*) };
}
/// Deprecated, replaced with [`ArgEnum`][crate::ArgEnum]
#[deprecated(since = "3.0.0", note = "Replaced with `ArgEnum`")]
#[doc(hidden)]
#[macro_export]
macro_rules! arg_enum {
(@as_item $($i:item)*) => ($($i)*);
@ -180,9 +195,9 @@ macro_rules! arg_enum {
/// ```no_run
/// # #[macro_use]
/// # extern crate clap;
/// # use clap::App;
/// # use clap::Command;
/// # fn main() {
/// let m = App::new("app")
/// let m = Command::new("cmd")
/// .version(crate_version!())
/// .get_matches();
/// # }
@ -195,7 +210,7 @@ macro_rules! crate_version {
};
}
/// Allows you to pull the authors for the app from your Cargo.toml at
/// 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>"`
///
@ -209,9 +224,9 @@ macro_rules! crate_version {
/// ```no_run
/// # #[macro_use]
/// # extern crate clap;
/// # use clap::App;
/// # use clap::Command;
/// # fn main() {
/// let m = App::new("app")
/// let m = Command::new("cmd")
/// .author(crate_authors!("\n"))
/// .get_matches();
/// # }
@ -239,9 +254,9 @@ macro_rules! crate_authors {
/// ```no_run
/// # #[macro_use]
/// # extern crate clap;
/// # use clap::App;
/// # use clap::Command;
/// # fn main() {
/// let m = App::new("app")
/// let m = Command::new("cmd")
/// .about(crate_description!())
/// .get_matches();
/// # }
@ -261,9 +276,9 @@ macro_rules! crate_description {
/// ```no_run
/// # #[macro_use]
/// # extern crate clap;
/// # use clap::App;
/// # use clap::Command;
/// # fn main() {
/// let m = App::new(crate_name!())
/// let m = Command::new(crate_name!())
/// .get_matches();
/// # }
/// ```
@ -275,17 +290,12 @@ macro_rules! crate_name {
};
}
/// Allows you to build the `App` instance from your Cargo.toml at compile time.
///
/// Equivalent to using the `crate_*!` macros with their respective fields.
///
/// Provided separator is for the [`crate_authors!`] macro,
/// refer to the documentation therefor.
/// Allows you to build the `Command` instance from your Cargo.toml at compile time.
///
/// **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.
///
/// **Pro Tip:** In some cases you can "trick" the compiler into triggering a rebuild when your
/// 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");`
///
@ -295,41 +305,78 @@ macro_rules! crate_name {
/// # #[macro_use]
/// # extern crate clap;
/// # fn main() {
/// let m = app_from_crate!().get_matches();
/// 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");
}};
}
/// Deprecated, replaced with [`clap::command!`][crate::command]
#[cfg(feature = "cargo")]
#[deprecated(since = "3.1.0", note = "Replaced with `clap::command!")]
#[macro_export]
macro_rules! app_from_crate {
() => {{
let mut app = $crate::App::new($crate::crate_name!()).version($crate::crate_version!());
let mut cmd = $crate::Command::new($crate::crate_name!()).version($crate::crate_version!());
let author = $crate::crate_authors!(", ");
if !author.is_empty() {
app = app.author(author)
cmd = cmd.author(author)
}
let about = $crate::crate_description!();
if !about.is_empty() {
app = app.about(about)
cmd = cmd.about(about)
}
app
cmd
}};
($sep:expr) => {{
let mut app = $crate::App::new($crate::crate_name!()).version($crate::crate_version!());
let mut cmd = $crate::Command::new($crate::crate_name!()).version($crate::crate_version!());
let author = $crate::crate_authors!($sep);
if !author.is_empty() {
app = app.author(author)
cmd = cmd.author(author)
}
let about = $crate::crate_description!();
if !about.is_empty() {
app = app.about(about)
cmd = cmd.about(about)
}
app
cmd
}};
}
@ -378,12 +425,12 @@ macro_rules! arg_impl {
@arg
({
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
debug_assert!(!$arg.is_set($crate::ArgSettings::MultipleOccurrences), "Flags should precede `...`");
debug_assert!(!$arg.is_multiple_occurrences_set(), "Flags should precede `...`");
let mut arg = $arg;
let long = $crate::arg_impl! { @string $long };
if arg.get_name().is_empty() {
arg = arg.name(long);
if arg.get_id().is_empty() {
arg = arg.id(long);
}
arg.long(long)
})
@ -400,12 +447,12 @@ macro_rules! arg_impl {
@arg
({
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
debug_assert!(!$arg.is_set($crate::ArgSettings::MultipleOccurrences), "Flags should precede `...`");
debug_assert!(!$arg.is_multiple_occurrences_set(), "Flags should precede `...`");
let mut arg = $arg;
let long = $crate::arg_impl! { @string $long };
if arg.get_name().is_empty() {
arg = arg.name(long);
if arg.get_id().is_empty() {
arg = arg.id(long);
}
arg.long(long)
})
@ -423,7 +470,7 @@ macro_rules! arg_impl {
({
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!(!$arg.is_set($crate::ArgSettings::MultipleOccurrences), "Flags should precede `...`");
debug_assert!(!$arg.is_multiple_occurrences_set(), "Flags should precede `...`");
$arg.short($crate::arg_impl! { @char $short })
})
@ -441,7 +488,7 @@ macro_rules! arg_impl {
({
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!(!$arg.is_set($crate::ArgSettings::MultipleOccurrences), "Flags should precede `...`");
debug_assert!(!$arg.is_multiple_occurrences_set(), "Flags should precede `...`");
$arg.short($crate::arg_impl! { @char $short })
})
@ -457,7 +504,7 @@ macro_rules! arg_impl {
$crate::arg_impl! {
@arg
({
debug_assert!(!$arg.is_set($crate::ArgSettings::MultipleOccurrences), "Values should precede `...`");
debug_assert!(!$arg.is_multiple_occurrences_set(), "Values should precede `...`");
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
let mut arg = $arg;
@ -466,8 +513,34 @@ macro_rules! arg_impl {
arg = arg.takes_value(true);
let value_name = $crate::arg_impl! { @string $value_name };
if arg.get_name().is_empty() {
arg = arg.name(value_name);
if arg.get_id().is_empty() {
arg = arg.id(value_name);
}
arg.value_name(value_name)
})
$($tail)*
}
};
(
@arg
($arg:expr)
<$value_name:literal>
$($tail:tt)*
) => {
$crate::arg_impl! {
@arg
({
debug_assert!(!$arg.is_multiple_occurrences_set(), "Values should precede `...`");
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
let mut arg = $arg;
arg = arg.required(true);
arg = arg.takes_value(true);
let value_name = $crate::arg_impl! { @string $value_name };
if arg.get_id().is_empty() {
arg = arg.id(value_name);
}
arg.value_name(value_name)
})
@ -483,7 +556,7 @@ macro_rules! arg_impl {
$crate::arg_impl! {
@arg
({
debug_assert!(!$arg.is_set($crate::ArgSettings::MultipleOccurrences), "Values should precede `...`");
debug_assert!(!$arg.is_multiple_occurrences_set(), "Values should precede `...`");
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
let mut arg = $arg;
@ -496,8 +569,38 @@ macro_rules! arg_impl {
arg = arg.takes_value(true);
let value_name = $crate::arg_impl! { @string $value_name };
if arg.get_name().is_empty() {
arg = arg.name(value_name);
if arg.get_id().is_empty() {
arg = arg.id(value_name);
}
arg.value_name(value_name)
})
$($tail)*
}
};
(
@arg
($arg:expr)
[$value_name:literal]
$($tail:tt)*
) => {
$crate::arg_impl! {
@arg
({
debug_assert!(!$arg.is_multiple_occurrences_set(), "Values 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.min_values(0).max_values(1);
}
arg = arg.takes_value(true);
let value_name = $crate::arg_impl! { @string $value_name };
if arg.get_id().is_empty() {
arg = arg.id(value_name);
}
arg.value_name(value_name)
})
@ -595,14 +698,14 @@ macro_rules! arg_impl {
///
/// ### Help String
///
/// The help string is denoted between a pair of single quotes `''` and may contain any
/// The help string is denoted between a pair of double quotes `""` and may contain any
/// characters.
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, arg};
/// App::new("prog")
/// # use clap::{Command, Arg, arg};
/// 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"),
@ -622,7 +725,7 @@ macro_rules! arg {
let arg = $crate::arg_impl! {
@arg ($crate::Arg::default()) $($tail)+
};
debug_assert!(!arg.get_name().is_empty(), "Without a value or long flag, the `name:` prefix is required");
debug_assert!(!arg.get_id().is_empty(), "Without a value or long flag, the `name:` prefix is required");
arg
}};
}
@ -632,6 +735,7 @@ macro_rules! arg {
since = "3.0.0",
note = "Replaced with `clap::Parser` for a declarative API (Issue clap-rs/clap#2835)"
)]
#[doc(hidden)]
#[macro_export]
macro_rules! clap_app {
(@app ($builder:expr)) => { $builder };
@ -681,7 +785,7 @@ macro_rules! clap_app {
(@app ($builder:expr) (@subcommand $name:ident => $($tail:tt)*) $($tt:tt)*) => {
$crate::clap_app!{ @app
($builder.subcommand(
$crate::clap_app!{ @app ($crate::App::new(stringify!($name))) $($tail)* }
$crate::clap_app!{ @app ($crate::Command::new(stringify!($name))) $($tail)* }
))
$($tt)*
}
@ -773,15 +877,15 @@ macro_rules! clap_app {
// Build a subcommand outside of an app.
(@subcommand $name:ident => $($tail:tt)*) => {
$crate::clap_app!{ @app ($crate::App::new(stringify!($name))) $($tail)* }
$crate::clap_app!{ @app ($crate::Command::new(stringify!($name))) $($tail)* }
};
// Start the magic
(($name:expr) => $($tail:tt)*) => {{
$crate::clap_app!{ @app ($crate::App::new($name)) $($tail)*}
$crate::clap_app!{ @app ($crate::Command::new($name)) $($tail)*}
}};
($name:ident => $($tail:tt)*) => {{
$crate::clap_app!{ @app ($crate::App::new(stringify!($name))) $($tail)*}
$crate::clap_app!{ @app ($crate::Command::new(stringify!($name))) $($tail)*}
}};
}
@ -894,7 +998,7 @@ macro_rules! debug {
($($arg:tt)*) => ({
let prefix = format!("[{:>w$}] \t", module_path!(), w = 28);
let body = format!($($arg)*);
let mut color = $crate::output::fmt::Colorizer::new(true, $crate::ColorChoice::Auto);
let mut color = $crate::output::fmt::Colorizer::new($crate::output::fmt::Stream::Stderr, $crate::ColorChoice::Auto);
color.hint(prefix);
color.hint(body);
color.none("\n");

9
third_party/rust/clap/src/mkeymap.rs поставляемый
Просмотреть файл

@ -49,6 +49,15 @@ impl PartialEq<&str> for KeyType {
}
}
impl PartialEq<str> for KeyType {
fn eq(&self, rhs: &str) -> bool {
match self {
KeyType::Long(l) => l == rhs,
_ => false,
}
}
}
impl PartialEq<OsStr> for KeyType {
fn eq(&self, rhs: &OsStr) -> bool {
match self {

61
third_party/rust/clap/src/output/fmt.rs поставляемый
Просмотреть файл

@ -5,46 +5,52 @@ use std::{
io::{self, Write},
};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum Stream {
Stdout,
Stderr,
}
#[derive(Clone, Debug)]
pub(crate) struct Colorizer {
use_stderr: bool,
stream: Stream,
#[allow(unused)]
color_when: ColorChoice,
pieces: Vec<(String, Style)>,
}
impl Colorizer {
#[inline]
pub(crate) fn new(use_stderr: bool, color_when: ColorChoice) -> Self {
#[inline(never)]
pub(crate) fn new(stream: Stream, color_when: ColorChoice) -> Self {
Colorizer {
use_stderr,
stream,
color_when,
pieces: vec![],
}
}
#[inline]
#[inline(never)]
pub(crate) fn good(&mut self, msg: impl Into<String>) {
self.pieces.push((msg.into(), Style::Good));
}
#[inline]
#[inline(never)]
pub(crate) fn warning(&mut self, msg: impl Into<String>) {
self.pieces.push((msg.into(), Style::Warning));
}
#[inline]
#[inline(never)]
pub(crate) fn error(&mut self, msg: impl Into<String>) {
self.pieces.push((msg.into(), Style::Error));
}
#[inline]
#[inline(never)]
#[allow(dead_code)]
pub(crate) fn hint(&mut self, msg: impl Into<String>) {
self.pieces.push((msg.into(), Style::Hint));
}
#[inline]
#[inline(never)]
pub(crate) fn none(&mut self, msg: impl Into<String>) {
self.pieces.push((msg.into(), Style::Default));
}
@ -58,14 +64,13 @@ impl Colorizer {
let color_when = match self.color_when {
ColorChoice::Always => DepColorChoice::Always,
ColorChoice::Auto if is_a_tty(self.use_stderr) => DepColorChoice::Auto,
ColorChoice::Auto if is_a_tty(self.stream) => DepColorChoice::Auto,
_ => DepColorChoice::Never,
};
let writer = if self.use_stderr {
BufferWriter::stderr(color_when)
} else {
BufferWriter::stdout(color_when)
let writer = match self.stream {
Stream::Stderr => BufferWriter::stderr(color_when),
Stream::Stdout => BufferWriter::stdout(color_when),
};
let mut buffer = writer.buffer();
@ -101,14 +106,17 @@ impl Colorizer {
pub(crate) fn print(&self) -> io::Result<()> {
// [e]println can't be used here because it panics
// if something went wrong. We don't want that.
if self.use_stderr {
let stderr = std::io::stderr();
let mut stderr = stderr.lock();
write!(stderr, "{}", self)
} else {
let stdout = std::io::stdout();
let mut stdout = stdout.lock();
write!(stdout, "{}", self)
match self.stream {
Stream::Stdout => {
let stdout = std::io::stdout();
let mut stdout = stdout.lock();
write!(stdout, "{}", self)
}
Stream::Stderr => {
let stderr = std::io::stderr();
let mut stderr = stderr.lock();
write!(stderr, "{}", self)
}
}
}
}
@ -140,11 +148,10 @@ impl Default for Style {
}
#[cfg(feature = "color")]
fn is_a_tty(stderr: bool) -> bool {
let stream = if stderr {
atty::Stream::Stderr
} else {
atty::Stream::Stdout
fn is_a_tty(stream: Stream) -> bool {
let stream = match stream {
Stream::Stdout => atty::Stream::Stdout,
Stream::Stderr => atty::Stream::Stderr,
};
atty::is(stream)

511
third_party/rust/clap/src/output/help.rs поставляемый
Просмотреть файл

@ -2,16 +2,16 @@
use std::{
borrow::Cow,
cmp,
collections::BTreeMap,
fmt::Write as _,
io::{self, Write},
usize,
};
// Internal
use crate::{
build::{arg::display_arg_val, App, AppSettings, Arg, ArgSettings},
build::{display_arg_val, Arg, Command},
output::{fmt::Colorizer, Usage},
parse::Parser,
PossibleValue,
};
// Third party
@ -21,17 +21,26 @@ use textwrap::core::display_width;
/// `clap` Help Writer.
///
/// Wraps a writer stream providing different methods to generate help for `clap` objects.
pub(crate) struct Help<'help, 'app, 'parser, 'writer> {
pub(crate) struct Help<'help, 'cmd, 'writer> {
writer: HelpWriter<'writer>,
parser: &'parser Parser<'help, 'app>,
cmd: &'cmd Command<'help>,
usage: &'cmd Usage<'help, 'cmd>,
next_line_help: bool,
hide_pv: bool,
term_w: usize,
use_long: bool,
}
// Public Functions
impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
impl<'help, 'cmd, 'writer> Help<'help, 'cmd, 'writer> {
#[cfg(feature = "unstable-v4")]
const DEFAULT_TEMPLATE: &'static str = "\
{before-help}{name} {version}\n\
{author-with-newline}{about-with-newline}\n\
{usage-heading}\n {usage}\n\
\n\
{all-args}{after-help}\
";
#[cfg(not(feature = "unstable-v4"))]
const DEFAULT_TEMPLATE: &'static str = "\
{before-help}{bin} {version}\n\
{author-with-newline}{about-with-newline}\n\
@ -40,6 +49,13 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
{all-args}{after-help}\
";
#[cfg(feature = "unstable-v4")]
const DEFAULT_NO_ARGS_TEMPLATE: &'static str = "\
{before-help}{name} {version}\n\
{author-with-newline}{about-with-newline}\n\
{usage-heading}\n {usage}{after-help}\
";
#[cfg(not(feature = "unstable-v4"))]
const DEFAULT_NO_ARGS_TEMPLATE: &'static str = "\
{before-help}{bin} {version}\n\
{author-with-newline}{about-with-newline}\n\
@ -49,29 +65,29 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
/// Create a new `Help` instance.
pub(crate) fn new(
writer: HelpWriter<'writer>,
parser: &'parser Parser<'help, 'app>,
cmd: &'cmd Command<'help>,
usage: &'cmd Usage<'help, 'cmd>,
use_long: bool,
) -> Self {
debug!("Help::new");
let term_w = match parser.app.term_w {
let term_w = match cmd.get_term_width() {
Some(0) => usize::MAX,
Some(w) => w,
None => cmp::min(
dimensions().map_or(100, |(w, _)| w),
match parser.app.max_w {
match cmd.get_max_term_width() {
None | Some(0) => usize::MAX,
Some(mw) => mw,
},
),
};
let next_line_help = parser.is_set(AppSettings::NextLineHelp);
let hide_pv = parser.is_set(AppSettings::HidePossibleValues);
let next_line_help = cmd.is_next_line_help_set();
Help {
writer,
parser,
cmd,
usage,
next_line_help,
hide_pv,
term_w,
use_long,
}
@ -81,22 +97,20 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
pub(crate) fn write_help(&mut self) -> io::Result<()> {
debug!("Help::write_help");
if let Some(h) = self.parser.app.help_str {
if let Some(h) = self.cmd.get_override_help() {
self.none(h)?;
} else if let Some(tmpl) = self.parser.app.template {
} else if let Some(tmpl) = self.cmd.get_help_template() {
self.write_templated_help(tmpl)?;
} else {
let pos = self
.parser
.app
.cmd
.get_positionals()
.any(|arg| should_show_arg(self.use_long, arg));
let non_pos = self
.parser
.app
.cmd
.get_non_positionals()
.any(|arg| should_show_arg(self.use_long, arg));
let subcmds = self.parser.app.has_visible_subcommands();
let subcmds = self.cmd.has_visible_subcommands();
if non_pos || pos || subcmds {
self.write_templated_help(Self::DEFAULT_TEMPLATE)?;
@ -124,19 +138,23 @@ macro_rules! write_method {
}
// Methods to write Arg help.
impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
impl<'help, 'cmd, 'writer> Help<'help, 'cmd, 'writer> {
#[inline(never)]
fn good<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()> {
write_method!(self, msg, good)
}
#[inline(never)]
fn warning<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()> {
write_method!(self, msg, warning)
}
#[inline(never)]
fn none<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()> {
write_method!(self, msg, none)
}
#[inline(never)]
fn spaces(&mut self, n: usize) -> io::Result<()> {
// A string with 64 consecutive spaces.
const SHORT_SPACE: &str =
@ -155,7 +173,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
let mut longest = 2;
let mut arg_v = Vec::with_capacity(10);
for arg in args
for &arg in args
.iter()
.filter(|arg| should_show_arg(self.use_long, *arg))
{
@ -179,10 +197,10 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
debug!("Help::write_args");
// The shortest an arg can legally be is 2 (i.e. '-x')
let mut longest = 2;
let mut ord_m = BTreeMap::new();
let mut ord_v = Vec::new();
// Determine the longest
for arg in args.iter().filter(|arg| {
for &arg in args.iter().filter(|arg| {
// If it's NextLineHelp we don't care to compute how long it is because it may be
// NextLineHelp on purpose simply *because* it's so long and would throw off all other
// args alignment
@ -193,9 +211,6 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
longest = longest.max(display_width(arg.to_string().as_str()));
debug!("Help::write_args: New Longest...{}", longest);
}
let btm = ord_m
.entry(arg.get_display_order())
.or_insert_with(BTreeMap::new);
// Formatting key like this to ensure that:
// 1. Argument has long flags are printed just after short flags.
@ -216,19 +231,15 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
s.push_str(arg.name);
s
};
btm.insert(key, arg);
ord_v.push((arg.get_display_order(), key, arg));
}
ord_v.sort_by(|a, b| (a.0, &a.1).cmp(&(b.0, &b.1)));
let next_line_help = self.will_args_wrap(args, longest);
let num_ord_m = ord_m.len();
for (i, btm) in ord_m.values().enumerate() {
let last_btm = i + 1 == num_ord_m;
let num_args = btm.len();
for (i, arg) in btm.values().enumerate() {
let last_arg = last_btm && i + 1 == num_args;
self.write_arg(arg, last_arg, next_line_help, longest)?;
}
for (i, (_, _, arg)) in ord_v.iter().enumerate() {
let last_arg = i + 1 == ord_v.len();
self.write_arg(arg, last_arg, next_line_help, longest)?;
}
Ok(())
}
@ -261,7 +272,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
self.none(TAB)?;
if let Some(s) = arg.short {
self.good(&format!("-{}", s))
self.good(format!("-{}", s))
} else if !arg.is_positional() {
self.none(TAB)
} else {
@ -272,49 +283,65 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
/// Writes argument's long command to the wrapped stream.
fn long(&mut self, arg: &Arg<'help>) -> io::Result<()> {
debug!("Help::long");
if arg.is_positional() {
return Ok(());
}
if arg.is_set(ArgSettings::TakesValue) {
if let Some(l) = arg.long {
if arg.short.is_some() {
self.none(", ")?;
}
self.good(&format!("--{}", l))?
}
let sep = if arg.is_set(ArgSettings::RequireEquals) {
"="
} else {
" "
};
self.none(sep)?;
} else if let Some(l) = arg.long {
if let Some(long) = arg.long {
if arg.short.is_some() {
self.none(", ")?;
}
self.good(&format!("--{}", l))?;
self.good(format!("--{}", long))?;
}
Ok(())
}
/// Writes argument's possible values to the wrapped stream.
fn val(&mut self, arg: &Arg<'help>, next_line_help: bool, longest: usize) -> io::Result<()> {
fn val(&mut self, arg: &Arg<'help>) -> io::Result<()> {
debug!("Help::val: arg={}", arg.name);
if arg.is_set(ArgSettings::TakesValue) || arg.is_positional() {
let mut need_closing_bracket = false;
if arg.is_takes_value_set() && !arg.is_positional() {
let is_optional_val = arg.min_vals == Some(0);
let sep = if arg.is_require_equals_set() {
if is_optional_val {
need_closing_bracket = true;
"[="
} else {
"="
}
} else if is_optional_val {
need_closing_bracket = true;
" ["
} else {
" "
};
self.none(sep)?;
}
if arg.is_takes_value_set() || arg.is_positional() {
display_arg_val(
arg,
|s, good| if good { self.good(s) } else { self.none(s) },
)?;
}
debug!("Help::val: Has switch...");
if need_closing_bracket {
self.none("]")?;
}
Ok(())
}
/// Write alignment padding between arg's switches/values and its about message.
fn align_to_about(
&mut self,
arg: &Arg<'help>,
next_line_help: bool,
longest: usize,
) -> io::Result<()> {
debug!("Help::align_to_about: arg={}", arg.name);
debug!("Help::align_to_about: Has switch...");
if self.use_long {
// long help prints messages on the next line so it don't need to align text
debug!("Help::val: printing long help so skip alignment");
// long help prints messages on the next line so it doesn't need to align text
debug!("Help::align_to_about: printing long help so skip alignment");
} else if !arg.is_positional() {
debug!("Yes");
debug!("Help::val: nlh...{:?}", next_line_help);
debug!("Help::align_to_about: nlh...{:?}", next_line_help);
if !next_line_help {
let self_len = display_width(arg.to_string().as_str());
// subtract ourself
@ -343,12 +370,11 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
fn write_before_help(&mut self) -> io::Result<()> {
debug!("Help::write_before_help");
let before_help = if self.use_long {
self.parser
.app
.before_long_help
.or(self.parser.app.before_help)
self.cmd
.get_before_long_help()
.or_else(|| self.cmd.get_before_help())
} else {
self.parser.app.before_help
self.cmd.get_before_help()
};
if let Some(output) = before_help {
self.none(text_wrapper(&output.replace("{n}", "\n"), self.term_w))?;
@ -360,12 +386,11 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
fn write_after_help(&mut self) -> io::Result<()> {
debug!("Help::write_after_help");
let after_help = if self.use_long {
self.parser
.app
.after_long_help
.or(self.parser.app.after_help)
self.cmd
.get_after_long_help()
.or_else(|| self.cmd.get_after_help())
} else {
self.parser.app.after_help
self.cmd.get_after_help()
};
if let Some(output) = after_help {
self.none("\n\n")?;
@ -377,7 +402,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
/// Writes argument's help to the wrapped stream.
fn help(
&mut self,
is_not_positional: bool,
arg: Option<&Arg<'help>>,
about: &str,
spec_vals: &str,
next_line_help: bool,
@ -393,11 +418,11 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
longest + 12
};
let too_long = spaces + display_width(about) + display_width(spec_vals) >= self.term_w;
let too_long = spaces + display_width(&help) >= self.term_w;
// Is help on next line, if so then indent
if next_line_help {
self.none(&format!("\n{}{}{}", TAB, TAB, TAB))?;
self.none(format!("\n{}{}{}", TAB, TAB, TAB))?;
}
debug!("Help::help: Too long...");
@ -415,17 +440,100 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
if let Some(part) = help.lines().next() {
self.none(part)?;
}
// indent of help
let spaces = if next_line_help {
TAB_WIDTH * 3
} else if let Some(true) = arg.map(|a| a.is_positional()) {
longest + TAB_WIDTH * 2
} else {
longest + TAB_WIDTH * 3
};
for part in help.lines().skip(1) {
self.none("\n")?;
if next_line_help {
self.none(&format!("{}{}{}", TAB, TAB, TAB))?;
} else if is_not_positional {
self.spaces(longest + 12)?;
} else {
self.spaces(longest + 8)?;
}
self.spaces(spaces)?;
self.none(part)?;
}
#[cfg(feature = "unstable-v4")]
if let Some(arg) = arg {
const DASH_SPACE: usize = "- ".len();
const COLON_SPACE: usize = ": ".len();
if self.use_long
&& !arg.is_hide_possible_values_set()
&& arg
.possible_vals
.iter()
.any(PossibleValue::should_show_help)
{
debug!("Help::help: Found possible vals...{:?}", arg.possible_vals);
if !help.is_empty() {
self.none("\n\n")?;
self.spaces(spaces)?;
}
self.none("Possible values:")?;
let longest = arg
.possible_vals
.iter()
.filter_map(|f| f.get_visible_quoted_name().map(|name| display_width(&name)))
.max()
.expect("Only called with possible value");
let help_longest = arg
.possible_vals
.iter()
.filter_map(|f| f.get_visible_help().map(display_width))
.max()
.expect("Only called with possible value with help");
// should new line
let taken = longest + spaces + DASH_SPACE;
let possible_value_new_line =
self.term_w >= taken && self.term_w < taken + COLON_SPACE + help_longest;
let spaces = spaces + TAB_WIDTH - DASH_SPACE;
let spaces_help = if possible_value_new_line {
spaces + DASH_SPACE
} else {
spaces + longest + DASH_SPACE + COLON_SPACE
};
for pv in arg.possible_vals.iter().filter(|pv| !pv.is_hide_set()) {
self.none("\n")?;
self.spaces(spaces)?;
self.none("- ")?;
self.good(pv.get_name())?;
if let Some(help) = pv.get_help() {
debug!("Help::help: Possible Value help");
if possible_value_new_line {
self.none(":\n")?;
self.spaces(spaces_help)?;
} else {
self.none(": ")?;
// To align help messages
self.spaces(longest - display_width(pv.get_name()))?;
}
let avail_chars = if self.term_w > spaces_help {
self.term_w - spaces_help
} else {
usize::MAX
};
let help = text_wrapper(help, avail_chars);
let mut help = help.lines();
self.none(help.next().unwrap_or_default())?;
for part in help {
self.none("\n")?;
self.spaces(spaces_help)?;
self.none(part)?;
}
}
}
}
}
Ok(())
}
@ -439,21 +547,16 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
) -> io::Result<()> {
self.short(arg)?;
self.long(arg)?;
self.val(arg, next_line_help, longest)?;
self.val(arg)?;
self.align_to_about(arg, next_line_help, longest)?;
let about = if self.use_long {
arg.long_help.unwrap_or_else(|| arg.help.unwrap_or(""))
arg.long_help.or(arg.help).unwrap_or("")
} else {
arg.help.unwrap_or_else(|| arg.long_help.unwrap_or(""))
arg.help.or(arg.long_help).unwrap_or("")
};
self.help(
!arg.is_positional(),
about,
spec_vals,
next_line_help,
longest,
)?;
self.help(Some(arg), about, spec_vals, next_line_help, longest)?;
Ok(())
}
@ -468,7 +571,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
}
fn arg_next_line_help(&self, arg: &Arg<'help>, spec_vals: &str, longest: usize) -> bool {
if self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || self.use_long {
if self.next_line_help || arg.is_next_line_help_set() || self.use_long {
// setting_next_line
true
} else {
@ -487,12 +590,12 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
let mut spec_vals = vec![];
#[cfg(feature = "env")]
if let Some(ref env) = a.env {
if !a.is_set(ArgSettings::HideEnv) {
if !a.is_hide_env_set() {
debug!(
"Help::spec_vals: Found environment variable...[{:?}:{:?}]",
env.0, env.1
);
let env_val = if !a.is_set(ArgSettings::HideEnvValues) {
let env_val = if !a.is_hide_env_values_set() {
format!(
"={}",
env.1
@ -506,7 +609,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
spec_vals.push(env_info);
}
}
if !a.is_set(ArgSettings::HideDefaultValue) && !a.default_vals.is_empty() {
if !a.is_hide_default_value_set() && !a.default_vals.is_empty() {
debug!(
"Help::spec_vals: Found default value...[{:?}]",
a.default_vals
@ -563,9 +666,11 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
}
}
if !self.hide_pv
&& !a.is_set(ArgSettings::HidePossibleValues)
&& !a.possible_vals.is_empty()
if !(a.is_hide_possible_values_set()
|| a.possible_vals.is_empty()
|| cfg!(feature = "unstable-v4")
&& self.use_long
&& a.possible_vals.iter().any(PossibleValue::should_show_help))
{
debug!(
"Help::spec_vals: Found possible vals...{:?}",
@ -575,15 +680,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
let pvs = a
.possible_vals
.iter()
.filter_map(|value| {
if value.is_hidden() {
None
} else if value.get_name().contains(char::is_whitespace) {
Some(format!("{:?}", value.get_name()))
} else {
Some(value.get_name().to_string())
}
})
.filter_map(PossibleValue::get_visible_quoted_name)
.collect::<Vec<_>>()
.join(", ");
@ -604,9 +701,9 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
fn write_about(&mut self, before_new_line: bool, after_new_line: bool) -> io::Result<()> {
let about = if self.use_long {
self.parser.app.long_about.or(self.parser.app.about)
self.cmd.get_long_about().or_else(|| self.cmd.get_about())
} else {
self.parser.app.about
self.cmd.get_about()
};
if let Some(output) = about {
if before_new_line {
@ -621,7 +718,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
}
fn write_author(&mut self, before_new_line: bool, after_new_line: bool) -> io::Result<()> {
if let Some(author) = self.parser.app.author {
if let Some(author) = self.cmd.get_author() {
if before_new_line {
self.none("\n")?;
}
@ -634,7 +731,10 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
}
fn write_version(&mut self) -> io::Result<()> {
let version = self.parser.app.version.or(self.parser.app.long_version);
let version = self
.cmd
.get_version()
.or_else(|| self.cmd.get_long_version());
if let Some(output) = version {
self.none(text_wrapper(output, self.term_w))?;
}
@ -643,32 +743,38 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
}
/// Methods to write a single subcommand
impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
impl<'help, 'cmd, 'writer> Help<'help, 'cmd, 'writer> {
fn write_subcommand(
&mut self,
sc_str: &str,
app: &App<'help>,
cmd: &Command<'help>,
next_line_help: bool,
longest: usize,
) -> io::Result<()> {
debug!("Help::write_subcommand");
let spec_vals = &self.sc_spec_vals(app);
let spec_vals = &self.sc_spec_vals(cmd);
let about = app.about.unwrap_or_else(|| app.long_about.unwrap_or(""));
let about = cmd
.get_about()
.or_else(|| cmd.get_long_about())
.unwrap_or("");
self.subcmd(sc_str, next_line_help, longest)?;
self.help(false, about, spec_vals, next_line_help, longest)
self.help(None, about, spec_vals, next_line_help, longest)
}
fn sc_spec_vals(&self, a: &App) -> String {
debug!("Help::sc_spec_vals: a={}", a.name);
fn sc_spec_vals(&self, a: &Command) -> String {
debug!("Help::sc_spec_vals: a={}", a.get_name());
let mut spec_vals = vec![];
if !a.aliases.is_empty() || !a.short_flag_aliases.is_empty() {
debug!("Help::spec_vals: Found aliases...{:?}", a.aliases);
if 0 < a.get_all_aliases().count() || 0 < a.get_all_short_flag_aliases().count() {
debug!(
"Help::spec_vals: Found aliases...{:?}",
a.get_all_aliases().collect::<Vec<_>>()
);
debug!(
"Help::spec_vals: Found short flag aliases...{:?}",
a.short_flag_aliases
a.get_all_short_flag_aliases().collect::<Vec<_>>()
);
let mut short_als = a
@ -689,13 +795,18 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
spec_vals.join(" ")
}
fn subcommand_next_line_help(&self, app: &App<'help>, spec_vals: &str, longest: usize) -> bool {
fn subcommand_next_line_help(
&self,
cmd: &Command<'help>,
spec_vals: &str,
longest: usize,
) -> bool {
if self.next_line_help | self.use_long {
// setting_next_line
true
} else {
// force_next_line
let h = app.about.unwrap_or("");
let h = cmd.get_about().unwrap_or("");
let h_w = display_width(h) + display_width(spec_vals);
let taken = longest + 12;
self.term_w >= taken
@ -717,30 +828,26 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
}
// Methods to write Parser help.
impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
impl<'help, 'cmd, 'writer> Help<'help, 'cmd, 'writer> {
/// Writes help for all arguments (options, flags, args, subcommands)
/// including titles of a Parser Object to the wrapped stream.
pub(crate) fn write_all_args(&mut self) -> io::Result<()> {
debug!("Help::write_all_args");
let pos = self
.parser
.app
.cmd
.get_positionals_with_no_heading()
.filter(|arg| should_show_arg(self.use_long, arg))
.collect::<Vec<_>>();
let non_pos = self
.parser
.app
.cmd
.get_non_positionals_with_no_heading()
.filter(|arg| should_show_arg(self.use_long, arg))
.collect::<Vec<_>>();
let subcmds = self.parser.app.has_visible_subcommands();
let subcmds = self.cmd.has_visible_subcommands();
let custom_headings = self
.parser
.app
.args
.args()
.cmd
.get_arguments()
.filter_map(|arg| arg.get_help_heading())
.collect::<IndexSet<_>>();
@ -764,10 +871,8 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
if !custom_headings.is_empty() {
for heading in custom_headings {
let args = self
.parser
.app
.args
.args()
.cmd
.get_arguments()
.filter(|a| {
if let Some(help_heading) = a.get_help_heading() {
return help_heading == heading;
@ -781,8 +886,8 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
if !first {
self.none("\n\n")?;
}
self.warning(&*format!("{}:\n", heading))?;
self.write_args(&*args)?;
self.warning(format!("{}:\n", heading))?;
self.write_args(&args)?;
first = false
}
}
@ -793,19 +898,30 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
self.none("\n\n")?;
}
self.warning(self.parser.app.subcommand_heading.unwrap_or("SUBCOMMANDS"))?;
self.warning(
self.cmd
.get_subcommand_help_heading()
.unwrap_or("SUBCOMMANDS"),
)?;
self.warning(":\n")?;
self.write_subcommands(self.parser.app)?;
self.write_subcommands(self.cmd)?;
}
Ok(())
}
/// Will use next line help on writing subcommands.
fn will_subcommands_wrap(&self, subcommands: &[App<'help>], longest: usize) -> bool {
fn will_subcommands_wrap<'a>(
&self,
subcommands: impl IntoIterator<Item = &'a Command<'help>>,
longest: usize,
) -> bool
where
'help: 'a,
{
subcommands
.iter()
.into_iter()
.filter(|&subcommand| should_show_subcommand(subcommand))
.any(|subcommand| {
let spec_vals = &self.sc_spec_vals(subcommand);
@ -814,66 +930,73 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
}
/// Writes help for subcommands of a Parser Object to the wrapped stream.
fn write_subcommands(&mut self, app: &App<'help>) -> io::Result<()> {
fn write_subcommands(&mut self, cmd: &Command<'help>) -> io::Result<()> {
debug!("Help::write_subcommands");
// The shortest an arg can legally be is 2 (i.e. '-x')
let mut longest = 2;
let mut ord_m = BTreeMap::new();
for subcommand in app
.subcommands
.iter()
let mut ord_v = Vec::new();
for subcommand in cmd
.get_subcommands()
.filter(|subcommand| should_show_subcommand(subcommand))
{
let btm = ord_m
.entry(subcommand.get_display_order())
.or_insert_with(BTreeMap::new);
let mut sc_str = String::new();
sc_str.push_str(
&subcommand
.short_flag
.map_or(String::new(), |c| format!("-{}, ", c)),
);
sc_str.push_str(
&subcommand
.long_flag
.map_or(String::new(), |c| format!("--{}, ", c)),
);
sc_str.push_str(&subcommand.name);
sc_str.push_str(subcommand.get_name());
if let Some(short) = subcommand.get_short_flag() {
write!(sc_str, " -{}", short).unwrap();
}
if let Some(long) = subcommand.get_long_flag() {
write!(sc_str, " --{}", long).unwrap();
}
longest = longest.max(display_width(&sc_str));
btm.insert(sc_str, subcommand.clone());
ord_v.push((subcommand.get_display_order(), sc_str, subcommand));
}
ord_v.sort_by(|a, b| (a.0, &a.1).cmp(&(b.0, &b.1)));
debug!("Help::write_subcommands longest = {}", longest);
let next_line_help = self.will_subcommands_wrap(&app.subcommands, longest);
let next_line_help = self.will_subcommands_wrap(cmd.get_subcommands(), longest);
let mut first = true;
for btm in ord_m.values() {
for (sc_str, sc) in btm {
if first {
first = false;
} else {
self.none("\n")?;
}
self.write_subcommand(sc_str, sc, next_line_help, longest)?;
for (_, sc_str, sc) in &ord_v {
if first {
first = false;
} else {
self.none("\n")?;
}
self.write_subcommand(sc_str, sc, next_line_help, longest)?;
}
Ok(())
}
/// Writes binary name of a Parser Object to the wrapped stream.
fn write_display_name(&mut self) -> io::Result<()> {
debug!("Help::write_display_name");
let display_name = text_wrapper(
&self
.cmd
.get_display_name()
.unwrap_or_else(|| self.cmd.get_name())
.replace("{n}", "\n"),
self.term_w,
);
self.good(&display_name)?;
Ok(())
}
/// Writes binary name of a Parser Object to the wrapped stream.
fn write_bin_name(&mut self) -> io::Result<()> {
debug!("Help::write_bin_name");
let bin_name = if let Some(bn) = self.parser.app.bin_name.as_ref() {
let bin_name = if let Some(bn) = self.cmd.get_bin_name() {
if bn.contains(' ') {
// In case we're dealing with subcommands i.e. git mv is translated to git-mv
bn.replace(' ', "-")
} else {
text_wrapper(&self.parser.app.name.replace("{n}", "\n"), self.term_w)
text_wrapper(&self.cmd.get_name().replace("{n}", "\n"), self.term_w)
}
} else {
text_wrapper(&self.parser.app.name.replace("{n}", "\n"), self.term_w)
text_wrapper(&self.cmd.get_name().replace("{n}", "\n"), self.term_w)
};
self.good(&bin_name)?;
Ok(())
@ -881,12 +1004,12 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
}
// Methods to write Parser help using templates.
impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
impl<'help, 'cmd, 'writer> Help<'help, 'cmd, 'writer> {
/// Write help to stream for the parser in the format defined by the template.
///
/// For details about the template language see [`App::help_template`].
/// For details about the template language see [`Command::help_template`].
///
/// [`App::help_template`]: App::help_template()
/// [`Command::help_template`]: Command::help_template()
fn write_templated_help(&mut self, template: &str) -> io::Result<()> {
debug!("Help::write_templated_help");
@ -928,6 +1051,9 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
for part in parts {
tags! {
match part {
"name" => {
self.write_display_name()?;
}
"bin" => {
self.write_bin_name()?;
}
@ -956,7 +1082,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
self.warning("USAGE:")?;
}
"usage" => {
self.none(Usage::new(self.parser).create_usage_no_title(&[]))?;
self.none(self.usage.create_usage_no_title(&[]))?;
}
"all-args" => {
self.write_all_args()?;
@ -964,13 +1090,13 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
"options" => {
// Include even those with a heading as we don't have a good way of
// handling help_heading in the template.
self.write_args(&self.parser.app.get_non_positionals().collect::<Vec<_>>())?;
self.write_args(&self.cmd.get_non_positionals().collect::<Vec<_>>())?;
}
"positionals" => {
self.write_args(&self.parser.app.get_positionals().collect::<Vec<_>>())?;
self.write_args(&self.cmd.get_positionals().collect::<Vec<_>>())?;
}
"subcommands" => {
self.write_subcommands(self.parser.app)?;
self.write_subcommands(self.cmd)?;
}
"after-help" => {
self.write_after_help()?;
@ -995,6 +1121,7 @@ pub(crate) fn dimensions() -> Option<(usize, usize)> {
}
const TAB: &str = " ";
const TAB_WIDTH: usize = 4;
pub(crate) enum HelpWriter<'writer> {
Normal(&'writer mut dyn Write),
@ -1003,20 +1130,22 @@ pub(crate) enum HelpWriter<'writer> {
fn should_show_arg(use_long: bool, arg: &Arg) -> bool {
debug!("should_show_arg: use_long={:?}, arg={}", use_long, arg.name);
if arg.is_set(ArgSettings::Hidden) {
if arg.is_hide_set() {
return false;
}
(!arg.is_set(ArgSettings::HiddenLongHelp) && use_long)
|| (!arg.is_set(ArgSettings::HiddenShortHelp) && !use_long)
|| arg.is_set(ArgSettings::NextLineHelp)
(!arg.is_hide_long_help_set() && use_long)
|| (!arg.is_hide_short_help_set() && !use_long)
|| arg.is_next_line_help_set()
}
fn should_show_subcommand(subcommand: &App) -> bool {
!subcommand.is_set(AppSettings::Hidden)
fn should_show_subcommand(subcommand: &Command) -> bool {
!subcommand.is_hide_set()
}
fn text_wrapper(help: &str, width: usize) -> String {
let wrapper = textwrap::Options::new(width).break_words(false);
let wrapper = textwrap::Options::new(width)
.break_words(false)
.word_splitter(textwrap::WordSplitter::NoHyphenation);
help.lines()
.map(|line| textwrap::fill(line, &wrapper))
.collect::<Vec<String>>()

294
third_party/rust/clap/src/output/usage.rs поставляемый
Просмотреть файл

@ -1,24 +1,29 @@
// std
use std::collections::BTreeMap;
use indexmap::IndexSet;
// Internal
use crate::{
build::AppSettings as AS,
build::{Arg, ArgSettings},
parse::{ArgMatcher, Parser},
util::Id,
INTERNAL_ERROR_MSG,
};
use crate::build::AppSettings as AS;
use crate::build::{Arg, ArgPredicate, Command};
use crate::parse::ArgMatcher;
use crate::util::ChildGraph;
use crate::util::Id;
use crate::INTERNAL_ERROR_MSG;
pub(crate) struct Usage<'help, 'app, 'parser> {
p: &'parser Parser<'help, 'app>,
pub(crate) struct Usage<'help, 'cmd> {
cmd: &'cmd Command<'help>,
required: Option<&'cmd ChildGraph<Id>>,
}
impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
pub(crate) fn new(p: &'parser Parser<'help, 'app>) -> Self {
Usage { p }
impl<'help, 'cmd> Usage<'help, 'cmd> {
pub(crate) fn new(cmd: &'cmd Command<'help>) -> Self {
Usage {
cmd,
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
@ -34,7 +39,7 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
// 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]) -> String {
debug!("Usage::create_usage_no_title");
if let Some(u) = self.p.app.usage_str {
if let Some(u) = self.cmd.get_override_usage() {
String::from(&*u)
} else if used.is_empty() {
self.create_help_usage(true)
@ -44,20 +49,19 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
}
// Creates a usage string for display in help messages (i.e. not for errors)
pub(crate) fn create_help_usage(&self, incl_reqs: bool) -> String {
fn create_help_usage(&self, incl_reqs: bool) -> String {
debug!("Usage::create_help_usage; incl_reqs={:?}", incl_reqs);
let mut usage = String::with_capacity(75);
let name = self
.p
.app
.usage
.as_ref()
.unwrap_or_else(|| self.p.app.bin_name.as_ref().unwrap_or(&self.p.app.name));
usage.push_str(&*name);
.cmd
.get_usage_name()
.or_else(|| self.cmd.get_bin_name())
.unwrap_or_else(|| self.cmd.get_name());
usage.push_str(name);
let req_string = if incl_reqs {
self.get_required_usage_from(&[], None, false)
.iter()
.fold(String::new(), |a, s| a + &format!(" {}", s)[..])
.fold(String::new(), |a, s| a + " " + s)
} else {
String::new()
};
@ -66,39 +70,27 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
usage.push_str(" [OPTIONS]");
}
let allow_missing_positional = self.p.app.is_set(AS::AllowMissingPositional);
let allow_missing_positional = self.cmd.is_allow_missing_positional_set();
if !allow_missing_positional {
usage.push_str(&req_string);
}
let has_last = self
.p
.app
.get_positionals()
.any(|p| p.is_set(ArgSettings::Last));
let has_last = self.cmd.get_positionals().any(|p| p.is_last_set());
// places a '--' in the usage string if there are args and options
// supporting multiple values
if self
.p
.app
.cmd
.get_non_positionals()
.any(|o| o.is_set(ArgSettings::MultipleValues))
&& self
.p
.app
.get_positionals()
.any(|p| !p.is_set(ArgSettings::Required))
&& !(self.p.app.has_visible_subcommands()
|| self.p.is_set(AS::AllowExternalSubcommands))
.any(|o| o.is_multiple_values_set())
&& self.cmd.get_positionals().any(|p| !p.is_required_set())
&& !(self.cmd.has_visible_subcommands() || self.cmd.is_allow_external_subcommands_set())
&& !has_last
{
usage.push_str(" [--]");
}
let not_req_or_hidden = |p: &Arg| {
(!p.is_set(ArgSettings::Required) || p.is_set(ArgSettings::Last))
&& !p.is_set(ArgSettings::Hidden)
};
if self.p.app.get_positionals().any(not_req_or_hidden) {
let not_req_or_hidden =
|p: &Arg| (!p.is_required_set() || p.is_last_set()) && !p.is_hide_set();
if self.cmd.get_positionals().any(not_req_or_hidden) {
if let Some(args_tag) = self.get_args_tag(incl_reqs) {
usage.push_str(&*args_tag);
} else {
@ -106,20 +98,13 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
}
if has_last && incl_reqs {
let pos = self
.p
.app
.cmd
.get_positionals()
.find(|p| p.is_set(ArgSettings::Last))
.find(|p| p.is_last_set())
.expect(INTERNAL_ERROR_MSG);
debug!("Usage::create_help_usage: '{}' has .last(true)", pos.name);
let req = pos.is_set(ArgSettings::Required);
if req
&& self
.p
.app
.get_positionals()
.any(|p| !p.is_set(ArgSettings::Required))
{
let req = pos.is_required_set();
if req && self.cmd.get_positionals().any(|p| !p.is_required_set()) {
usage.push_str(" -- <");
} else if req {
usage.push_str(" [--] <");
@ -140,14 +125,16 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
}
// incl_reqs is only false when this function is called recursively
if self.p.app.has_visible_subcommands() && incl_reqs
|| self.p.is_set(AS::AllowExternalSubcommands)
if self.cmd.has_visible_subcommands() && incl_reqs
|| self.cmd.is_allow_external_subcommands_set()
{
let placeholder = self.p.app.subcommand_value_name.unwrap_or("SUBCOMMAND");
if self.p.is_set(AS::SubcommandsNegateReqs) || self.p.is_set(AS::ArgsNegateSubcommands)
let placeholder = self.cmd.get_subcommand_value_name().unwrap_or("SUBCOMMAND");
#[allow(deprecated)]
if self.cmd.is_subcommand_negates_reqs_set()
|| self.cmd.is_args_conflicts_with_subcommands_set()
{
usage.push_str("\n ");
if !self.p.is_set(AS::ArgsNegateSubcommands) {
if !self.cmd.is_args_conflicts_with_subcommands_set() {
usage.push_str(&*self.create_help_usage(false));
} else {
usage.push_str(&*name);
@ -155,8 +142,8 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
usage.push_str(" <");
usage.push_str(placeholder);
usage.push('>');
} else if self.p.is_set(AS::SubcommandRequired)
|| self.p.is_set(AS::SubcommandRequiredElseHelp)
} else if self.cmd.is_subcommand_required_set()
|| self.cmd.is_set(AS::SubcommandRequiredElseHelp)
{
usage.push_str(" <");
usage.push_str(placeholder);
@ -167,7 +154,7 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
usage.push(']');
}
}
usage.shrink_to_fit();
let usage = usage.trim().to_owned();
debug!("Usage::create_help_usage: usage={}", usage);
usage
}
@ -181,20 +168,18 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
let r_string = self
.get_required_usage_from(used, None, true)
.iter()
.fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
.fold(String::new(), |acc, s| acc + " " + s);
usage.push_str(
&self
.p
.app
.usage
.as_ref()
.unwrap_or_else(|| self.p.app.bin_name.as_ref().unwrap_or(&self.p.app.name))[..],
self.cmd
.get_usage_name()
.or_else(|| self.cmd.get_bin_name())
.unwrap_or_else(|| self.cmd.get_name()),
);
usage.push_str(&*r_string);
if self.p.is_set(AS::SubcommandRequired) {
if self.cmd.is_subcommand_required_set() {
usage.push_str(" <");
usage.push_str(self.p.app.subcommand_value_name.unwrap_or("SUBCOMMAND"));
usage.push_str(self.cmd.get_subcommand_value_name().unwrap_or("SUBCOMMAND"));
usage.push('>');
}
usage.shrink_to_fit();
@ -206,22 +191,17 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
debug!("Usage::get_args_tag; incl_reqs = {:?}", incl_reqs);
let mut count = 0;
for pos in self
.p
.app
.cmd
.get_positionals()
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.filter(|pos| !pos.is_required_set())
.filter(|pos| !pos.is_hide_set())
.filter(|pos| !pos.is_last_set())
{
debug!("Usage::get_args_tag:iter:{}", pos.name);
let required = self.p.app.groups_for_arg(&pos.id).any(|grp_s| {
let required = self.cmd.groups_for_arg(&pos.id).any(|grp_s| {
debug!("Usage::get_args_tag:iter:{:?}:iter:{:?}", pos.name, grp_s);
// if it's part of a required group we don't want to count it
self.p
.app
.groups
.iter()
.any(|g| g.required && (g.id == grp_s))
self.cmd.get_groups().any(|g| g.required && (g.id == grp_s))
});
if !required {
count += 1;
@ -232,28 +212,23 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
}
}
if !self.p.is_set(AS::DontCollapseArgsInUsage) && count > 1 {
if !self.cmd.is_dont_collapse_args_in_usage_set() && count > 1 {
debug!("Usage::get_args_tag:iter: More than one, returning [ARGS]");
// [ARGS]
None
} else if count == 1 && incl_reqs {
let pos = self
.p
.app
.cmd
.get_positionals()
.find(|pos| {
!pos.is_set(ArgSettings::Required)
&& !pos.is_set(ArgSettings::Hidden)
&& !pos.is_set(ArgSettings::Last)
&& !self.p.app.groups_for_arg(&pos.id).any(|grp_s| {
!pos.is_required_set()
&& !pos.is_hide_set()
&& !pos.is_last_set()
&& !self.cmd.groups_for_arg(&pos.id).any(|grp_s| {
debug!("Usage::get_args_tag:iter:{:?}:iter:{:?}", pos.name, grp_s);
// if it's part of a required group we don't want to count it
self.p
.app
.groups
.iter()
.any(|g| g.required && (g.id == grp_s))
self.cmd.get_groups().any(|g| g.required && (g.id == grp_s))
})
})
.expect(INTERNAL_ERROR_MSG);
@ -268,18 +243,17 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
pos.name_no_brackets(),
pos.multiple_str()
))
} else if self.p.is_set(AS::DontCollapseArgsInUsage)
&& self.p.app.has_positionals()
} else if self.cmd.is_dont_collapse_args_in_usage_set()
&& self.cmd.has_positionals()
&& incl_reqs
{
debug!("Usage::get_args_tag:iter: Don't collapse returning all");
Some(
self.p
.app
self.cmd
.get_positionals()
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.filter(|pos| !pos.is_required_set())
.filter(|pos| !pos.is_hide_set())
.filter(|pos| !pos.is_last_set())
.map(|pos| format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str()))
.collect::<Vec<_>>()
.join(""),
@ -287,26 +261,24 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
} else if !incl_reqs {
debug!("Usage::get_args_tag:iter: incl_reqs=false, building secondary usage string");
let highest_req_pos = self
.p
.app
.cmd
.get_positionals()
.filter_map(|pos| {
if pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Last) {
if pos.is_required_set() && !pos.is_last_set() {
Some(pos.index)
} else {
None
}
})
.max()
.unwrap_or_else(|| Some(self.p.app.get_positionals().count()));
.unwrap_or_else(|| Some(self.cmd.get_positionals().count()));
Some(
self.p
.app
self.cmd
.get_positionals()
.filter(|pos| pos.index <= highest_req_pos)
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.filter(|pos| !pos.is_required_set())
.filter(|pos| !pos.is_hide_set())
.filter(|pos| !pos.is_last_set())
.map(|pos| format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str()))
.collect::<Vec<_>>()
.join(""),
@ -319,7 +291,7 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
// 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.p.app.get_non_positionals() {
'outer: for f in self.cmd.get_non_positionals() {
debug!("Usage::needs_options_tag:iter: f={}", f.name);
// Don't print `[OPTIONS]` just for help or version
@ -328,23 +300,17 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
continue;
}
if f.is_set(ArgSettings::Hidden) {
if f.is_hide_set() {
debug!("Usage::needs_options_tag:iter Option is hidden");
continue;
}
if f.is_set(ArgSettings::Required) {
if f.is_required_set() {
debug!("Usage::needs_options_tag:iter Option is required");
continue;
}
for grp_s in self.p.app.groups_for_arg(&f.id) {
for grp_s in self.cmd.groups_for_arg(&f.id) {
debug!("Usage::needs_options_tag:iter:iter: grp_s={:?}", grp_s);
if self
.p
.app
.groups
.iter()
.any(|g| g.id == grp_s && g.required)
{
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;
}
@ -367,24 +333,44 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
incls: &[Id],
matcher: Option<&ArgMatcher>,
incl_last: bool,
) -> Vec<String> {
) -> IndexSet<String> {
debug!(
"Usage::get_required_usage_from: incls={:?}, matcher={:?}, incl_last={:?}",
incls,
matcher.is_some(),
incl_last
);
let mut ret_val = Vec::new();
let mut ret_val = IndexSet::new();
let mut unrolled_reqs = IndexSet::new();
for a in self.p.required.iter() {
if let Some(m) = matcher {
for aa in self.p.app.unroll_requirements_for_arg(a, m) {
// if we don't check for duplicates here this causes duplicate error messages
// see https://github.com/clap-rs/clap/issues/2770
unrolled_reqs.insert(aa);
}
let required_owned;
let required = if let Some(required) = self.required {
required
} else {
required_owned = self.cmd.required_graph();
&required_owned
};
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.insert(aa);
}
// always include the required arg itself. it will not be enumerated
// by unroll_requirements_for_arg.
@ -397,36 +383,33 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
);
let args_in_groups = self
.p
.app
.groups
.iter()
.filter(|gn| self.p.required.contains(&gn.id))
.flat_map(|g| self.p.app.unroll_args_in_group(&g.id))
.cmd
.get_groups()
.filter(|gn| required.contains(&gn.id))
.flat_map(|g| self.cmd.unroll_args_in_group(&g.id))
.collect::<Vec<_>>();
for a in unrolled_reqs
.iter()
.chain(incls.iter())
.filter(|name| !self.p.app.get_positionals().any(|p| &&p.id == name))
.filter(|name| !self.p.app.groups.iter().any(|g| &&g.id == name))
.filter(|name| !self.cmd.get_positionals().any(|p| &&p.id == name))
.filter(|name| !self.cmd.get_groups().any(|g| &&g.id == name))
.filter(|name| !args_in_groups.contains(name))
.filter(|name| !(matcher.is_some() && matcher.as_ref().unwrap().contains(name)))
{
debug!("Usage::get_required_usage_from:iter:{:?}", a);
let arg = self.p.app.find(a).expect(INTERNAL_ERROR_MSG).to_string();
ret_val.push(arg);
let arg = self.cmd.find(a).expect(INTERNAL_ERROR_MSG).to_string();
ret_val.insert(arg);
}
let mut g_vec: Vec<String> = vec![];
for g in unrolled_reqs
.iter()
.filter(|n| self.p.app.groups.iter().any(|g| g.id == **n))
.filter(|n| self.cmd.get_groups().any(|g| g.id == **n))
{
// don't print requirement for required groups that have an arg.
if let Some(m) = matcher {
let have_group_entry = self
.p
.app
.cmd
.unroll_args_in_group(g)
.iter()
.any(|arg| m.contains(arg));
@ -435,28 +418,29 @@ impl<'help, 'app, 'parser> Usage<'help, 'app, 'parser> {
}
}
let elem = self.p.app.format_group(g);
let elem = self.cmd.format_group(g);
if !g_vec.contains(&elem) {
g_vec.push(elem);
}
}
ret_val.extend_from_slice(&g_vec);
ret_val.extend(g_vec);
let pmap = unrolled_reqs
let mut pvec = unrolled_reqs
.iter()
.chain(incls.iter())
.filter(|a| self.p.app.get_positionals().any(|p| &&p.id == a))
.filter(|a| self.cmd.get_positionals().any(|p| &&p.id == a))
.filter(|&pos| matcher.map_or(true, |m| !m.contains(pos)))
.filter_map(|pos| self.p.app.find(pos))
.filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
.filter_map(|pos| self.cmd.find(pos))
.filter(|&pos| incl_last || !pos.is_last_set())
.filter(|pos| !args_in_groups.contains(&pos.id))
.map(|pos| (pos.index.unwrap(), pos))
.collect::<BTreeMap<usize, &Arg>>(); // sort by index
.collect::<Vec<(usize, &Arg)>>();
pvec.sort_by_key(|(ind, _)| *ind); // sort by index
for p in pmap.values() {
debug!("Usage::get_required_usage_from:iter:{:?}", p.id);
for (_, p) in pvec {
debug!("Usage::get_required_usage_from:push:{:?}", p.id);
if !args_in_groups.contains(&p.id) {
ret_val.push(p.to_string());
ret_val.insert(p.to_string());
}
}

Просмотреть файл

@ -3,8 +3,8 @@ use std::{collections::HashMap, ffi::OsString, mem, ops::Deref};
// Internal
use crate::{
build::{App, Arg, ArgSettings},
parse::{ArgMatches, MatchedArg, SubCommand, ValueType},
build::{Arg, ArgPredicate, Command},
parse::{ArgMatches, MatchedArg, SubCommand, ValueSource},
util::Id,
};
@ -12,25 +12,29 @@ use crate::{
use indexmap::map::Entry;
#[derive(Debug, Default)]
pub(crate) struct ArgMatcher(pub(crate) ArgMatches);
pub(crate) struct ArgMatcher(ArgMatches);
impl ArgMatcher {
pub(crate) fn new(_app: &App) -> Self {
pub(crate) fn new(_cmd: &Command) -> Self {
ArgMatcher(ArgMatches {
#[cfg(debug_assertions)]
valid_args: {
let args = _app.args.args().map(|a| a.id.clone());
let groups = _app.groups.iter().map(|g| g.id.clone());
let args = _cmd.get_arguments().map(|a| a.id.clone());
let groups = _cmd.get_groups().map(|g| g.id.clone());
args.chain(groups).collect()
},
#[cfg(debug_assertions)]
valid_subcommands: _app.subcommands.iter().map(|sc| sc.id.clone()).collect(),
valid_subcommands: _cmd.get_subcommands().map(|sc| sc.get_id()).collect(),
// HACK: Allow an external subcommand's ArgMatches be a stand-in for any ArgMatches
// since users can't detect it and avoid the asserts.
//
// See clap-rs/clap#3263
#[cfg(debug_assertions)]
disable_asserts: _app.is_set(crate::AppSettings::AllowExternalSubcommands),
#[cfg(not(feature = "unstable-v4"))]
disable_asserts: _cmd.is_allow_external_subcommands_set(),
#[cfg(debug_assertions)]
#[cfg(feature = "unstable-v4")]
disable_asserts: false,
..Default::default()
})
}
@ -62,14 +66,15 @@ impl ArgMatcher {
// a default value of `other` myprog would have an existing MatchedArg for
// --global-arg where the value is `other`, however the occurs will be 0.
let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
if parent_ma.occurs > 0 && ma.occurs == 0 {
parent_ma.clone()
if parent_ma.get_occurrences() > 0 && ma.get_occurrences() == 0 {
parent_ma
} else {
ma.clone()
ma
}
} else {
ma.clone()
};
ma
}
.clone();
vals_map.insert(global_arg.clone(), to_update);
}
}
@ -84,6 +89,7 @@ impl ArgMatcher {
}
}
#[cfg(not(feature = "unstable-v4"))]
pub(crate) fn get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg> {
self.0.args.get_mut(arg)
}
@ -100,17 +106,6 @@ impl ArgMatcher {
self.0.args.contains_key(arg)
}
pub(crate) fn contains_explicit(&self, arg: &Id) -> bool {
self.0
.args
.get(arg)
.map_or(false, |a| a.ty != ValueType::DefaultValue)
}
pub(crate) fn is_empty(&self) -> bool {
self.0.args.is_empty()
}
pub(crate) fn arg_names(&self) -> indexmap::map::Keys<Id, MatchedArg> {
self.0.args.keys()
}
@ -131,24 +126,41 @@ impl ArgMatcher {
self.0.args.iter()
}
pub(crate) fn check_explicit<'a>(&self, arg: &Id, predicate: ArgPredicate<'a>) -> bool {
self.get(arg).map_or(false, |a| a.check_explicit(predicate))
}
pub(crate) fn inc_occurrence_of_arg(&mut self, arg: &Arg) {
let id = &arg.id;
debug!("ArgMatcher::inc_occurrence_of_arg: id={:?}", id);
let ma = self.entry(id).or_insert(MatchedArg::new());
ma.set_ty(ValueType::CommandLine);
ma.set_ignore_case(arg.is_set(ArgSettings::IgnoreCase));
ma.invalid_utf8_allowed(arg.is_set(ArgSettings::AllowInvalidUtf8));
ma.occurs += 1;
ma.update_ty(ValueSource::CommandLine);
ma.set_ignore_case(arg.is_ignore_case_set());
ma.invalid_utf8_allowed(arg.is_allow_invalid_utf8_set());
ma.inc_occurrences();
}
pub(crate) fn inc_occurrence_of_group(&mut self, id: &Id) {
debug!("ArgMatcher::inc_occurrence_of_group: id={:?}", id);
let ma = self.entry(id).or_insert(MatchedArg::new());
ma.set_ty(ValueType::CommandLine);
ma.occurs += 1;
ma.update_ty(ValueSource::CommandLine);
ma.inc_occurrences();
}
pub(crate) fn add_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType, append: bool) {
#[cfg(feature = "unstable-v4")]
pub(crate) fn inc_occurrence_of_external(&mut self, allow_invalid_utf8: bool) {
let id = &Id::empty_hash();
debug!(
"ArgMatcher::inc_occurrence_of_external: id={:?}, allow_invalid_utf8={}",
id, allow_invalid_utf8
);
let ma = self.entry(id).or_insert(MatchedArg::new());
ma.update_ty(ValueSource::CommandLine);
ma.invalid_utf8_allowed(allow_invalid_utf8);
ma.inc_occurrences();
}
pub(crate) fn add_val_to(&mut self, arg: &Id, val: OsString, ty: ValueSource, append: bool) {
if append {
self.append_val_to(arg, val, ty);
} else {
@ -156,18 +168,18 @@ impl ArgMatcher {
}
}
fn push_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType) {
fn push_val_to(&mut self, arg: &Id, val: OsString, ty: ValueSource) {
// We will manually inc occurrences later(for flexibility under
// specific circumstances, like only add one occurrence for flag
// when we met: `--flag=one,two`).
let ma = self.entry(arg).or_default();
ma.set_ty(ty);
ma.update_ty(ty);
ma.push_val(val);
}
fn append_val_to(&mut self, arg: &Id, val: OsString, ty: ValueType) {
fn append_val_to(&mut self, arg: &Id, val: OsString, ty: ValueSource) {
let ma = self.entry(arg).or_default();
ma.set_ty(ty);
ma.update_ty(ty);
ma.append_val(val);
}
@ -176,9 +188,9 @@ impl ArgMatcher {
ma.new_val_group();
}
pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize, ty: ValueType) {
pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize, ty: ValueSource) {
let ma = self.entry(arg).or_default();
ma.set_ty(ty);
ma.update_ty(ty);
ma.push_index(idx);
}
@ -195,7 +207,7 @@ impl ArgMatcher {
let current_num = ma.num_vals();
if let Some(num) = o.num_vals {
debug!("ArgMatcher::needs_more_vals: num_vals...{}", num);
return if o.is_set(ArgSettings::MultipleOccurrences) {
return if o.is_multiple_occurrences_set() {
(current_num % num) != 0
} else {
num != current_num
@ -207,7 +219,7 @@ impl ArgMatcher {
debug!("ArgMatcher::needs_more_vals: min_vals...true");
return true;
}
return o.is_set(ArgSettings::MultipleValues);
return o.is_multiple_values_set();
}
true
}

1242
third_party/rust/clap/src/parse/errors.rs поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -2,7 +2,7 @@
use std::cmp::Ordering;
// Internal
use crate::build::App;
use crate::build::Command;
/// Produces multiple strings from a given list of possible values which are similar
/// to the passed in value `v` within a certain confidence by least confidence.
@ -33,13 +33,14 @@ where
}
/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
pub(crate) fn did_you_mean_flag<I, T>(
pub(crate) fn did_you_mean_flag<'a, 'help, I, T>(
arg: &str,
remaining_args: &[&str],
longs: I,
subcommands: &mut [App],
subcommands: impl IntoIterator<Item = &'a mut Command<'help>>,
) -> Option<(String, Option<String>)>
where
'help: 'a,
T: AsRef<str>,
I: IntoIterator<Item = T>,
{
@ -48,11 +49,11 @@ where
match did_you_mean(arg, longs).pop() {
Some(candidate) => Some((candidate, None)),
None => subcommands
.iter_mut()
.into_iter()
.filter_map(|subcommand| {
subcommand._build();
subcommand._build_self();
let longs = subcommand.args.keys().filter_map(|a| {
let longs = subcommand.get_keymap().keys().filter_map(|a| {
if let KeyType::Long(v) = a {
Some(v.to_string_lossy().into_owned())
} else {

Просмотреть файл

@ -12,23 +12,22 @@ use std::{
use indexmap::IndexMap;
// Internal
use crate::{
parse::MatchedArg,
util::{Id, Key},
{Error, INVALID_UTF8},
};
use crate::parse::MatchedArg;
use crate::parse::ValueSource;
use crate::util::{Id, Key};
use crate::{Error, INVALID_UTF8};
/// Container for parse results.
///
/// Used to get information about the arguments that were supplied to the program at runtime by
/// the user. New instances of this struct are obtained by using the [`App::get_matches`] family of
/// the user. New instances of this struct are obtained by using the [`Command::get_matches`] family of
/// methods.
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg};
/// let matches = App::new("MyApp")
/// # use clap::{Command, Arg};
/// let matches = Command::new("MyApp")
/// .arg(Arg::new("out")
/// .long("output")
/// .required(true)
@ -66,7 +65,7 @@ use crate::{
/// }
/// }
/// ```
/// [`App::get_matches`]: crate::App::get_matches()
/// [`Command::get_matches`]: crate::Command::get_matches()
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ArgMatches {
#[cfg(debug_assertions)]
@ -80,6 +79,29 @@ pub struct ArgMatches {
}
impl ArgMatches {
/// Check if any args were present on the command line
///
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg};
/// let mut cmd = Command::new("myapp")
/// .arg(Arg::new("output")
/// .takes_value(true));
///
/// let m = cmd
/// .try_get_matches_from_mut(vec!["myapp", "something"])
/// .unwrap();
/// assert!(m.args_present());
///
/// let m = cmd
/// .try_get_matches_from_mut(vec!["myapp"])
/// .unwrap();
/// assert!(! m.args_present());
pub fn args_present(&self) -> bool {
!self.args.is_empty()
}
/// Gets the value of a specific option or positional argument.
///
/// i.e. an argument that [takes an additional value][crate::Arg::takes_value] at runtime.
@ -103,8 +125,8 @@ impl ArgMatches {
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myapp")
/// # use clap::{Command, Arg};
/// let m = Command::new("myapp")
/// .arg(Arg::new("output")
/// .takes_value(true))
/// .get_matches_from(vec!["myapp", "something"]);
@ -116,6 +138,7 @@ impl ArgMatches {
/// [`ArgMatches::values_of`]: ArgMatches::values_of()
/// [`default_value`]: crate::Arg::default_value()
/// [`occurrences_of`]: crate::ArgMatches::occurrences_of()
#[cfg_attr(debug_assertions, track_caller)]
pub fn value_of<T: Key>(&self, id: T) -> Option<&str> {
let id = Id::from(id);
let arg = self.get_arg(&id)?;
@ -150,11 +173,11 @@ impl ArgMatches {
///
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, arg};
/// # use clap::{Command, arg};
/// use std::ffi::OsString;
/// use std::os::unix::ffi::{OsStrExt,OsStringExt};
///
/// let m = App::new("utf8")
/// let m = Command::new("utf8")
/// .arg(arg!(<arg> "some arg")
/// .allow_invalid_utf8(true))
/// .get_matches_from(vec![OsString::from("myprog"),
@ -201,11 +224,11 @@ impl ArgMatches {
///
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, arg};
/// # use clap::{Command, arg};
/// use std::ffi::OsString;
/// use std::os::unix::ffi::{OsStrExt,OsStringExt};
///
/// let m = App::new("utf8")
/// let m = Command::new("utf8")
/// .arg(arg!(<arg> "some arg")
/// .allow_invalid_utf8(true))
/// .get_matches_from(vec![OsString::from("myprog"),
@ -241,8 +264,8 @@ impl ArgMatches {
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myprog")
/// # use clap::{Command, Arg};
/// let m = Command::new("myprog")
/// .arg(Arg::new("output")
/// .multiple_occurrences(true)
/// .short('o')
@ -255,6 +278,7 @@ impl ArgMatches {
/// ```
/// [values]: Values
/// [`Iterator`]: std::iter::Iterator
#[cfg_attr(debug_assertions, track_caller)]
pub fn values_of<T: Key>(&self, id: T) -> Option<Values> {
let id = Id::from(id);
let arg = self.get_arg(&id)?;
@ -269,8 +293,41 @@ impl ArgMatches {
Some(v)
}
/// Placeholder documentation.
/// Get an [`Iterator`] over groups of values of a specific option.
///
/// specifically grouped by the occurrences of the options.
///
/// Each group is a `Vec<&str>` containing the arguments passed to a single occurrence
/// of the option.
///
/// If the option doesn't support multiple occurrences, or there was only a single occurrence,
/// the iterator will only contain a single item.
///
/// Returns `None` if the option wasn't present.
///
/// # Panics
///
/// If the value is invalid UTF-8.
///
/// If `id` is not a valid argument or group name.
///
/// # Examples
/// ```rust
/// # use clap::{Command,Arg};
/// let m = Command::new("myprog")
/// .arg(Arg::new("exec")
/// .short('x')
/// .min_values(1)
/// .multiple_occurrences(true)
/// .value_terminator(";"))
/// .get_matches_from(vec![
/// "myprog", "-x", "echo", "hi", ";", "-x", "echo", "bye"]);
/// let vals: Vec<Vec<&str>> = m.grouped_values_of("exec").unwrap().collect();
/// assert_eq!(vals, [["echo", "hi"], ["echo", "bye"]]);
/// ```
/// [`Iterator`]: std::iter::Iterator
#[cfg(feature = "unstable-grouped")]
#[cfg_attr(debug_assertions, track_caller)]
pub fn grouped_values_of<T: Key>(&self, id: T) -> Option<GroupedValues> {
let id = Id::from(id);
let arg = self.get_arg(&id)?;
@ -303,11 +360,11 @@ impl ArgMatches {
///
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, arg};
/// # use clap::{Command, arg};
/// use std::ffi::OsString;
/// use std::os::unix::ffi::OsStringExt;
///
/// let m = App::new("utf8")
/// let m = Command::new("utf8")
/// .arg(arg!(<arg> ... "some arg")
/// .allow_invalid_utf8(true))
/// .get_matches_from(vec![OsString::from("myprog"),
@ -352,11 +409,11 @@ impl ArgMatches {
///
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, arg};
/// # use clap::{Command, arg};
/// use std::ffi::{OsStr,OsString};
/// use std::os::unix::ffi::{OsStrExt,OsStringExt};
///
/// let m = App::new("utf8")
/// let m = Command::new("utf8")
/// .arg(arg!(<arg> ... "some arg")
/// .allow_invalid_utf8(true))
/// .get_matches_from(vec![OsString::from("myprog"),
@ -408,8 +465,8 @@ impl ArgMatches {
/// # Examples
///
/// ```
/// # use clap::{App, arg};
/// let matches = App::new("myapp")
/// # use clap::{Command, arg};
/// let matches = Command::new("myapp")
/// .arg(arg!([length] "Set the length to use as a pos whole num i.e. 20"))
/// .get_matches_from(&["test", "12"]);
///
@ -440,7 +497,7 @@ impl ArgMatches {
v, name, e
);
Error::value_validation_without_app(name.to_string(), v.to_string(), message.into())
Error::value_validation(name.to_string(), v.to_string(), message.into())
})
}
@ -458,8 +515,8 @@ impl ArgMatches {
/// # Examples
///
/// ```
/// # use clap::{App, arg};
/// let matches = App::new("myapp")
/// # use clap::{Command, arg};
/// let matches = Command::new("myapp")
/// .arg(arg!([length] "Set the length to use as a pos whole num i.e. 20"))
/// .get_matches_from(&["test", "12"]);
///
@ -501,8 +558,8 @@ impl ArgMatches {
/// # Examples
///
/// ```
/// # use clap::{App, arg};
/// let matches = App::new("myapp")
/// # use clap::{Command, arg};
/// let matches = Command::new("myapp")
/// .arg(arg!([length] ... "A sequence of integers because integers are neat!"))
/// .get_matches_from(&["test", "12", "77", "40"]);
///
@ -528,7 +585,7 @@ impl ArgMatches {
v.parse::<R>().map_err(|e| {
let message = format!("The argument '{}' isn't a valid value: {}", v, e);
Error::value_validation_without_app(name.to_string(), v.to_string(), message.into())
Error::value_validation(name.to_string(), v.to_string(), message.into())
})
})
.collect()
@ -548,8 +605,8 @@ impl ArgMatches {
/// # Examples
///
/// ```
/// # use clap::{App, arg};
/// let matches = App::new("myapp")
/// # use clap::{Command, arg};
/// let matches = Command::new("myapp")
/// .arg(arg!([length] ... "A sequence of integers because integers are neat!"))
/// .get_matches_from(&["test", "12", "77", "40"]);
///
@ -582,8 +639,8 @@ impl ArgMatches {
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myprog")
/// # use clap::{Command, Arg};
/// let m = Command::new("myprog")
/// .arg(Arg::new("debug")
/// .short('d'))
/// .get_matches_from(vec![
@ -604,6 +661,36 @@ impl ArgMatches {
self.args.contains_key(&id)
}
/// Report where argument value came from
///
/// # Panics
///
/// If `id` is is not a valid argument or group name.
///
/// # Examples
///
/// ```rust
/// # use clap::{Command, Arg, ValueSource};
/// let m = Command::new("myprog")
/// .arg(Arg::new("debug")
/// .short('d'))
/// .get_matches_from(vec![
/// "myprog", "-d"
/// ]);
///
/// assert_eq!(m.value_source("debug"), Some(ValueSource::CommandLine));
/// ```
///
/// [`default_value`]: crate::Arg::default_value()
/// [`occurrences_of`]: ArgMatches::occurrences_of()
pub fn value_source<T: Key>(&self, id: T) -> Option<ValueSource> {
let id = Id::from(id);
let value = self.get_arg(&id);
value.and_then(MatchedArg::source)
}
/// The number of times an argument was used at runtime.
///
/// If an argument isn't present it will return `0`.
@ -619,8 +706,8 @@ impl ArgMatches {
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myprog")
/// # use clap::{Command, Arg};
/// let m = Command::new("myprog")
/// .arg(Arg::new("debug")
/// .short('d')
/// .multiple_occurrences(true))
@ -634,8 +721,8 @@ impl ArgMatches {
/// This next example shows that counts actual uses of the argument, not just `-`'s
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myprog")
/// # use clap::{Command, Arg};
/// let m = Command::new("myprog")
/// .arg(Arg::new("debug")
/// .short('d')
/// .multiple_occurrences(true))
@ -649,7 +736,8 @@ impl ArgMatches {
/// assert_eq!(m.occurrences_of("flag"), 1);
/// ```
pub fn occurrences_of<T: Key>(&self, id: T) -> u64 {
self.get_arg(&Id::from(id)).map_or(0, |a| a.occurs)
self.get_arg(&Id::from(id))
.map_or(0, |a| a.get_occurrences())
}
/// The first index of that an argument showed up.
@ -681,8 +769,8 @@ impl ArgMatches {
/// in an `ArgMatches` struct for querying.
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myapp")
/// # use clap::{Command, Arg};
/// let m = Command::new("myapp")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("option")
@ -699,8 +787,8 @@ impl ArgMatches {
/// Now notice, if we use one of the other styles of options:
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myapp")
/// # use clap::{Command, Arg};
/// let m = Command::new("myapp")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("option")
@ -718,8 +806,8 @@ impl ArgMatches {
/// flags. Let's also throw in the final option style for good measure.
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myapp")
/// # use clap::{Command, Arg};
/// let m = Command::new("myapp")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("flag2")
@ -744,8 +832,8 @@ impl ArgMatches {
/// One final combination of flags/options to see how they combine:
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myapp")
/// # use clap::{Command, Arg};
/// let m = Command::new("myapp")
/// .arg(Arg::new("flag")
/// .short('f'))
/// .arg(Arg::new("flag2")
@ -770,11 +858,11 @@ impl ArgMatches {
/// The last part to mention is when values are sent in multiple groups with a [delimiter].
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myapp")
/// # use clap::{Command, Arg};
/// let m = Command::new("myapp")
/// .arg(Arg::new("option")
/// .short('o')
/// .use_delimiter(true)
/// .use_value_delimiter(true)
/// .multiple_values(true))
/// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
/// // ARGV indices: ^0 ^1
@ -811,11 +899,11 @@ impl ArgMatches {
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myapp")
/// # use clap::{Command, Arg};
/// let m = Command::new("myapp")
/// .arg(Arg::new("option")
/// .short('o')
/// .use_delimiter(true)
/// .use_value_delimiter(true)
/// .multiple_values(true))
/// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
/// // ARGV indices: ^0 ^1
@ -829,8 +917,8 @@ impl ArgMatches {
/// Another quick example is when flags and options are used together
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myapp")
/// # use clap::{Command, Arg};
/// let m = Command::new("myapp")
/// .arg(Arg::new("option")
/// .short('o')
/// .takes_value(true)
@ -852,8 +940,8 @@ impl ArgMatches {
/// index.
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myapp")
/// # use clap::{Command, Arg};
/// let m = Command::new("myapp")
/// .arg(Arg::new("option")
/// .short('o')
/// .takes_value(true)
@ -886,11 +974,11 @@ impl ArgMatches {
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg, };
/// let app_m = App::new("git")
/// .subcommand(App::new("clone"))
/// .subcommand(App::new("push"))
/// .subcommand(App::new("commit"))
/// # use clap::{Command, Arg, };
/// let app_m = Command::new("git")
/// .subcommand(Command::new("clone"))
/// .subcommand(Command::new("push"))
/// .subcommand(Command::new("commit"))
/// .get_matches();
///
/// match app_m.subcommand() {
@ -906,10 +994,10 @@ impl ArgMatches {
/// with pattern matching!
///
/// ```rust
/// # use clap::{App, AppSettings};
/// # use clap::Command;
/// // Assume there is an external subcommand named "subcmd"
/// let app_m = App::new("myprog")
/// .setting(AppSettings::AllowExternalSubcommands)
/// let app_m = Command::new("myprog")
/// .allow_external_subcommands(true)
/// .get_matches_from(vec![
/// "myprog", "subcmd", "--option", "value", "-fff", "--flag"
/// ]);
@ -925,7 +1013,7 @@ impl ArgMatches {
/// _ => {},
/// }
/// ```
/// [subcommand]: crate::App::subcommand
/// [subcommand]: crate::Command::subcommand
#[inline]
pub fn subcommand(&self) -> Option<(&str, &ArgMatches)> {
self.subcommand.as_ref().map(|sc| (&*sc.name, &sc.matches))
@ -944,11 +1032,11 @@ impl ArgMatches {
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, };
/// let app_m = App::new("myprog")
/// # use clap::{Command, Arg, };
/// let app_m = Command::new("myprog")
/// .arg(Arg::new("debug")
/// .short('d'))
/// .subcommand(App::new("test")
/// .subcommand(Command::new("test")
/// .arg(Arg::new("opt")
/// .long("option")
/// .takes_value(true)))
@ -966,8 +1054,8 @@ impl ArgMatches {
/// }
/// ```
///
/// [subcommand]: crate::App::subcommand
/// [`App`]: crate::App
/// [subcommand]: crate::Command::subcommand
/// [`Command`]: crate::Command
pub fn subcommand_matches<T: Key>(&self, id: T) -> Option<&ArgMatches> {
self.get_subcommand(&id.into()).map(|sc| &sc.matches)
}
@ -979,11 +1067,11 @@ impl ArgMatches {
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg, };
/// let app_m = App::new("git")
/// .subcommand(App::new("clone"))
/// .subcommand(App::new("push"))
/// .subcommand(App::new("commit"))
/// # use clap::{Command, Arg, };
/// let app_m = Command::new("git")
/// .subcommand(Command::new("clone"))
/// .subcommand(Command::new("push"))
/// .subcommand(Command::new("commit"))
/// .get_matches();
///
/// match app_m.subcommand_name() {
@ -993,8 +1081,8 @@ impl ArgMatches {
/// _ => {}, // Either no subcommand or one not tested for...
/// }
/// ```
/// [subcommand]: crate::App::subcommand
/// [`App`]: crate::App
/// [subcommand]: crate::Command::subcommand
/// [`Command`]: crate::Command
#[inline]
pub fn subcommand_name(&self) -> Option<&str> {
self.subcommand.as_ref().map(|sc| &*sc.name)
@ -1111,8 +1199,8 @@ pub(crate) struct SubCommand {
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myapp")
/// # use clap::{Command, Arg};
/// let m = Command::new("myapp")
/// .arg(Arg::new("output")
/// .short('o')
/// .multiple_occurrences(true)
@ -1126,8 +1214,7 @@ pub(crate) struct SubCommand {
/// assert_eq!(values.next(), None);
/// ```
/// [`ArgMatches::values_of`]: ArgMatches::values_of()
#[derive(Clone)]
#[allow(missing_debug_implementations)]
#[derive(Clone, Debug)]
pub struct Values<'a> {
#[allow(clippy::type_complexity)]
iter: Map<Flatten<Iter<'a, Vec<OsString>>>, for<'r> fn(&'r OsString) -> &'r str>,
@ -1208,11 +1295,11 @@ impl<'a> Default for GroupedValues<'a> {
///
#[cfg_attr(not(unix), doc = " ```ignore")]
#[cfg_attr(unix, doc = " ```")]
/// # use clap::{App, arg};
/// # use clap::{Command, arg};
/// use std::ffi::OsString;
/// use std::os::unix::ffi::{OsStrExt,OsStringExt};
///
/// let m = App::new("utf8")
/// let m = Command::new("utf8")
/// .arg(arg!(<arg> "some arg")
/// .allow_invalid_utf8(true))
/// .get_matches_from(vec![OsString::from("myprog"),
@ -1221,8 +1308,7 @@ impl<'a> Default for GroupedValues<'a> {
/// assert_eq!(&*m.value_of_os("arg").unwrap().as_bytes(), [b'H', b'i', b' ', 0xe9, b'!']);
/// ```
/// [`ArgMatches::values_of_os`]: ArgMatches::values_of_os()
#[derive(Clone)]
#[allow(missing_debug_implementations)]
#[derive(Clone, Debug)]
pub struct OsValues<'a> {
#[allow(clippy::type_complexity)]
iter: Map<Flatten<Iter<'a, Vec<OsString>>>, fn(&OsString) -> &OsStr>,
@ -1264,8 +1350,8 @@ impl Default for OsValues<'_> {
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("myapp")
/// # use clap::{Command, Arg};
/// let m = Command::new("myapp")
/// .arg(Arg::new("output")
/// .short('o')
/// .multiple_values(true)
@ -1279,8 +1365,7 @@ impl Default for OsValues<'_> {
/// assert_eq!(indices.next(), None);
/// ```
/// [`ArgMatches::indices_of`]: ArgMatches::indices_of()
#[derive(Clone)]
#[allow(missing_debug_implementations)]
#[derive(Clone, Debug)]
pub struct Indices<'a> {
iter: Cloned<Iter<'a, usize>>,
len: usize,
@ -1382,7 +1467,7 @@ mod tests {
#[test]
fn values_exact_size() {
let l = crate::App::new("test")
let l = crate::Command::new("test")
.arg(
crate::Arg::new("POTATO")
.takes_value(true)
@ -1399,7 +1484,7 @@ mod tests {
#[test]
fn os_values_exact_size() {
let l = crate::App::new("test")
let l = crate::Command::new("test")
.arg(
crate::Arg::new("POTATO")
.takes_value(true)
@ -1417,7 +1502,7 @@ mod tests {
#[test]
fn indices_exact_size() {
let l = crate::App::new("test")
let l = crate::Command::new("test")
.arg(
crate::Arg::new("POTATO")
.takes_value(true)

Просмотреть файл

@ -5,13 +5,15 @@ use std::{
slice::Iter,
};
use crate::build::ArgPredicate;
use crate::parse::ValueSource;
use crate::util::eq_ignore_case;
use crate::INTERNAL_ERROR_MSG;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct MatchedArg {
pub(crate) occurs: u64,
pub(crate) ty: ValueType,
occurs: u64,
ty: Option<ValueSource>,
indices: Vec<usize>,
vals: Vec<Vec<OsString>>,
ignore_case: bool,
@ -22,7 +24,7 @@ impl MatchedArg {
pub(crate) fn new() -> Self {
MatchedArg {
occurs: 0,
ty: ValueType::Unknown,
ty: None,
indices: Vec::new(),
vals: Vec::new(),
ignore_case: false,
@ -30,6 +32,14 @@ impl MatchedArg {
}
}
pub(crate) fn inc_occurrences(&mut self) {
self.occurs += 1;
}
pub(crate) fn get_occurrences(&self) -> u64 {
self.occurs
}
pub(crate) fn indices(&self) -> Cloned<Iter<'_, usize>> {
self.indices.iter().cloned()
}
@ -108,19 +118,34 @@ impl MatchedArg {
}
}
pub(crate) fn contains_val(&self, val: &str) -> bool {
self.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
v.to_str().map_or(false, |v| eq_ignore_case(v, val))
} else {
OsString::as_os_str(v) == OsStr::new(val)
}
})
pub(crate) fn check_explicit(&self, predicate: ArgPredicate) -> bool {
if self.ty == Some(ValueSource::DefaultValue) {
return false;
}
match predicate {
ArgPredicate::Equals(val) => self.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 set_ty(&mut self, ty: ValueType) {
self.ty = ty;
pub(crate) fn source(&self) -> Option<ValueSource> {
self.ty
}
pub(crate) fn update_ty(&mut self, ty: ValueSource) {
if let Some(existing) = self.ty {
self.ty = Some(existing.max(ty));
} else {
self.ty = Some(ty)
}
}
pub(crate) fn set_ignore_case(&mut self, yes: bool) {
@ -142,15 +167,6 @@ impl Default for MatchedArg {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ValueType {
Unknown,
#[cfg(feature = "env")]
EnvVariable,
CommandLine,
DefaultValue,
}
#[cfg(test)]
mod tests {
use super::*;

Просмотреть файл

@ -1,9 +1,9 @@
mod arg_matches;
mod matched_arg;
mod value_source;
pub(crate) use self::{
arg_matches::SubCommand,
matched_arg::{MatchedArg, ValueType},
};
pub use arg_matches::{ArgMatches, Indices, OsValues, Values};
pub use value_source::ValueSource;
pub use self::arg_matches::{ArgMatches, Indices, OsValues, Values};
pub(crate) use arg_matches::SubCommand;
pub(crate) use matched_arg::MatchedArg;

11
third_party/rust/clap/src/parse/matches/value_source.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,11 @@
/// 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,
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше