mirror of
https://github.com/clap-rs/clap
synced 2025-01-18 23:53:54 +00:00
commit
4740b1e05b
48 changed files with 529 additions and 391 deletions
|
@ -1,9 +1,9 @@
|
|||
environment:
|
||||
matrix:
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
RUST_BACKTRACE: full
|
||||
install:
|
||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
||||
|
@ -13,5 +13,5 @@ install:
|
|||
- cargo -vV
|
||||
build: false
|
||||
test_script:
|
||||
- cargo build --all --verbose --features yaml
|
||||
- cargo test --all --verbose --features yaml
|
||||
- cargo test --all --no-default-features
|
||||
- cargo test --all --features "yaml unstable"
|
||||
|
|
22
.github/CONTRIBUTING.md
vendored
22
.github/CONTRIBUTING.md
vendored
|
@ -9,8 +9,8 @@ Another really great way to help is if you find an interesting, or helpful way i
|
|||
To test with all features both enabled and disabled, you can run these commands:
|
||||
|
||||
```sh
|
||||
$ cargo test --no-default-features
|
||||
$ cargo test --features "yaml unstable"
|
||||
$ cargo test --all --no-default-features
|
||||
$ cargo test --all --features "yaml unstable"
|
||||
```
|
||||
|
||||
Alternatively, if you have [`just`](https://github.com/casey/just) installed you can run the prebuilt recipes. *Not* using `just` is perfectly fine as well, it simply bundles commands automatically.
|
||||
|
@ -26,7 +26,7 @@ From here on, I will list the appropriate `cargo` command as well as the `just`
|
|||
Sometimes it's helpful to only run a subset of the tests, which can be done via:
|
||||
|
||||
```sh
|
||||
$ cargo test --test <test_name>
|
||||
$ cargo test --all --test <test_name>
|
||||
|
||||
# Or
|
||||
|
||||
|
@ -35,14 +35,14 @@ $ just run-test <test_name>
|
|||
|
||||
### Linting Code
|
||||
|
||||
During the CI process `clap` runs against many different lints using [`clippy`](https://github.com/Manishearth/rust-clippy). In order to check if these lints pass on your own computer prior to submitting a PR you'll need a nightly compiler.
|
||||
During the CI process `clap` runs against many different lints using [`clippy`](https://github.com/rust-lang/rust-clippy).
|
||||
|
||||
In order to check the code for lints run either:
|
||||
In order to check the code for lints and to format it run either:
|
||||
|
||||
```sh
|
||||
$ rustup override add nightly
|
||||
$ cargo build --features lints
|
||||
$ rustup override remove
|
||||
$ cargo clippy --all --lib --features "yaml unstable" -- -D warnings
|
||||
$ cargo clippy --all --tests --examples --features "yaml unstable"
|
||||
$ cargo fmt -- --check
|
||||
|
||||
# Or
|
||||
|
||||
|
@ -54,10 +54,10 @@ $ just lint
|
|||
Another helpful technique is to see the `clap` debug output while developing features. In order to see the debug output while running the full test suite or individual tests, run:
|
||||
|
||||
```sh
|
||||
$ cargo test --features debug
|
||||
$ cargo test --all --features debug
|
||||
|
||||
# Or for individual tests
|
||||
$ cargo test --test <test_name> --features debug
|
||||
$ cargo test --all --test <test_name> --features debug
|
||||
|
||||
# The corresponding just command for individual debugging tests is:
|
||||
$ just debug <test_name>
|
||||
|
@ -81,7 +81,7 @@ I use a [conventional](https://github.com/ajoslin/conventional-changelog/blob/a5
|
|||
- `wip` - A work in progress commit (Should typically be `git rebase`'ed away)
|
||||
- `chore` - Catch all or things that have to do with the build system, etc
|
||||
- `examples` - Changes to existing example, or a new example
|
||||
* The `COMPONENT` is optional, and may be a single file, directory, or logical component. Parenthesis can be omitted if you are opting not to use the `COMPONENT`.
|
||||
* The `COMPONENT` is optional, and may be a single file, directory, or logical component. Parenthesis can be omitted if you are opting not to use the `COMPONENT`.
|
||||
|
||||
### Tests and Documentation
|
||||
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"findPotentialReviewers": false,
|
||||
"alwaysNotifyForPaths": [
|
||||
{
|
||||
"name": "kbknapp",
|
||||
"files": ["**/*.rs", "**/*.md", "*"]
|
||||
}
|
||||
]
|
||||
}
|
111
.travis.yml
111
.travis.yml
|
@ -1,68 +1,53 @@
|
|||
sudo: true
|
||||
os: linux
|
||||
language: rust
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cargo
|
||||
- $HOME/.rustup
|
||||
before_cache:
|
||||
- rm -rf /home/travis/.cargo/registry
|
||||
rust:
|
||||
- nightly
|
||||
- nightly-2019-06-18
|
||||
- beta
|
||||
- stable
|
||||
- 1.36.0
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
include:
|
||||
- rust: nightly-2019-06-18
|
||||
before_script:
|
||||
- rustup component add clippy
|
||||
script: cargo clippy
|
||||
before_script:
|
||||
- |
|
||||
pip install git+git://github.com/kbknapp/travis-cargo.git --user &&
|
||||
export PATH=$HOME/.local/bin:$PATH
|
||||
- |
|
||||
if [[ "$TRAVIS_RUST_VERSION" == "1.13.0" ]]; then
|
||||
echo "Old Rust detected, removing version-sync dependency"
|
||||
sed -i "/^version-sync =/d" Cargo.toml
|
||||
rm "tests/version-numbers.rs"
|
||||
fi
|
||||
cache: cargo
|
||||
rust: stable
|
||||
jobs:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
- env:
|
||||
- SHARD=coverage
|
||||
fast_finish: true
|
||||
include:
|
||||
- os: osx
|
||||
- {}
|
||||
- rust: 1.36.0
|
||||
- rust: beta
|
||||
- rust: nightly
|
||||
- env:
|
||||
- SHARD=lint
|
||||
before_script:
|
||||
- rustup component add clippy
|
||||
- rustup component add rustfmt
|
||||
script:
|
||||
- echo "Checking codebase with Clippy release `cargo clippy --version`."
|
||||
- cargo clippy --all --lib --features "yaml unstable" -- -D warnings
|
||||
- cargo clippy --all --tests --examples --features "yaml unstable"
|
||||
- cargo fmt -- --check
|
||||
- rust: nightly
|
||||
env:
|
||||
- SHARD=bench
|
||||
script:
|
||||
- cargo bench
|
||||
- env:
|
||||
- SHARD=coverage
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libssl-dev
|
||||
- cmake
|
||||
- pkg-config
|
||||
- zlib1g-dev
|
||||
update: true
|
||||
before_script:
|
||||
- cargo install cargo-tarpaulin
|
||||
script:
|
||||
- cargo tarpaulin --workspace --features "yaml unstable" --ciserver travis-ci --coveralls $TRAVIS_JOB_ID
|
||||
script:
|
||||
- |
|
||||
travis-cargo --skip nightly test -- --all --verbose --no-default-features &&
|
||||
travis-cargo --only nightly test -- --verbose --no-default-features &&
|
||||
travis-cargo --skip nightly test -- --verbose --features "yaml unstable" &&
|
||||
travis-cargo --only nightly test -- --verbose --features "yaml unstable nightly" &&
|
||||
travis-cargo --only nightly bench
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libcurl4-openssl-dev
|
||||
- libelf-dev
|
||||
- libdw-dev
|
||||
- cmake
|
||||
- gcc
|
||||
- binutils-dev
|
||||
after_success:
|
||||
- |
|
||||
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
|
||||
tar xzf master.tar.gz &&
|
||||
cd kcov-master &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake .. &&
|
||||
make &&
|
||||
sudo make install &&
|
||||
cd ../.. &&
|
||||
rm -rf kcov-master &&
|
||||
cargo clean &&
|
||||
cargo test --no-run --features "yaml unstable" &&
|
||||
for file in target/debug/*-*; do mkdir -p "target/cov/$(basename $file)"; kcov --exclude-pattern=/.cargo --verify "target/cov/$(basename $file)" "$file"; done &&
|
||||
kcov --coveralls-id=$TRAVIS_JOB_ID --merge target/cov target/cov/* &&
|
||||
echo "Uploaded code coverage"
|
||||
- cargo test --all --no-default-features
|
||||
- cargo test --all --features yaml unstable
|
||||
notifications:
|
||||
email: false
|
||||
env:
|
||||
global:
|
||||
- secure: JLBlgHY6OEmhJ8woewNJHmuBokTNUv7/WvLkJGV8xk0t6bXBwSU0jNloXwlH7FiQTc4TccX0PumPDD4MrMgxIAVFPmmmlQOCmdpYP4tqZJ8xo189E5zk8lKF5OyaVYCs5SMmFC3cxCsKjfwGIexNu3ck5Uhwe9jI0tqgkgM3URA=
|
||||
|
|
|
@ -8,7 +8,11 @@ use clap::App;
|
|||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn build_app(b: &mut Bencher) { b.iter(|| App::new("claptests")); }
|
||||
fn build_app(b: &mut Bencher) {
|
||||
b.iter(|| App::new("claptests"));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn parse_clean(b: &mut Bencher) { b.iter(|| App::new("claptests").get_matches_from(vec![""])); }
|
||||
fn parse_clean(b: &mut Bencher) {
|
||||
b.iter(|| App::new("claptests").get_matches_from(vec![""]));
|
||||
}
|
||||
|
|
|
@ -20,18 +20,24 @@ macro_rules! create_app {
|
|||
}
|
||||
|
||||
#[bench]
|
||||
fn build_app(b: &mut Bencher) { b.iter(|| create_app!()); }
|
||||
fn build_app(b: &mut Bencher) {
|
||||
b.iter(|| create_app!());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn add_flag(b: &mut Bencher) {
|
||||
fn build_app() -> App<'static> { App::new("claptests") }
|
||||
fn build_app() -> App<'static> {
|
||||
App::new("claptests")
|
||||
}
|
||||
|
||||
b.iter(|| build_app().arg(Arg::from("-s, --some 'something'")));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn add_flag_ref(b: &mut Bencher) {
|
||||
fn build_app() -> App<'static> { App::new("claptests") }
|
||||
fn build_app() -> App<'static> {
|
||||
App::new("claptests")
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
let arg = Arg::from("-s, --some 'something'");
|
||||
|
@ -41,14 +47,18 @@ fn add_flag_ref(b: &mut Bencher) {
|
|||
|
||||
#[bench]
|
||||
fn add_opt(b: &mut Bencher) {
|
||||
fn build_app() -> App<'static> { App::new("claptests") }
|
||||
fn build_app() -> App<'static> {
|
||||
App::new("claptests")
|
||||
}
|
||||
|
||||
b.iter(|| build_app().arg(Arg::from("-s, --some <FILE> 'something'")));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn add_opt_ref(b: &mut Bencher) {
|
||||
fn build_app() -> App<'static> { App::new("claptests") }
|
||||
fn build_app() -> App<'static> {
|
||||
App::new("claptests")
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
let arg = Arg::from("-s, --some <FILE> 'something'");
|
||||
|
@ -58,14 +68,18 @@ fn add_opt_ref(b: &mut Bencher) {
|
|||
|
||||
#[bench]
|
||||
fn add_pos(b: &mut Bencher) {
|
||||
fn build_app() -> App<'static> { App::new("claptests") }
|
||||
fn build_app() -> App<'static> {
|
||||
App::new("claptests")
|
||||
}
|
||||
|
||||
b.iter(|| build_app().arg(Arg::with_name("some")));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn add_pos_ref(b: &mut Bencher) {
|
||||
fn build_app() -> App<'static> { App::new("claptests") }
|
||||
fn build_app() -> App<'static> {
|
||||
App::new("claptests")
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
let arg = Arg::with_name("some");
|
||||
|
@ -74,10 +88,14 @@ fn add_pos_ref(b: &mut Bencher) {
|
|||
}
|
||||
|
||||
#[bench]
|
||||
fn parse_clean(b: &mut Bencher) { b.iter(|| create_app!().get_matches_from(vec![""])); }
|
||||
fn parse_clean(b: &mut Bencher) {
|
||||
b.iter(|| create_app!().get_matches_from(vec![""]));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn parse_flag(b: &mut Bencher) { b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"])); }
|
||||
fn parse_flag(b: &mut Bencher) {
|
||||
b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"]));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn parse_option(b: &mut Bencher) {
|
||||
|
|
|
@ -49,7 +49,9 @@ macro_rules! create_app {
|
|||
}
|
||||
|
||||
#[bench]
|
||||
fn create_app_from_usage(b: &mut Bencher) { b.iter(|| create_app!()); }
|
||||
fn create_app_from_usage(b: &mut Bencher) {
|
||||
b.iter(|| create_app!());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn create_app_builder(b: &mut Bencher) {
|
||||
|
@ -203,10 +205,14 @@ fn create_app_macros(b: &mut Bencher) {
|
|||
}
|
||||
|
||||
#[bench]
|
||||
fn parse_clean(b: &mut Bencher) { b.iter(|| create_app!().get_matches_from(vec![""])); }
|
||||
fn parse_clean(b: &mut Bencher) {
|
||||
b.iter(|| create_app!().get_matches_from(vec![""]));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn parse_flag(b: &mut Bencher) { b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"])); }
|
||||
fn parse_flag(b: &mut Bencher) {
|
||||
b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"]));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn parse_option(b: &mut Bencher) {
|
||||
|
|
|
@ -17,10 +17,14 @@ use std::io::Cursor;
|
|||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn build_app_short(b: &mut Bencher) { b.iter(app_short); }
|
||||
fn build_app_short(b: &mut Bencher) {
|
||||
b.iter(app_short);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn build_app_long(b: &mut Bencher) { b.iter(app_long); }
|
||||
fn build_app_long(b: &mut Bencher) {
|
||||
b.iter(app_long);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn build_help_short(b: &mut Bencher) {
|
||||
|
@ -35,7 +39,9 @@ fn build_help_long(b: &mut Bencher) {
|
|||
}
|
||||
|
||||
#[bench]
|
||||
fn parse_clean(b: &mut Bencher) { b.iter(|| app_short().get_matches_from(vec!["rg", "pat"])); }
|
||||
fn parse_clean(b: &mut Bencher) {
|
||||
b.iter(|| app_short().get_matches_from(vec!["rg", "pat"]));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn parse_complex(b: &mut Bencher) {
|
||||
|
@ -255,10 +261,14 @@ OPTIONS:
|
|||
{unified}";
|
||||
|
||||
/// Build a clap application with short help strings.
|
||||
pub fn app_short() -> App<'static> { app(false, |k| USAGES[k].short) }
|
||||
pub fn app_short() -> App<'static> {
|
||||
app(false, |k| USAGES[k].short)
|
||||
}
|
||||
|
||||
/// Build a clap application with long help strings.
|
||||
pub fn app_long() -> App<'static> { app(true, |k| USAGES[k].long) }
|
||||
pub fn app_long() -> App<'static> {
|
||||
app(true, |k| USAGES[k].long)
|
||||
}
|
||||
|
||||
/// Build the help text of an application.
|
||||
fn build_help(app: &mut App) -> String {
|
||||
|
|
|
@ -12,10 +12,14 @@ use clap::{App, AppSettings, Arg, ArgGroup, ArgSettings};
|
|||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn build_app(b: &mut Bencher) { b.iter(build_cli); }
|
||||
fn build_app(b: &mut Bencher) {
|
||||
b.iter(build_cli);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn parse_clean(b: &mut Bencher) { b.iter(|| build_cli().get_matches_from(vec![""])); }
|
||||
fn parse_clean(b: &mut Bencher) {
|
||||
b.iter(|| build_cli().get_matches_from(vec![""]));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn parse_subcommands(b: &mut Bencher) {
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
format_strings = false
|
||||
fn_single_line = true
|
|
@ -7,25 +7,23 @@
|
|||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
/*
|
||||
use proc_macro2;
|
||||
// use quote;
|
||||
use quote;
|
||||
use syn;
|
||||
// use syn::punctuated;
|
||||
// use syn::token;
|
||||
use syn::punctuated;
|
||||
use syn::token;
|
||||
|
||||
pub fn derive_arg_enum(_ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
|
||||
unimplemented!()
|
||||
let from_str_block = impl_from_str(ast)?;
|
||||
let variants_block = impl_variants(ast)?;
|
||||
|
||||
// let from_str_block = impl_from_str(ast)?;
|
||||
// let variants_block = impl_variants(ast)?;
|
||||
|
||||
// quote! {
|
||||
// #from_str_block
|
||||
// #variants_block
|
||||
// }
|
||||
quote! {
|
||||
#from_str_block
|
||||
#variants_block
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fn impl_from_str(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
|
||||
let ident = &ast.ident;
|
||||
let is_case_sensitive = ast.attrs.iter().any(|v| v.name() == "case_sensitive");
|
||||
|
|
|
@ -25,6 +25,7 @@ use syn::{self, ext::IdentExt, spanned::Spanned, LitStr};
|
|||
/// Default casing style for generated arguments.
|
||||
pub const DEFAULT_CASING: CasingStyle = CasingStyle::Kebab;
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Clone)]
|
||||
pub enum Kind {
|
||||
Arg(Sp<Ty>),
|
||||
|
@ -375,7 +376,7 @@ impl Attrs {
|
|||
.join("\n");
|
||||
|
||||
let expected_doc_comment_split = if let Some(content) = doc_comments.get(1) {
|
||||
(doc_comments.len() > 2) && (content == &"\n\n")
|
||||
(doc_comments.len() > 2) && (content == "\n\n")
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
@ -432,7 +433,7 @@ impl Attrs {
|
|||
|
||||
pub fn from_field(field: &syn::Field, struct_casing: Sp<CasingStyle>) -> Self {
|
||||
let name = field.ident.clone().unwrap();
|
||||
let mut res = Self::new(field.span(), Name::Derived(name.clone()), struct_casing);
|
||||
let mut res = Self::new(field.span(), Name::Derived(name), struct_casing);
|
||||
res.push_doc_comment(&field.attrs, "help");
|
||||
res.push_attrs(&field.attrs);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ pub mod parse;
|
|||
pub mod spanned;
|
||||
pub mod ty;
|
||||
|
||||
pub use self::arg_enum::derive_arg_enum;
|
||||
// pub use self::arg_enum::derive_arg_enum;
|
||||
pub use self::attrs::{
|
||||
Attrs, CasingStyle, GenOutput, Kind, Name, Parser, ParserKind, DEFAULT_CASING,
|
||||
};
|
||||
|
|
|
@ -26,6 +26,7 @@ impl Parse for ClapAttributes {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum ClapAttr {
|
||||
// single-identifier attributes
|
||||
Short(Ident),
|
||||
|
@ -82,7 +83,7 @@ impl Parse for ClapAttr {
|
|||
}
|
||||
};
|
||||
|
||||
match &*name_str.to_string() {
|
||||
match &*name_str {
|
||||
"rename_all" => Ok(RenameAll(name, lit)),
|
||||
|
||||
"version" => {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
use clap::Clap;
|
||||
|
||||
use std::ffi::{CString, OsStr, OsString};
|
||||
use std::ffi::{CString, OsStr};
|
||||
use std::num::ParseIntError;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -74,7 +74,9 @@ fn test_parse_hex() {
|
|||
HexOpt::parse_from(&["test", "-n", "5"])
|
||||
);
|
||||
assert_eq!(
|
||||
HexOpt { number: 0xabcdef },
|
||||
HexOpt {
|
||||
number: 0x00ab_cdef
|
||||
},
|
||||
HexOpt::parse_from(&["test", "-n", "abcdef"])
|
||||
);
|
||||
|
||||
|
@ -292,8 +294,6 @@ fn test_custom_bool() {
|
|||
|
||||
#[test]
|
||||
fn test_cstring() {
|
||||
use clap::IntoApp;
|
||||
|
||||
#[derive(Clap)]
|
||||
struct Opt {
|
||||
#[clap(parse(try_from_str = CString::new))]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#[test]
|
||||
fn issue_151() {
|
||||
use clap::{ArgGroup, Clap, IntoApp};
|
||||
use clap::{ArgGroup, Clap};
|
||||
|
||||
#[derive(Clap, Debug)]
|
||||
#[clap(group = ArgGroup::with_name("verb").required(true).multiple(true))]
|
||||
|
@ -28,7 +28,7 @@ fn issue_151() {
|
|||
|
||||
#[test]
|
||||
fn issue_289() {
|
||||
use clap::{AppSettings, Clap, IntoApp};
|
||||
use clap::{AppSettings, Clap};
|
||||
|
||||
#[derive(Clap)]
|
||||
#[clap(setting = AppSettings::InferSubcommands)]
|
||||
|
|
|
@ -171,8 +171,6 @@ enum Stash {
|
|||
#[test]
|
||||
fn sub_sub_cmd_with_option() {
|
||||
fn make(args: &[&str]) -> Option<SubSubCmdWithOption> {
|
||||
use clap::{FromArgMatches, IntoApp};
|
||||
|
||||
SubSubCmdWithOption::try_parse_from(args).ok()
|
||||
}
|
||||
assert_eq!(
|
||||
|
|
|
@ -140,7 +140,9 @@ fn test_parse_hex_function_path() {
|
|||
HexOpt::parse_from(&["test", "-n", "5"])
|
||||
);
|
||||
assert_eq!(
|
||||
HexOpt { number: 0xabcdef },
|
||||
HexOpt {
|
||||
number: 0x00ab_cdef
|
||||
},
|
||||
HexOpt::parse_from(&["test", "-n", "abcdef"])
|
||||
);
|
||||
|
||||
|
|
|
@ -116,8 +116,6 @@ fn option_from_str() {
|
|||
|
||||
#[test]
|
||||
fn optional_argument_for_optional_option() {
|
||||
use clap::IntoApp;
|
||||
|
||||
#[derive(Clap, PartialEq, Debug)]
|
||||
struct Opt {
|
||||
#[clap(short)]
|
||||
|
|
|
@ -68,7 +68,7 @@ fn skip_enum() {
|
|||
|
||||
impl Default for Kind {
|
||||
fn default() -> Self {
|
||||
return Kind::B;
|
||||
Kind::B
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ fn skip_val() {
|
|||
Opt::parse_from(&["test", "-n", "10"]),
|
||||
Opt {
|
||||
number: 10,
|
||||
k: "key".into(),
|
||||
k: "key".to_string(),
|
||||
v: vec![1, 2, 3]
|
||||
}
|
||||
);
|
||||
|
|
|
@ -140,8 +140,6 @@ enum Opt4 {
|
|||
|
||||
#[test]
|
||||
fn test_tuple_commands() {
|
||||
use clap::IntoApp;
|
||||
|
||||
assert_eq!(
|
||||
Opt4::Add(Add {
|
||||
file: "f".to_string()
|
||||
|
|
|
@ -5,9 +5,7 @@ use clap::IntoApp;
|
|||
|
||||
pub fn get_help<T: IntoApp>() -> String {
|
||||
let mut output = Vec::new();
|
||||
<T as IntoApp>::into_app()
|
||||
.write_help(&mut output)
|
||||
.unwrap();
|
||||
<T as IntoApp>::into_app().write_help(&mut output).unwrap();
|
||||
let output = String::from_utf8(output).unwrap();
|
||||
|
||||
eprintln!("\n%%% HELP %%%:=====\n{}\n=====\n", output);
|
||||
|
|
24
justfile
24
justfile
|
@ -13,25 +13,23 @@
|
|||
rm CONTRIBUTORS.md.bak
|
||||
|
||||
run-test TESTG TEST="":
|
||||
cargo test --test {{TESTG}} -- {{TEST}}
|
||||
cargo test --all --test {{TESTG}} -- {{TEST}}
|
||||
|
||||
debug TESTG TEST="":
|
||||
cargo test --test {{TESTG}} --features debug -- {{TEST}}
|
||||
cargo test --all --test {{TESTG}} --features debug -- {{TEST}}
|
||||
|
||||
run-tests:
|
||||
cargo test --features "yaml unstable"
|
||||
cargo test --all --features "yaml unstable"
|
||||
|
||||
@bench: nightly
|
||||
cargo bench && just remove-nightly
|
||||
@bench:
|
||||
cargo bench
|
||||
|
||||
nightly:
|
||||
rustup override add nightly
|
||||
|
||||
remove-nightly:
|
||||
rustup override remove
|
||||
|
||||
@lint: nightly
|
||||
cargo build --features lints && just remove-nightly
|
||||
@lint:
|
||||
rustup add component clippy
|
||||
rustup add component rustfmt
|
||||
cargo clippy --all --lib --features "yaml unstable" -- -D warnings
|
||||
cargo clippy --all --tests --examples --features "yaml unstable"
|
||||
cargo fmt -- --check
|
||||
|
||||
clean:
|
||||
cargo clean
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
format_strings = false
|
||||
fn_single_line = true
|
|
@ -138,10 +138,14 @@ impl<'b> App<'b> {
|
|||
}
|
||||
|
||||
/// Get the name of the app
|
||||
pub fn get_name(&self) -> &str { &self.name }
|
||||
pub fn get_name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Get the name of the binary
|
||||
pub fn get_bin_name(&self) -> Option<&str> { self.bin_name.as_ref().map(String::as_str) }
|
||||
pub fn get_bin_name(&self) -> Option<&str> {
|
||||
self.bin_name.as_ref().map(String::as_str)
|
||||
}
|
||||
|
||||
/// Sets a string of author(s) that will be displayed to the user when they
|
||||
/// request the help information with `--help` or `-h`.
|
||||
|
@ -250,13 +254,11 @@ impl<'b> App<'b> {
|
|||
/// # #[macro_use]
|
||||
/// # extern crate clap;
|
||||
/// # use clap::App;
|
||||
/// # fn main() {
|
||||
/// let yml = load_yaml!("app.yml");
|
||||
/// let app = App::from_yaml(yml)
|
||||
/// .name(crate_name!());
|
||||
///
|
||||
/// // continued logic goes here, such as `app.get_matches()` etc.
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`App::from_yaml`]: ./struct.App.html#method.from_yaml
|
||||
|
@ -1165,7 +1167,9 @@ impl<'b> App<'b> {
|
|||
/// .get_matches();
|
||||
/// ```
|
||||
/// [`env::args_os`]: https://doc.rust-lang.org/std/env/fn.args_os.html
|
||||
pub fn get_matches(self) -> ArgMatches { self.get_matches_from(&mut env::args_os()) }
|
||||
pub fn get_matches(self) -> ArgMatches {
|
||||
self.get_matches_from(&mut env::args_os())
|
||||
}
|
||||
|
||||
/// Starts the parsing process, just like [`App::get_matches`] but doesn't consume the `App`
|
||||
///
|
||||
|
@ -1406,6 +1410,7 @@ impl<'b> App<'b> {
|
|||
Ok(matcher.into_inner())
|
||||
}
|
||||
|
||||
#[allow(clippy::debug_assert_with_mut_call)]
|
||||
// used in clap_generate (https://github.com/clap-rs/clap_generate)
|
||||
#[doc(hidden)]
|
||||
pub fn _build(&mut self) {
|
||||
|
@ -1461,7 +1466,7 @@ impl<'b> App<'b> {
|
|||
}
|
||||
|
||||
// Perform some expensive assertions on the Parser itself
|
||||
fn _app_debug_asserts(&mut self) -> bool {
|
||||
fn _app_debug_asserts(&self) -> bool {
|
||||
debugln!("App::_app_debug_asserts;");
|
||||
for name in self.args.args.iter().map(|x| x.id) {
|
||||
if self.args.args.iter().filter(|x| x.id == name).count() > 1 {
|
||||
|
@ -1777,27 +1782,49 @@ impl<'b> App<'b> {
|
|||
self.settings.is_set(s) || self.g_settings.is_set(s)
|
||||
}
|
||||
|
||||
pub fn set(&mut self, s: AppSettings) { self.settings.set(s) }
|
||||
pub fn set(&mut self, s: AppSettings) {
|
||||
self.settings.set(s)
|
||||
}
|
||||
|
||||
pub fn set_global(&mut self, s: AppSettings) { self.g_settings.set(s) }
|
||||
pub fn set_global(&mut self, s: AppSettings) {
|
||||
self.g_settings.set(s)
|
||||
}
|
||||
|
||||
pub fn unset_global(&mut self, s: AppSettings) { self.g_settings.unset(s) }
|
||||
pub fn unset_global(&mut self, s: AppSettings) {
|
||||
self.g_settings.unset(s)
|
||||
}
|
||||
|
||||
pub fn unset(&mut self, s: AppSettings) { self.settings.unset(s) }
|
||||
pub fn unset(&mut self, s: AppSettings) {
|
||||
self.settings.unset(s)
|
||||
}
|
||||
|
||||
pub fn has_subcommands(&self) -> bool { !self.subcommands.is_empty() }
|
||||
pub fn has_subcommands(&self) -> bool {
|
||||
!self.subcommands.is_empty()
|
||||
}
|
||||
|
||||
pub fn has_args(&self) -> bool { !self.args.is_empty() }
|
||||
pub fn has_args(&self) -> bool {
|
||||
!self.args.is_empty()
|
||||
}
|
||||
|
||||
pub fn has_opts(&self) -> bool { opts!(self).count() > 0 }
|
||||
pub fn has_opts(&self) -> bool {
|
||||
opts!(self).count() > 0
|
||||
}
|
||||
|
||||
pub fn has_flags(&self) -> bool { flags!(self).count() > 0 }
|
||||
pub fn has_flags(&self) -> bool {
|
||||
flags!(self).count() > 0
|
||||
}
|
||||
|
||||
pub fn has_positionals(&self) -> bool { positionals!(self).count() > 0 }
|
||||
pub fn has_positionals(&self) -> bool {
|
||||
positionals!(self).count() > 0
|
||||
}
|
||||
|
||||
pub fn has_visible_opts(&self) -> bool { opts!(self).any(|o| !o.is_set(ArgSettings::Hidden)) }
|
||||
pub fn has_visible_opts(&self) -> bool {
|
||||
opts!(self).any(|o| !o.is_set(ArgSettings::Hidden))
|
||||
}
|
||||
|
||||
pub fn has_visible_flags(&self) -> bool { flags!(self).any(|o| !o.is_set(ArgSettings::Hidden)) }
|
||||
pub fn has_visible_flags(&self) -> bool {
|
||||
flags!(self).any(|o| !o.is_set(ArgSettings::Hidden))
|
||||
}
|
||||
|
||||
pub fn has_visible_positionals(&self) -> bool {
|
||||
positionals!(self).any(|o| !o.is_set(ArgSettings::Hidden))
|
||||
|
@ -1840,7 +1867,7 @@ impl<'b> App<'b> {
|
|||
if let Some(v) = val {
|
||||
if matcher
|
||||
.get(arg)
|
||||
.and_then(|ma| Some(ma.contains_val(v)))
|
||||
.map(|ma| ma.contains_val(v))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
Some(req_arg)
|
||||
|
@ -1876,6 +1903,7 @@ impl<'b> App<'b> {
|
|||
|
||||
#[cfg(feature = "yaml")]
|
||||
impl<'a> From<&'a Yaml> for App<'a> {
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn from(mut yaml: &'a Yaml) -> Self {
|
||||
// We WANT this to panic on error...so expect() is good.
|
||||
let mut is_sc = None;
|
||||
|
@ -2013,5 +2041,7 @@ impl<'a> From<&'a Yaml> for App<'a> {
|
|||
}
|
||||
|
||||
impl<'e> fmt::Display for App<'e> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.name) }
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,16 +55,24 @@ pub struct AppFlags(Flags);
|
|||
|
||||
impl BitOr for AppFlags {
|
||||
type Output = Self;
|
||||
fn bitor(self, rhs: Self) -> Self { AppFlags(self.0 | rhs.0) }
|
||||
fn bitor(self, rhs: Self) -> Self {
|
||||
AppFlags(self.0 | rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AppFlags {
|
||||
fn default() -> Self { AppFlags(Flags::UTF8_NONE | Flags::COLOR_AUTO) }
|
||||
fn default() -> Self {
|
||||
AppFlags(Flags::UTF8_NONE | Flags::COLOR_AUTO)
|
||||
}
|
||||
}
|
||||
|
||||
impl AppFlags {
|
||||
pub fn new() -> Self { AppFlags::default() }
|
||||
pub fn zeroed() -> Self { AppFlags(Flags::empty()) }
|
||||
pub fn new() -> Self {
|
||||
AppFlags::default()
|
||||
}
|
||||
pub fn zeroed() -> Self {
|
||||
AppFlags(Flags::empty())
|
||||
}
|
||||
|
||||
impl_settings! { AppSettings,
|
||||
ArgRequiredElseHelp => Flags::A_REQUIRED_ELSE_HELP,
|
||||
|
@ -949,6 +957,7 @@ impl FromStr for AppSettings {
|
|||
mod test {
|
||||
use super::AppSettings;
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
#[test]
|
||||
fn app_settings_fromstr() {
|
||||
assert_eq!(
|
||||
|
|
|
@ -165,13 +165,12 @@ impl<'help> Arg<'help> {
|
|||
/// # #[macro_use]
|
||||
/// # extern crate clap;
|
||||
/// # use clap::Arg;
|
||||
/// # fn main() {
|
||||
/// let yml = load_yaml!("arg.yml");
|
||||
/// let arg = Arg::from_yaml(yml);
|
||||
/// # }
|
||||
/// ```
|
||||
/// [`Arg`]: ./struct.Arg.html
|
||||
#[cfg(feature = "yaml")]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn from_yaml(y: &yaml_rust::yaml::Hash) -> Arg {
|
||||
// We WANT this to panic on error...so expect() is good.
|
||||
let name_yml = y.keys().nth(0).unwrap();
|
||||
|
@ -2319,7 +2318,9 @@ impl<'help> Arg<'help> {
|
|||
/// only using [`OsStr`]s instead.
|
||||
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
|
||||
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
|
||||
pub fn default_value_os(self, val: &'help OsStr) -> Self { self.default_values_os(&[val]) }
|
||||
pub fn default_value_os(self, val: &'help OsStr) -> Self {
|
||||
self.default_values_os(&[val])
|
||||
}
|
||||
|
||||
/// Like [`Arg::default_value'] but for args taking multiple values
|
||||
/// [`Arg::default_value`]: ./struct.Arg.html#method.default_value
|
||||
|
@ -2575,7 +2576,6 @@ impl<'help> Arg<'help> {
|
|||
/// [`Arg::default_value_ifs`] only using [`OsStr`]s instead.
|
||||
/// [`Arg::default_value_ifs`]: ./struct.Arg.html#method.default_value_ifs
|
||||
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
|
||||
#[cfg_attr(feature = "lints", allow(explicit_counter_loop))]
|
||||
pub fn default_value_ifs_os<T: Key>(
|
||||
mut self,
|
||||
ifs: &[(T, Option<&'help OsStr>, &'help OsStr)],
|
||||
|
@ -2685,7 +2685,9 @@ impl<'help> Arg<'help> {
|
|||
///
|
||||
/// assert_eq!(m.values_of("flag").unwrap().collect::<Vec<_>>(), vec!["env1", "env2"]);
|
||||
/// ```
|
||||
pub fn env(self, name: &'help str) -> Self { self.env_os(OsStr::new(name)) }
|
||||
pub fn env(self, name: &'help str) -> Self {
|
||||
self.env_os(OsStr::new(name))
|
||||
}
|
||||
|
||||
/// Specifies that if the value is not passed in as an argument, that it should be retrieved
|
||||
/// from the environment if available in the exact same manner as [`Arg::env`] only using
|
||||
|
@ -3855,7 +3857,9 @@ impl<'help> Arg<'help> {
|
|||
/// [`Arg::allow_hyphen_values(true)`]: ./struct.Arg.html#method.allow_hyphen_values
|
||||
/// [`Arg::last(true)`]: ./struct.Arg.html#method.last
|
||||
/// [`AppSettings::TrailingVarArg`]: ./enum.AppSettings.html#variant.TrailingVarArg
|
||||
pub fn raw(self, raw: bool) -> Self { self.multiple(raw).allow_hyphen_values(raw).last(raw) }
|
||||
pub fn raw(self, raw: bool) -> Self {
|
||||
self.multiple(raw).allow_hyphen_values(raw).last(raw)
|
||||
}
|
||||
|
||||
/// Hides an argument from short help message output.
|
||||
///
|
||||
|
@ -4014,7 +4018,9 @@ impl<'help> Arg<'help> {
|
|||
// @TODO @docs @v3-beta: write better docs as ArgSettings is now critical
|
||||
/// Checks if one of the [`ArgSettings`] is set for the argument
|
||||
/// [`ArgSettings`]: ./enum.ArgSettings.html
|
||||
pub fn is_set(&self, s: ArgSettings) -> bool { self.settings.is_set(s) }
|
||||
pub fn is_set(&self, s: ArgSettings) -> bool {
|
||||
self.settings.is_set(s)
|
||||
}
|
||||
|
||||
/// Sets one of the [`ArgSettings`] settings for the argument
|
||||
/// [`ArgSettings`]: ./enum.ArgSettings.html
|
||||
|
@ -4073,14 +4079,20 @@ impl<'help> Arg<'help> {
|
|||
|
||||
// @TODO @p6 @naming @internal: rename to set_mut
|
||||
#[doc(hidden)]
|
||||
pub fn setb(&mut self, s: ArgSettings) { self.settings.set(s); }
|
||||
pub fn setb(&mut self, s: ArgSettings) {
|
||||
self.settings.set(s);
|
||||
}
|
||||
|
||||
// @TODO @p6 @naming @internal: rename to unset_mut
|
||||
#[doc(hidden)]
|
||||
pub fn unsetb(&mut self, s: ArgSettings) { self.settings.unset(s); }
|
||||
pub fn unsetb(&mut self, s: ArgSettings) {
|
||||
self.settings.unset(s);
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn has_switch(&self) -> bool { self.short.is_some() || self.long.is_some() }
|
||||
pub fn has_switch(&self) -> bool {
|
||||
self.short.is_some() || self.long.is_some()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn longest_filter(&self) -> bool {
|
||||
|
@ -4142,15 +4154,21 @@ impl<'help> Arg<'help> {
|
|||
}
|
||||
|
||||
impl<'help, 'z> From<&'z Arg<'help>> for Arg<'help> {
|
||||
fn from(a: &'z Arg<'help>) -> Self { a.clone() }
|
||||
fn from(a: &'z Arg<'help>) -> Self {
|
||||
a.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'help> From<&'help str> for Arg<'help> {
|
||||
fn from(s: &'help str) -> Self { UsageParser::from_usage(s).parse() }
|
||||
fn from(s: &'help str) -> Self {
|
||||
UsageParser::from_usage(s).parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'help> PartialEq for Arg<'help> {
|
||||
fn eq(&self, other: &Arg<'help>) -> bool { self.name == other.name }
|
||||
fn eq(&self, other: &Arg<'help>) -> bool {
|
||||
self.name == other.name
|
||||
}
|
||||
}
|
||||
|
||||
impl<'help> Display for Arg<'help> {
|
||||
|
@ -4252,11 +4270,15 @@ impl<'help> Display for Arg<'help> {
|
|||
}
|
||||
|
||||
impl<'help> PartialOrd for Arg<'help> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'help> Ord for Arg<'help> {
|
||||
fn cmp(&self, other: &Arg) -> Ordering { self.name.cmp(&other.name) }
|
||||
fn cmp(&self, other: &Arg) -> Ordering {
|
||||
self.name.cmp(&other.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'help> Eq for Arg<'help> {}
|
||||
|
|
|
@ -34,7 +34,9 @@ bitflags! {
|
|||
pub struct ArgFlags(Flags);
|
||||
|
||||
impl ArgFlags {
|
||||
pub fn new() -> Self { ArgFlags::default() }
|
||||
pub fn new() -> Self {
|
||||
ArgFlags::default()
|
||||
}
|
||||
|
||||
// @TODO @p6 @internal: Reorder alphabetically
|
||||
impl_settings! {ArgSettings,
|
||||
|
@ -62,7 +64,9 @@ impl ArgFlags {
|
|||
}
|
||||
|
||||
impl Default for ArgFlags {
|
||||
fn default() -> Self { ArgFlags(Flags::DELIM_NOT_SET) }
|
||||
fn default() -> Self {
|
||||
ArgFlags(Flags::DELIM_NOT_SET)
|
||||
}
|
||||
}
|
||||
|
||||
/// Various settings that apply to arguments and may be set, unset, and checked via getter/setter
|
||||
|
|
|
@ -107,7 +107,9 @@ impl<'a> ArgGroup<'a> {
|
|||
}
|
||||
}
|
||||
/// @TODO @p2 @docs @v3-beta1: Write Docs
|
||||
pub fn new<T: Key>(id: T) -> Self { ArgGroup::_with_id(id.key()) }
|
||||
pub fn new<T: Key>(id: T) -> Self {
|
||||
ArgGroup::_with_id(id.key())
|
||||
}
|
||||
/// Creates a new instance of `ArgGroup` using a unique string name. The name will be used to
|
||||
/// get values from the group or refer to the group inside of conflict and requirement rules.
|
||||
///
|
||||
|
@ -134,10 +136,8 @@ impl<'a> ArgGroup<'a> {
|
|||
/// # #[macro_use]
|
||||
/// # extern crate clap;
|
||||
/// # use clap::ArgGroup;
|
||||
/// # fn main() {
|
||||
/// let yml = load_yaml!("group.yml");
|
||||
/// let ag = ArgGroup::from_yaml(yml);
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(feature = "yaml")]
|
||||
pub fn from_yaml(y: &'a yaml_rust::Yaml) -> ArgGroup<'a> {
|
||||
|
@ -165,7 +165,6 @@ impl<'a> ArgGroup<'a> {
|
|||
/// assert!(m.is_present("flag"));
|
||||
/// ```
|
||||
/// [argument]: ./struct.Arg.html
|
||||
#[cfg_attr(feature = "lints", allow(should_assert_eq))]
|
||||
pub fn arg<T: Key>(mut self, arg_id: T) -> Self {
|
||||
self.args.push(arg_id.key());
|
||||
self
|
||||
|
|
|
@ -159,7 +159,7 @@ impl<'a> UsageParser<'a> {
|
|||
fn short(&mut self, arg: &mut Arg<'a>) {
|
||||
debugln!("UsageParser::short;");
|
||||
let start = &self.usage[self.pos..];
|
||||
let short = start.chars().nth(0).expect(INTERNAL_ERROR_MSG);
|
||||
let short = start.chars().next().expect(INTERNAL_ERROR_MSG);
|
||||
debugln!("UsageParser::short: setting short...{}", short);
|
||||
arg.short = Some(short);
|
||||
if arg.name.is_empty() {
|
||||
|
@ -228,7 +228,9 @@ impl<'a> UsageParser<'a> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn name_end(b: u8) -> bool { b != b']' && b != b'>' }
|
||||
fn name_end(b: u8) -> bool {
|
||||
b != b']' && b != b'>'
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn token(b: u8) -> bool {
|
||||
|
@ -241,15 +243,20 @@ fn long_end(b: u8) -> bool {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn help_start(b: u8) -> bool { b != b'\'' }
|
||||
fn help_start(b: u8) -> bool {
|
||||
b != b'\''
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn default_value_end(b: u8) -> bool { b != b' ' }
|
||||
fn default_value_end(b: u8) -> bool {
|
||||
b != b' '
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::build::{Arg, ArgSettings};
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
#[test]
|
||||
fn create_flag_usage() {
|
||||
let a = Arg::from("[flag] -f 'some help info'");
|
||||
|
|
76
src/lib.rs
76
src/lib.rs
|
@ -373,81 +373,7 @@
|
|||
//!
|
||||
//! ## How to Contribute
|
||||
//!
|
||||
//! Contributions are always welcome! And there is a multitude of ways in which you can help
|
||||
//! depending on what you like to do, or are good at. Anything from documentation, code cleanup,
|
||||
//! issue completion, new features, you name it, even filing issues is contributing and greatly
|
||||
//! appreciated!
|
||||
//!
|
||||
//! Another really great way to help is if you find an interesting, or helpful way in which to use
|
||||
//! `clap`. You can either add it to the [examples/] directory, or file an issue and tell
|
||||
//! me. I'm all about giving credit where credit is due :)
|
||||
//!
|
||||
//! Please read [CONTRIBUTING.md](https://raw.githubusercontent.com/kbknapp/clap-rs/master/.github/CONTRIBUTING.md) before you start contributing.
|
||||
//!
|
||||
//!
|
||||
//! ### Testing Code
|
||||
//!
|
||||
//! To test with all features both enabled and disabled, you can run theese commands:
|
||||
//!
|
||||
//! ```text
|
||||
//! $ cargo test --no-default-features
|
||||
//! $ cargo test --features "yaml unstable"
|
||||
//! ```
|
||||
//!
|
||||
//! Alternatively, if you have [`just`](https://github.com/casey/just) installed you can run the
|
||||
//! prebuilt recipies. *Not* using `just` is perfectly fine as well, it simply bundles commands
|
||||
//! automatically.
|
||||
//!
|
||||
//! For example, to test the code, as above simply run:
|
||||
//!
|
||||
//! ```text
|
||||
//! $ just run-tests`
|
||||
//! ```
|
||||
//!
|
||||
//! From here on, I will lis the appropriate `cargo` command as well as the `just` command.
|
||||
//!
|
||||
//! Sometimes it's helpful to only run a subset of the tests, which can be done via:
|
||||
//!
|
||||
//! ```text
|
||||
//! $ cargo test --test <test_name>
|
||||
//!
|
||||
//! # Or
|
||||
//!
|
||||
//! $ just run-test <test_name>
|
||||
//! ```
|
||||
//!
|
||||
//! ### Linting Code
|
||||
//!
|
||||
//! During the CI process `clap` runs against many different lints using
|
||||
//! [`clippy`](https://github.com/Manishearth/rust-clippy). In order to check if these lints pass on
|
||||
//! your own computer prior to submitting a PR you'll need a nightly compiler.
|
||||
//!
|
||||
//! In order to check the code for lints run either:
|
||||
//!
|
||||
//! ```text
|
||||
//! $ rustup override add nightly
|
||||
//! $ cargo build --features lints
|
||||
//! $ rustup override remove
|
||||
//!
|
||||
//! # Or
|
||||
//!
|
||||
//! $ just lint
|
||||
//! ```
|
||||
//!
|
||||
//! ### Debugging Code
|
||||
//!
|
||||
//! Another helpful technique is to see the `clap` debug output while developing features. In order
|
||||
//! to see the debug output while running the full test suite or individual tests, run:
|
||||
//!
|
||||
//! ```text
|
||||
//! $ cargo test --features debug
|
||||
//!
|
||||
//! # Or for individual tests
|
||||
//! $ cargo test --test <test_name> --features debug
|
||||
//!
|
||||
//! # The corresponding just command for individual debugging tests is:
|
||||
//! $ just debug <test_name>
|
||||
//! ```
|
||||
//! Please read [CONTRIBUTING.md](https://raw.githubusercontent.com/clap-rs/clap/master/.github/CONTRIBUTING.md) before you start contributing.
|
||||
//!
|
||||
//! ### Goals
|
||||
//!
|
||||
|
|
|
@ -51,15 +51,21 @@ impl PartialEq<char> for KeyType {
|
|||
}
|
||||
|
||||
impl<'b> MKeyMap<'b> {
|
||||
pub fn new() -> Self { MKeyMap::default() }
|
||||
pub fn new() -> Self {
|
||||
MKeyMap::default()
|
||||
}
|
||||
//TODO ::from(x), ::with_capacity(n) etc
|
||||
//? set theory ops?
|
||||
|
||||
#[deprecated(since = "3.0.0", note = "Use `contains` instead")]
|
||||
pub fn contains_long(&self, l: &str) -> bool { self.contains(l) }
|
||||
pub fn contains_long(&self, l: &str) -> bool {
|
||||
self.contains(l)
|
||||
}
|
||||
|
||||
#[deprecated(since = "3.0.0", note = "Use `contains` instead")]
|
||||
pub fn contains_short(&self, c: char) -> bool { self.contains(c) }
|
||||
pub fn contains_short(&self, c: char) -> bool {
|
||||
self.contains(c)
|
||||
}
|
||||
|
||||
pub fn contains<K>(&self, key: K) -> bool
|
||||
where
|
||||
|
@ -114,7 +120,9 @@ impl<'b> MKeyMap<'b> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool { self.keys.is_empty() && self.args.is_empty() }
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.keys.is_empty() && self.args.is_empty()
|
||||
}
|
||||
|
||||
pub fn remove_key(&mut self, key: &KeyType) {
|
||||
self.keys
|
||||
|
|
|
@ -34,7 +34,9 @@ pub fn is_a_tty(_: bool) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
pub fn is_term_dumb() -> bool { env::var("TERM").ok() == Some(String::from("dumb")) }
|
||||
pub fn is_term_dumb() -> bool {
|
||||
env::var("TERM").ok() == Some(String::from("dumb"))
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct ColorizerOption {
|
||||
|
@ -140,7 +142,6 @@ impl<T: AsRef<str>> Format<T> {
|
|||
}
|
||||
|
||||
#[cfg(any(not(feature = "color"), target_os = "windows"))]
|
||||
#[cfg_attr(feature = "lints", allow(match_same_arms))]
|
||||
impl<T: fmt::Display> Format<T> {
|
||||
fn format(&self) -> &T {
|
||||
match *self {
|
||||
|
@ -154,12 +155,16 @@ impl<T: fmt::Display> Format<T> {
|
|||
|
||||
#[cfg(all(feature = "color", not(target_os = "windows")))]
|
||||
impl<T: AsRef<str>> fmt::Display for Format<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.format()) }
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", &self.format())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(not(feature = "color"), target_os = "windows"))]
|
||||
impl<T: fmt::Display> fmt::Display for Format<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.format()) }
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", &self.format())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "color", not(target_os = "windows")))]
|
||||
|
|
|
@ -22,10 +22,14 @@ use unicode_width::UnicodeWidthStr;
|
|||
|
||||
#[cfg(not(feature = "wrap_help"))]
|
||||
mod term_size {
|
||||
pub fn dimensions() -> Option<(usize, usize)> { None }
|
||||
pub fn dimensions() -> Option<(usize, usize)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn str_width(s: &str) -> usize { UnicodeWidthStr::width(s) }
|
||||
fn str_width(s: &str) -> usize {
|
||||
UnicodeWidthStr::width(s)
|
||||
}
|
||||
|
||||
const TAB: &str = " ";
|
||||
|
||||
|
|
|
@ -18,7 +18,9 @@ where
|
|||
}
|
||||
|
||||
impl<'b, 'c, 'z> Usage<'b, 'c, 'z> {
|
||||
pub fn new(p: &'z Parser<'b, 'c>) -> Self { Usage { p } }
|
||||
pub fn new(p: &'z Parser<'b, 'c>) -> Self {
|
||||
Usage { p }
|
||||
}
|
||||
|
||||
// Creates a usage string for display. This happens just after all arguments were parsed, but before
|
||||
// any subcommands have been parsed (so as to give subcommands their own usage recursively)
|
||||
|
|
|
@ -18,19 +18,27 @@ type Id = u64;
|
|||
pub struct ArgMatcher(pub ArgMatches);
|
||||
|
||||
impl Default for ArgMatcher {
|
||||
fn default() -> Self { ArgMatcher(ArgMatches::default()) }
|
||||
fn default() -> Self {
|
||||
ArgMatcher(ArgMatches::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ArgMatcher {
|
||||
type Target = ArgMatches;
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ArgMatcher {
|
||||
pub fn into_inner(self) -> ArgMatches { self.0 }
|
||||
pub fn into_inner(self) -> ArgMatches {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn is_present(&self, name: Id) -> bool { self.0._id_is_present(name) }
|
||||
pub fn is_present(&self, name: Id) -> bool {
|
||||
self.0._id_is_present(name)
|
||||
}
|
||||
|
||||
pub fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
|
||||
debugln!(
|
||||
|
@ -77,11 +85,17 @@ impl ArgMatcher {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, arg: Id) -> Option<&mut MatchedArg> { self.0.args.get_mut(&arg) }
|
||||
pub fn get_mut(&mut self, arg: Id) -> Option<&mut MatchedArg> {
|
||||
self.0.args.get_mut(&arg)
|
||||
}
|
||||
|
||||
pub fn get(&self, arg: Id) -> Option<&MatchedArg> { self.0.args.get(&arg) }
|
||||
pub fn get(&self, arg: Id) -> Option<&MatchedArg> {
|
||||
self.0.args.get(&arg)
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, arg: Id) { self.0.args.swap_remove(&arg); }
|
||||
pub fn remove(&mut self, arg: Id) {
|
||||
self.0.args.swap_remove(&arg);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn remove_all(&mut self, args: &[Id]) {
|
||||
|
@ -90,23 +104,37 @@ impl ArgMatcher {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, name: Id) { self.0.args.insert(name, MatchedArg::new()); }
|
||||
pub fn insert(&mut self, name: Id) {
|
||||
self.0.args.insert(name, MatchedArg::new());
|
||||
}
|
||||
|
||||
pub fn contains(&self, arg: Id) -> bool { self.0.args.contains_key(&arg) }
|
||||
pub fn contains(&self, arg: Id) -> bool {
|
||||
self.0.args.contains_key(&arg)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool { self.0.args.is_empty() }
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.args.is_empty()
|
||||
}
|
||||
|
||||
pub fn arg_names(&self) -> indexmap::map::Keys<Id, MatchedArg> { self.0.args.keys() }
|
||||
pub fn arg_names(&self) -> indexmap::map::Keys<Id, MatchedArg> {
|
||||
self.0.args.keys()
|
||||
}
|
||||
|
||||
pub fn entry(&mut self, arg: Id) -> indexmap::map::Entry<Id, MatchedArg> {
|
||||
self.0.args.entry(arg)
|
||||
}
|
||||
|
||||
pub fn subcommand(&mut self, sc: SubCommand) { self.0.subcommand = Some(Box::new(sc)); }
|
||||
pub fn subcommand(&mut self, sc: SubCommand) {
|
||||
self.0.subcommand = Some(Box::new(sc));
|
||||
}
|
||||
|
||||
pub fn subcommand_name(&self) -> Option<&str> { self.0.subcommand_name() }
|
||||
pub fn subcommand_name(&self) -> Option<&str> {
|
||||
self.0.subcommand_name()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> indexmap::map::Iter<Id, MatchedArg> { self.0.args.iter() }
|
||||
pub fn iter(&self) -> indexmap::map::Iter<Id, MatchedArg> {
|
||||
self.0.args.iter()
|
||||
}
|
||||
|
||||
pub fn inc_occurrence_of(&mut self, arg: Id) {
|
||||
debugln!("ArgMatcher::inc_occurrence_of: arg={}", arg);
|
||||
|
|
|
@ -414,7 +414,9 @@ impl Error {
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn write_to<W: Write>(&self, w: &mut W) -> io::Result<()> { write!(w, "{}", self.message) }
|
||||
pub fn write_to<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
write!(w, "{}", self.message)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn group_conflict<O, U>(
|
||||
|
@ -983,8 +985,8 @@ impl Error {
|
|||
when: color,
|
||||
});
|
||||
Error {
|
||||
cause: e.description().to_string(),
|
||||
message: format!("{} {}", c.error("error:"), e.description()),
|
||||
cause: e.to_string(),
|
||||
message: format!("{} {}", c.error("error:"), e),
|
||||
kind: ErrorKind::Io,
|
||||
info: None,
|
||||
}
|
||||
|
@ -1016,34 +1018,40 @@ impl Error {
|
|||
///
|
||||
/// This can be used in combination with `Error::exit` to exit your program
|
||||
/// with a custom error message.
|
||||
pub fn with_description(description: &str, kind: ErrorKind) -> Self {
|
||||
pub fn with_description(description: impl Into<String>, kind: ErrorKind) -> Self {
|
||||
let c = Colorizer::new(&ColorizerOption {
|
||||
use_stderr: true,
|
||||
when: ColorWhen::Auto,
|
||||
});
|
||||
|
||||
let cause = description.into();
|
||||
let message = format!("{} {}", c.error("error:"), cause);
|
||||
|
||||
Error {
|
||||
cause: description.to_string(),
|
||||
message: format!("{} {}", c.error("error:"), description),
|
||||
cause,
|
||||
message,
|
||||
kind,
|
||||
info: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for Error {
|
||||
fn description(&self) -> &str { &*self.message }
|
||||
}
|
||||
impl StdError for Error {}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut std_fmt::Formatter) -> std_fmt::Result { writeln!(f, "{}", self.message) }
|
||||
fn fmt(&self, f: &mut std_fmt::Formatter) -> std_fmt::Result {
|
||||
writeln!(f, "{}", self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(e: io::Error) -> Self { Error::with_description(e.description(), ErrorKind::Io) }
|
||||
fn from(e: io::Error) -> Self {
|
||||
Error::with_description(e.to_string(), ErrorKind::Io)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std_fmt::Error> for Error {
|
||||
fn from(e: std_fmt::Error) -> Self {
|
||||
Error::with_description(e.description(), ErrorKind::Format)
|
||||
Error::with_description(e.to_string(), ErrorKind::Format)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ use crate::output::fmt::Format;
|
|||
/// Thus in a list of possible values like ["foo", "bar"], the value "fop" will yield
|
||||
/// `Some("foo")`, whereas "blark" would yield `None`.
|
||||
#[cfg(feature = "suggestions")]
|
||||
#[cfg_attr(feature = "lints", allow(needless_lifetimes))]
|
||||
pub fn did_you_mean<T, I>(v: &str, possible_values: I) -> Option<String>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
|
@ -39,7 +38,6 @@ where
|
|||
}
|
||||
|
||||
/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
|
||||
#[cfg_attr(feature = "lints", allow(needless_lifetimes))]
|
||||
pub fn did_you_mean_flag_suffix<I, T>(
|
||||
arg: &str,
|
||||
longs: I,
|
||||
|
|
|
@ -214,7 +214,9 @@ impl ArgMatches {
|
|||
/// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
|
||||
pub fn values_of<T: Key>(&self, id: T) -> Option<Values<'_>> {
|
||||
self.args.get(&id.key()).map(|arg| {
|
||||
fn to_str_slice(o: &OsString) -> &str { o.to_str().expect(INVALID_UTF8) }
|
||||
fn to_str_slice(o: &OsString) -> &str {
|
||||
o.to_str().expect(INVALID_UTF8)
|
||||
}
|
||||
let to_str_slice: fn(&OsString) -> &str = to_str_slice; // coerce to fn pointer
|
||||
|
||||
Values {
|
||||
|
@ -288,7 +290,9 @@ impl ArgMatches {
|
|||
/// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html
|
||||
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
|
||||
pub fn values_of_os<'a, T: Key>(&'a self, id: T) -> Option<OsValues<'a>> {
|
||||
fn to_str_slice(o: &OsString) -> &OsStr { &*o }
|
||||
fn to_str_slice(o: &OsString) -> &OsStr {
|
||||
&*o
|
||||
}
|
||||
let to_str_slice: fn(&'a OsString) -> &'a OsStr = to_str_slice; // coerce to fn pointer
|
||||
|
||||
self.args.get(&id.key()).map(|arg| OsValues {
|
||||
|
@ -311,7 +315,9 @@ impl ArgMatches {
|
|||
///
|
||||
/// assert!(m.is_present("debug"));
|
||||
/// ```
|
||||
pub fn is_present<T: Key>(&self, id: T) -> bool { self._id_is_present(id.key()) }
|
||||
pub fn is_present<T: Key>(&self, id: T) -> bool {
|
||||
self._id_is_present(id.key())
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn _id_is_present(&self, arg_id: Id) -> bool {
|
||||
|
@ -682,7 +688,9 @@ impl ArgMatches {
|
|||
/// [`Subcommand`]: ./struct..html
|
||||
/// [`App`]: ./struct.App.html
|
||||
/// [`ArgMatches`]: ./struct.ArgMatches.html
|
||||
pub fn subcommand_name(&self) -> Option<&str> { self.subcommand.as_ref().map(|sc| &*sc.name) }
|
||||
pub fn subcommand_name(&self) -> Option<&str> {
|
||||
self.subcommand.as_ref().map(|sc| &*sc.name)
|
||||
}
|
||||
|
||||
/// This brings together [`ArgMatches::subcommand_matches`] and [`ArgMatches::subcommand_name`]
|
||||
/// by returning a tuple with both pieces of information.
|
||||
|
@ -773,12 +781,18 @@ pub struct Values<'a> {
|
|||
impl<'a> Iterator for Values<'a> {
|
||||
type Item = &'a str;
|
||||
|
||||
fn next(&mut self) -> Option<&'a str> { self.iter.next() }
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
|
||||
fn next(&mut self) -> Option<&'a str> {
|
||||
self.iter.next()
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for Values<'a> {
|
||||
fn next_back(&mut self) -> Option<&'a str> { self.iter.next_back() }
|
||||
fn next_back(&mut self) -> Option<&'a str> {
|
||||
self.iter.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for Values<'a> {}
|
||||
|
@ -788,7 +802,9 @@ impl<'a> Default for Values<'a> {
|
|||
fn default() -> Self {
|
||||
static EMPTY: [OsString; 0] = [];
|
||||
// This is never called because the iterator is empty:
|
||||
fn to_str_slice(_: &OsString) -> &str { unreachable!() };
|
||||
fn to_str_slice(_: &OsString) -> &str {
|
||||
unreachable!()
|
||||
};
|
||||
Values {
|
||||
iter: EMPTY[..].iter().map(to_str_slice),
|
||||
}
|
||||
|
@ -825,12 +841,18 @@ pub struct OsValues<'a> {
|
|||
impl<'a> Iterator for OsValues<'a> {
|
||||
type Item = &'a OsStr;
|
||||
|
||||
fn next(&mut self) -> Option<&'a OsStr> { self.iter.next() }
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
|
||||
fn next(&mut self) -> Option<&'a OsStr> {
|
||||
self.iter.next()
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for OsValues<'a> {
|
||||
fn next_back(&mut self) -> Option<&'a OsStr> { self.iter.next_back() }
|
||||
fn next_back(&mut self) -> Option<&'a OsStr> {
|
||||
self.iter.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for OsValues<'a> {}
|
||||
|
@ -840,7 +862,9 @@ impl<'a> Default for OsValues<'a> {
|
|||
fn default() -> Self {
|
||||
static EMPTY: [OsString; 0] = [];
|
||||
// This is never called because the iterator is empty:
|
||||
fn to_str_slice(_: &OsString) -> &OsStr { unreachable!() };
|
||||
fn to_str_slice(_: &OsString) -> &OsStr {
|
||||
unreachable!()
|
||||
};
|
||||
OsValues {
|
||||
iter: EMPTY[..].iter().map(to_str_slice),
|
||||
}
|
||||
|
@ -878,12 +902,18 @@ pub struct Indices<'a> {
|
|||
impl<'a> Iterator for Indices<'a> {
|
||||
type Item = usize;
|
||||
|
||||
fn next(&mut self) -> Option<usize> { self.iter.next() }
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
|
||||
fn next(&mut self) -> Option<usize> {
|
||||
self.iter.next()
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for Indices<'a> {
|
||||
fn next_back(&mut self) -> Option<usize> { self.iter.next_back() }
|
||||
fn next_back(&mut self) -> Option<usize> {
|
||||
self.iter.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for Indices<'a> {}
|
||||
|
|
|
@ -23,7 +23,9 @@ impl Default for MatchedArg {
|
|||
}
|
||||
|
||||
impl MatchedArg {
|
||||
pub fn new() -> Self { MatchedArg::default() }
|
||||
pub fn new() -> Self {
|
||||
MatchedArg::default()
|
||||
}
|
||||
pub(crate) fn contains_val(&self, val: &str) -> bool {
|
||||
self.vals
|
||||
.iter()
|
||||
|
|
|
@ -4,10 +4,7 @@ use std::ffi::{OsStr, OsString};
|
|||
use std::io::Write;
|
||||
use std::iter::Peekable;
|
||||
use std::mem;
|
||||
#[cfg(all(
|
||||
feature = "debug",
|
||||
not(any(target_os = "windows", target_arch = "wasm32"))
|
||||
))]
|
||||
#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
// Internal
|
||||
|
@ -23,7 +20,7 @@ use crate::parse::errors::Result as ClapResult;
|
|||
use crate::parse::features::suggestions;
|
||||
use crate::parse::Validator;
|
||||
use crate::parse::{ArgMatcher, SubCommand};
|
||||
#[cfg(all(feature = "debug", any(target_os = "windows", target_arch = "wasm32")))]
|
||||
#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
|
||||
use crate::util::OsStrExt3;
|
||||
use crate::util::{self, ChildGraph, Key, OsStrExt2, EMPTY_HASH};
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
|
@ -81,8 +78,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))]
|
||||
fn _verify_positionals(&mut self) -> bool {
|
||||
fn _verify_positionals(&self) -> bool {
|
||||
debugln!("Parser::_verify_positionals;");
|
||||
// Because you must wait until all arguments have been supplied, this is the first chance
|
||||
// to make assertions on positional argument indexes
|
||||
|
@ -288,6 +284,7 @@ where
|
|||
true
|
||||
}
|
||||
|
||||
#[allow(clippy::block_in_if_condition_stmt)]
|
||||
// Does all the initializing and prepares the parser
|
||||
pub(crate) fn _build(&mut self) {
|
||||
debugln!("Parser::_build;");
|
||||
|
@ -720,11 +717,6 @@ where
|
|||
fn possible_subcommand(&self, arg_os: &OsStr) -> (bool, Option<&str>) {
|
||||
debugln!("Parser::possible_subcommand: arg={:?}", arg_os);
|
||||
fn starts(h: &str, n: &OsStr) -> bool {
|
||||
#[cfg(target_os = "windows")]
|
||||
use crate::util::OsStrExt3;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
let n_bytes = n.as_bytes();
|
||||
let h_bytes = OsStr::new(h).as_bytes();
|
||||
|
||||
|
@ -1050,7 +1042,6 @@ where
|
|||
.map(|_| ParseResult::NotFound)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "lints", allow(len_zero))]
|
||||
fn parse_short_arg(
|
||||
&mut self,
|
||||
matcher: &mut ArgMatcher,
|
||||
|
@ -1362,6 +1353,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub(crate) fn add_defaults(&mut self, matcher: &mut ArgMatcher) -> ClapResult<()> {
|
||||
debugln!("Parser::add_defaults;");
|
||||
macro_rules! add_val {
|
||||
|
@ -1567,26 +1559,43 @@ impl<'b, 'c> Parser<'b, 'c>
|
|||
where
|
||||
'b: 'c,
|
||||
{
|
||||
fn contains_short(&self, s: char) -> bool { self.app.contains_short(s) }
|
||||
fn contains_short(&self, s: char) -> bool {
|
||||
self.app.contains_short(s)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "lints", allow(needless_borrow))]
|
||||
pub(crate) fn has_args(&self) -> bool { self.app.has_args() }
|
||||
pub(crate) fn has_args(&self) -> bool {
|
||||
self.app.has_args()
|
||||
}
|
||||
|
||||
pub(crate) fn has_opts(&self) -> bool { self.app.has_opts() }
|
||||
pub(crate) fn has_opts(&self) -> bool {
|
||||
self.app.has_opts()
|
||||
}
|
||||
|
||||
pub(crate) fn has_flags(&self) -> bool { self.app.has_flags() }
|
||||
pub(crate) fn has_flags(&self) -> bool {
|
||||
self.app.has_flags()
|
||||
}
|
||||
|
||||
pub(crate) fn has_positionals(&self) -> bool {
|
||||
self.app.args.keys.iter().any(|x| x.key.is_position())
|
||||
}
|
||||
|
||||
pub(crate) fn has_subcommands(&self) -> bool { self.app.has_subcommands() }
|
||||
pub(crate) fn has_subcommands(&self) -> bool {
|
||||
self.app.has_subcommands()
|
||||
}
|
||||
|
||||
pub(crate) fn has_visible_subcommands(&self) -> bool { self.app.has_visible_subcommands() }
|
||||
pub(crate) fn has_visible_subcommands(&self) -> bool {
|
||||
self.app.has_visible_subcommands()
|
||||
}
|
||||
|
||||
pub(crate) fn is_set(&self, s: AS) -> bool { self.app.is_set(s) }
|
||||
pub(crate) fn is_set(&self, s: AS) -> bool {
|
||||
self.app.is_set(s)
|
||||
}
|
||||
|
||||
pub(crate) fn set(&mut self, s: AS) { self.app.set(s) }
|
||||
pub(crate) fn set(&mut self, s: AS) {
|
||||
self.app.set(s)
|
||||
}
|
||||
|
||||
pub(crate) fn unset(&mut self, s: AS) { self.app.unset(s) }
|
||||
pub(crate) fn unset(&mut self, s: AS) {
|
||||
self.app.unset(s)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,11 +24,15 @@ where
|
|||
pub(crate) struct FnvHasher(u64);
|
||||
|
||||
impl FnvHasher {
|
||||
pub(crate) fn new() -> Self { FnvHasher(MAGIC_INIT) }
|
||||
pub(crate) fn new() -> Self {
|
||||
FnvHasher(MAGIC_INIT)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hasher for FnvHasher {
|
||||
fn finish(&self) -> u64 { self.0 }
|
||||
fn finish(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
fn write(&mut self, bytes: &[u8]) {
|
||||
let FnvHasher(mut hash) = *self;
|
||||
|
||||
|
|
|
@ -5,7 +5,9 @@ struct Child<T> {
|
|||
}
|
||||
|
||||
impl<T> Child<T> {
|
||||
fn new(id: T) -> Self { Child { id, children: None } }
|
||||
fn new(id: T) -> Self {
|
||||
Child { id, children: None }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -15,7 +17,9 @@ impl<T> ChildGraph<T>
|
|||
where
|
||||
T: Sized + PartialEq + Copy + Clone,
|
||||
{
|
||||
pub fn with_capacity(s: usize) -> Self { ChildGraph(Vec::with_capacity(s)) }
|
||||
pub fn with_capacity(s: usize) -> Self {
|
||||
ChildGraph(Vec::with_capacity(s))
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, req: T) -> usize {
|
||||
if !self.contains(req) {
|
||||
|
@ -47,7 +51,11 @@ where
|
|||
c_idx
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &T> { self.0.iter().map(|r| &r.id) }
|
||||
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||
self.0.iter().map(|r| &r.id)
|
||||
}
|
||||
|
||||
pub fn contains(&self, req: T) -> bool { self.0.iter().any(|r| r.id == req) }
|
||||
pub fn contains(&self, req: T) -> bool {
|
||||
self.0.iter().any(|r| r.id == req)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,17 +22,25 @@ mod vec_map {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize { self.inner.len() }
|
||||
pub fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool { self.inner.is_empty() }
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: usize, value: V) -> Option<V> {
|
||||
self.inner.insert(key, value)
|
||||
}
|
||||
|
||||
pub fn values(&self) -> Values<V> { self.inner.values() }
|
||||
pub fn values(&self) -> Values<V> {
|
||||
self.inner.values()
|
||||
}
|
||||
|
||||
pub fn keys(&self) -> btree_map::Keys<usize, V> { self.inner.keys() }
|
||||
pub fn keys(&self) -> btree_map::Keys<usize, V> {
|
||||
self.inner.keys()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<V> {
|
||||
Iter {
|
||||
|
@ -40,11 +48,17 @@ mod vec_map {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn contains_key(&self, key: usize) -> bool { self.inner.contains_key(&key) }
|
||||
pub fn contains_key(&self, key: usize) -> bool {
|
||||
self.inner.contains_key(&key)
|
||||
}
|
||||
|
||||
pub fn entry(&mut self, key: usize) -> Entry<V> { self.inner.entry(key) }
|
||||
pub fn entry(&mut self, key: usize) -> Entry<V> {
|
||||
self.inner.entry(key)
|
||||
}
|
||||
|
||||
pub fn get(&self, key: usize) -> Option<&V> { self.inner.get(&key) }
|
||||
pub fn get(&self, key: usize) -> Option<&V> {
|
||||
self.inner.get(&key)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Values<'a, V> = btree_map::Values<'a, usize, V>;
|
||||
|
@ -65,7 +79,9 @@ mod vec_map {
|
|||
impl<'a, V: 'a> Iterator for Iter<'a, V> {
|
||||
type Item = (usize, &'a V);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> { self.inner.next().map(|(k, v)| (*k, v)) }
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.inner.next().map(|(k, v)| (*k, v))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: 'a> DoubleEndedIterator for Iter<'a, V> {
|
||||
|
|
|
@ -26,11 +26,15 @@ impl OsStrExt3 for OsStr {
|
|||
use std::mem;
|
||||
unsafe { mem::transmute(b) }
|
||||
}
|
||||
fn as_bytes(&self) -> &[u8] { self.to_str().map(|s| s.as_bytes()).expect(INVALID_UTF8) }
|
||||
fn as_bytes(&self) -> &[u8] {
|
||||
self.to_str().map(|s| s.as_bytes()).expect(INVALID_UTF8)
|
||||
}
|
||||
}
|
||||
|
||||
impl OsStrExt2 for OsStr {
|
||||
fn starts_with(&self, s: &[u8]) -> bool { self.as_bytes().starts_with(s) }
|
||||
fn starts_with(&self, s: &[u8]) -> bool {
|
||||
self.as_bytes().starts_with(s)
|
||||
}
|
||||
|
||||
fn contains_byte(&self, byte: u8) -> bool {
|
||||
for b in self.as_bytes() {
|
||||
|
|
|
@ -288,8 +288,7 @@ fn global_setting() {
|
|||
assert!(app
|
||||
.subcommands
|
||||
.iter()
|
||||
.filter(|s| s.name == "subcmd")
|
||||
.next()
|
||||
.find(|s| s.name == "subcmd")
|
||||
.unwrap()
|
||||
.is_set(AppSettings::ColoredHelp));
|
||||
}
|
||||
|
@ -304,15 +303,13 @@ fn global_settings() {
|
|||
assert!(app
|
||||
.subcommands
|
||||
.iter()
|
||||
.filter(|s| s.name == "subcmd")
|
||||
.next()
|
||||
.find(|s| s.name == "subcmd")
|
||||
.unwrap()
|
||||
.is_set(AppSettings::ColoredHelp));
|
||||
assert!(app
|
||||
.subcommands
|
||||
.iter()
|
||||
.filter(|s| s.name == "subcmd")
|
||||
.next()
|
||||
.find(|s| s.name == "subcmd")
|
||||
.unwrap()
|
||||
.is_set(AppSettings::TrailingVarArg));
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ fn template_author_version() {
|
|||
|
||||
// ----------
|
||||
|
||||
fn app_example1<'b, 'c>() -> App<'c> {
|
||||
fn app_example1<'c>() -> App<'c> {
|
||||
App::new("MyApp")
|
||||
.version("1.0")
|
||||
.author("Kevin K. <kbknapp@gmail.com>")
|
||||
|
|
|
@ -338,7 +338,9 @@ subcmd NOT present
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn long_opt_x2_pos() { check_complex_output("clap-test value --option some --option other", O2P); }
|
||||
fn long_opt_x2_pos() {
|
||||
check_complex_output("clap-test value --option some --option other", O2P);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_opt_eq_x2_pos() {
|
||||
|
@ -346,19 +348,29 @@ fn long_opt_eq_x2_pos() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn short_opt_x2_pos() { check_complex_output("clap-test value -o some -o other", O2P); }
|
||||
fn short_opt_x2_pos() {
|
||||
check_complex_output("clap-test value -o some -o other", O2P);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_opt_eq_x2_pos() { check_complex_output("clap-test value -o=some -o=other", O2P); }
|
||||
fn short_opt_eq_x2_pos() {
|
||||
check_complex_output("clap-test value -o=some -o=other", O2P);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_flag_x2_comb_short_opt_pos() { check_complex_output("clap-test value -ff -o some", F2OP); }
|
||||
fn short_flag_x2_comb_short_opt_pos() {
|
||||
check_complex_output("clap-test value -ff -o some", F2OP);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_flag_short_opt_pos() { check_complex_output("clap-test value -f -o some", FOP); }
|
||||
fn short_flag_short_opt_pos() {
|
||||
check_complex_output("clap-test value -f -o some", FOP);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_flag_long_opt_pos() { check_complex_output("clap-test value --flag --option some", FOP); }
|
||||
fn long_flag_long_opt_pos() {
|
||||
check_complex_output("clap-test value --flag --option some", FOP);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn long_flag_long_opt_eq_pos() {
|
||||
|
|
Loading…
Reference in a new issue