Merge pull request #1648 from clap-rs/maintain

Some maintainance stuff
This commit is contained in:
Pavan Kumar Sunkara 2020-02-01 12:23:50 +01:00 committed by GitHub
commit 4740b1e05b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 529 additions and 391 deletions

View file

@ -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"

View file

@ -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

View file

@ -1,9 +0,0 @@
{
"findPotentialReviewers": false,
"alwaysNotifyForPaths": [
{
"name": "kbknapp",
"files": ["**/*.rs", "**/*.md", "*"]
}
]
}

View file

@ -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=

View file

@ -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![""]));
}

View file

@ -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) {

View file

@ -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) {

View file

@ -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 {

View file

@ -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) {

View file

@ -1,2 +0,0 @@
format_strings = false
fn_single_line = true

View file

@ -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");

View file

@ -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);

View file

@ -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,
};

View file

@ -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" => {

View file

@ -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))]

View file

@ -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)]

View file

@ -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!(

View file

@ -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"])
);

View file

@ -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)]

View file

@ -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]
}
);

View file

@ -140,8 +140,6 @@ enum Opt4 {
#[test]
fn test_tuple_commands() {
use clap::IntoApp;
assert_eq!(
Opt4::Add(Add {
file: "f".to_string()

View file

@ -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);

View file

@ -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

View file

@ -1,2 +0,0 @@
format_strings = false
fn_single_line = true

View file

@ -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)
}
}

View file

@ -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!(

View file

@ -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> {}

View file

@ -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

View file

@ -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

View file

@ -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'");

View file

@ -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
//!

View file

@ -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

View file

@ -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")))]

View file

@ -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 = " ";

View file

@ -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)

View file

@ -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);

View file

@ -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)
}
}

View file

@ -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,

View file

@ -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> {}

View file

@ -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()

View file

@ -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)
}
}

View file

@ -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;

View file

@ -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)
}
}

View file

@ -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> {

View file

@ -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() {

View file

@ -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));
}

View file

@ -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>")

View file

@ -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() {