зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
c8b2b8d7b4
Коммит
bc89e96a24
|
@ -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!();
|
||||
}
|
||||
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -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"
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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![""]))
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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..]);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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).
|
||||
|
||||
|
|
|
@ -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)>,
|
||||
}
|
|
@ -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
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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));
|
||||
}
|
|
@ -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"))
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
|
@ -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.
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>>()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче