From abd7be33623c5effa58904fc2ef5d070c4cdfd7e Mon Sep 17 00:00:00 2001 From: Kevin K Date: Tue, 12 Jun 2018 09:51:07 -0400 Subject: [PATCH 01/10] Merge pull request #1247 from tormol/osstringext_cleanup Remove unused or unnecessary methods from osstringext --- src/app/parser.rs | 13 +++++++------ src/app/validator.rs | 3 +-- src/osstringext.rs | 38 ++------------------------------------ 3 files changed, 10 insertions(+), 44 deletions(-) diff --git a/src/app/parser.rs b/src/app/parser.rs index 1d5bc63e..d647d485 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -384,8 +384,9 @@ where self.unset(AS::ValidNegNumFound); // Is this a new argument, or values from a previous option? let starts_new_arg = self.is_new_arg(&arg_os, needs_val_of); - if !self.is_set(AS::TrailingValues) && - arg_os.starts_with(b"--") && arg_os.len_() == 2 && starts_new_arg { + if !self.is_set(AS::TrailingValues) && arg_os.starts_with(b"--") && arg_os.len() == 2 + && starts_new_arg + { debugln!("Parser::get_matches_with: setting TrailingVals=true"); self.set(AS::TrailingValues); continue; @@ -430,7 +431,7 @@ where } _ => (), } - } else if arg_os.starts_with(b"-") && arg_os.len_() != 1 { + } else if arg_os.starts_with(b"-") && arg_os.len() != 1 { // Try to parse short args like normal, if AllowLeadingHyphen or // AllowNegativeNumbers is set, parse_short_arg will *not* throw // an error, and instead return Ok(None) @@ -1149,7 +1150,7 @@ where if let Some(fv) = val { has_eq = fv.starts_with(&[b'=']) || had_eq; let v = fv.trim_left_matches(b'='); - if !empty_vals && (v.len_() == 0 || (needs_eq && !has_eq)) { + if !empty_vals && (v.len() == 0 || (needs_eq && !has_eq)) { sdebugln!("Found Empty - Error"); return Err(ClapError::empty_value( opt, @@ -1157,7 +1158,7 @@ where self.app.color(), )); } - sdebugln!("Found - {:?}, len: {}", v, v.len_()); + sdebugln!("Found - {:?}, len: {}", v, v.len()); debugln!( "Parser::parse_opt: {:?} contains '='...{:?}", fv, @@ -1208,7 +1209,7 @@ where ); if !(self.is_set(AS::TrailingValues) && self.is_set(AS::DontDelimitTrailingValues)) { if let Some(delim) = arg.val_delim { - if val.is_empty_() { + if val.is_empty() { Ok(self.add_single_val_to_arg(arg, val, matcher)?) } else { let mut iret = ParseResult::ValuesDone; diff --git a/src/app/validator.rs b/src/app/validator.rs index 4446e990..05947439 100644 --- a/src/app/validator.rs +++ b/src/app/validator.rs @@ -9,7 +9,6 @@ use args::{Arg, ArgMatcher, MatchedArg}; use args::settings::ArgSettings; use errors::{Error, ErrorKind}; use errors::Result as ClapResult; -use osstringext::OsStrExt2; use app::settings::AppSettings as AS; use app::parser::{ParseResult, Parser}; use fmt::{Colorizer, ColorizerOption}; @@ -110,7 +109,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> { )); } } - if !arg.is_set(ArgSettings::AllowEmptyValues) && val.is_empty_() + if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty() && matcher.contains(&*arg.name) { debugln!("Validator::validate_arg_values: illegal empty val found"); diff --git a/src/osstringext.rs b/src/osstringext.rs index b05bf2f1..3539feee 100644 --- a/src/osstringext.rs +++ b/src/osstringext.rs @@ -16,9 +16,7 @@ pub trait OsStrExt2 { fn split_at_byte(&self, b: u8) -> (&OsStr, &OsStr); fn split_at(&self, i: usize) -> (&OsStr, &OsStr); fn trim_left_matches(&self, b: u8) -> &OsStr; - fn len_(&self) -> usize; fn contains_byte(&self, b: u8) -> bool; - fn is_empty_(&self) -> bool; fn split(&self, b: u8) -> OsSplit; } @@ -34,8 +32,6 @@ impl OsStrExt3 for OsStr { impl OsStrExt2 for OsStr { fn starts_with(&self, s: &[u8]) -> bool { self.as_bytes().starts_with(s) } - fn is_empty_(&self) -> bool { self.as_bytes().is_empty() } - fn contains_byte(&self, byte: u8) -> bool { for b in self.as_bytes() { if b == &byte { @@ -56,7 +52,7 @@ impl OsStrExt2 for OsStr { } ( &*self, - OsStr::from_bytes(&self.as_bytes()[self.len_()..self.len_()]), + OsStr::from_bytes(&self.as_bytes()[self.len()..self.len()]), ) } @@ -70,7 +66,7 @@ impl OsStrExt2 for OsStr { } } if found { - return OsStr::from_bytes(&self.as_bytes()[self.len_()..]); + return OsStr::from_bytes(&self.as_bytes()[self.len()..]); } &*self } @@ -82,8 +78,6 @@ impl OsStrExt2 for OsStr { ) } - fn len_(&self) -> usize { self.as_bytes().len() } - fn split(&self, b: u8) -> OsSplit { OsSplit { sep: b, @@ -118,32 +112,4 @@ impl<'a> Iterator for OsSplit<'a> { } Some(OsStr::from_bytes(&self.val[start..])) } - fn size_hint(&self) -> (usize, Option) { - let mut count = 0; - for b in &self.val[self.pos..] { - if *b == self.sep { - count += 1; - } - } - if count > 0 { - return (count, Some(count)); - } - (0, None) - } -} - -impl<'a> DoubleEndedIterator for OsSplit<'a> { - fn next_back(&mut self) -> Option<&'a OsStr> { - if self.pos == 0 { - return None; - } - let start = self.pos; - for b in self.val[..self.pos].iter().rev() { - self.pos -= 1; - if *b == self.sep { - return Some(OsStr::from_bytes(&self.val[self.pos + 1..start])); - } - } - Some(OsStr::from_bytes(&self.val[..start])) - } } From 4ebede6d9a497f2b1ceb4e168220fc273ed99fa8 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Tue, 12 Jun 2018 09:53:22 -0400 Subject: [PATCH 02/10] Merge pull request #1271 from stevepentland/wasm-windows-fix Include guards around os-specific string elements. --- src/app/parser.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/parser.rs b/src/app/parser.rs index d647d485..b76f4059 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -1,8 +1,11 @@ // Std use std::ffi::{OsStr, OsString}; use std::io::{self, BufWriter, Write}; -#[cfg(all(feature = "debug", not(target_arch = "wasm32")))] +#[cfg(all(feature = "debug", not(any(target_os = "windows", target_arch = "wasm32"))))] use std::os::unix::ffi::OsStrExt; +#[cfg(all(feature = "debug", any(target_os = "windows", target_arch = "wasm32")))] +use osstringext::OsStrExt3; +use std::path::PathBuf; use std::slice::Iter; use std::iter::Peekable; use std::mem; From af3264d559ae173206ba40f7c20f2a0495a95ca5 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Tue, 12 Jun 2018 09:54:19 -0400 Subject: [PATCH 03/10] Merge pull request #1272 from bspeice/patch-1 examples: Method rename --- examples/05_flag_args.rs | 6 +++--- examples/06_positional_args.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/05_flag_args.rs b/examples/05_flag_args.rs index 3540b064..3a1bb429 100644 --- a/examples/05_flag_args.rs +++ b/examples/05_flag_args.rs @@ -28,10 +28,10 @@ fn main() { // requires_all(Vec<&str>) .conflicts_with("output") // Opposite of requires(), says "if the // user uses -a, they CANNOT use 'output'" - // also has a mutually_excludes_all(Vec<&str>) + // also has a conflicts_with_all(Vec<&str>) ) - // NOTE: In order to compile this example, comment out requres() and - // mutually_excludes() because we have not defined an "output" or "config" + // NOTE: In order to compile this example, comment out requires() and + // conflicts_with() because we have not defined an "output" or "config" // argument. .get_matches(); diff --git a/examples/06_positional_args.rs b/examples/06_positional_args.rs index a5788c14..12320ed7 100644 --- a/examples/06_positional_args.rs +++ b/examples/06_positional_args.rs @@ -24,7 +24,7 @@ fn main() { // requires_all(Vec<&str>) .conflicts_with("output") // Opposite of requires(), says "if the // user uses -a, they CANNOT use 'output'" - // also has a mutually_excludes_all(Vec<&str>) + // also has a conflicts_with_all(Vec<&str>) .required(true) // By default this argument MUST be present // NOTE: mutual exclusions take precedence over // required arguments @@ -37,7 +37,7 @@ fn main() { // Note, we also do not need to specify requires("input") // because requires lists are automatically two-way - // NOTE: In order to compile this example, comment out mutually_excludes() + // NOTE: In order to compile this example, comment out conflicts_with() // because we have not defined an "output" argument. .get_matches(); From b4b4ab629d13790a895d9b6c874a287ad8f861e7 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Tue, 12 Jun 2018 09:55:44 -0400 Subject: [PATCH 04/10] chore: forgot pre html tag --- .github/ISSUE_TEMPLATE.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index b10cc73d..8367b541 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -31,3 +31,14 @@ Compile clap with cargo features `"debug"` such as: clap = { version = "2", features = ["debug"] } ``` The output may be very long, so feel free to link to a gist or attach a text file + +
+ Debug Output +
+
+
+Paste Debug Output Here
+
+
+
+
From 24d5fb3202befea5739d63be9a4fbbefa8423809 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Tue, 12 Jun 2018 10:01:42 -0400 Subject: [PATCH 05/10] test: Added regression tests for Issue 897 --- tests/help.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/tests/help.rs b/tests/help.rs index 1fc101ae..6713f6ca 100644 --- a/tests/help.rs +++ b/tests/help.rs @@ -1443,4 +1443,49 @@ fn multiple_custom_help_headers() { MULTIPLE_CUSTOM_HELP_SECTIONS, false )); -} \ No newline at end of file +} + +static ISSUE_897: &'static str = "ctest-foo 0.1 +Long about foo + +USAGE: + ctest foo + +FLAGS: + -h, --help + Prints help information + + -V, --version + Prints version information"; + +#[test] +fn show_long_about_issue_897() { + let app = App::new("ctest") + .version("0.1") + .subcommand(SubCommand::with_name("foo") + .version("0.1") + .about("About foo") + .long_about("Long about foo")); + assert!(test::compare_output(app, "ctest foo --help", ISSUE_897, false)); +} + +static ISSUE_897_SHORT: &'static str = "ctest-foo 0.1 +Long about foo + +USAGE: + ctest foo + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information"; + +#[test] +fn show_short_about_issue_897() { + let app = App::new("ctest") + .version("0.1") + .subcommand(SubCommand::with_name("foo") + .version("0.1") + .about("About foo") + .long_about("Long about foo")); + assert!(test::compare_output(app, "ctest foo -h", ISSUE_897_SHORT, false)); +} From df35813d17d5dd40fd97de254270cfa4b0be814f Mon Sep 17 00:00:00 2001 From: Alan K Date: Sat, 2 Jun 2018 16:10:34 +0200 Subject: [PATCH 06/10] fix: fixes compilation errors form cherry picked commits --- src/app/parser.rs | 15 +++++++-------- src/app/validator.rs | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/app/parser.rs b/src/app/parser.rs index b76f4059..a4f28618 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -5,7 +5,6 @@ use std::io::{self, BufWriter, Write}; use std::os::unix::ffi::OsStrExt; #[cfg(all(feature = "debug", any(target_os = "windows", target_arch = "wasm32")))] use osstringext::OsStrExt3; -use std::path::PathBuf; use std::slice::Iter; use std::iter::Peekable; use std::mem; @@ -799,7 +798,7 @@ where // Is this a new argument, or values from a previous option? let mut ret = if arg_os.starts_with(b"--") { debugln!("Parser::is_new_arg: -- found"); - if arg_os.len_() == 2 && !arg_allows_tac { + if arg_os.len() == 2 && !arg_allows_tac { return true; // We have to return true so override everything else } else if arg_allows_tac { return false; @@ -808,7 +807,7 @@ where } else if arg_os.starts_with(b"-") { debugln!("Parser::is_new_arg: - found"); // a singe '-' by itself is a value and typically means "stdin" on unix systems - !(arg_os.len_() == 1) + !(arg_os.len() == 1) } else { debugln!("Parser::is_new_arg: probably value"); false @@ -932,21 +931,21 @@ where fn use_long_help(&self) -> bool { debugln!("Parser::use_long_help;"); - // In this case, both must be checked. This allows the retention of + // In this case, both must be checked. This allows the retention of // original formatting, but also ensures that the actual -h or --help // specified by the user is sent through. If HiddenShortHelp is not included, // then items specified with hidden_short_help will also be hidden. let should_long = |v: &Arg| { - v.long_help.is_some() || - v.is_set(ArgSettings::HiddenLongHelp) || - v.is_set(ArgSettings::HiddenShortHelp) + v.long_help.is_some() || + v.is_set(ArgSettings::HiddenLongHelp) || + v.is_set(ArgSettings::HiddenShortHelp) }; self.app.long_about.is_some() || args!(self.app).any(|f| should_long(&f)) || subcommands!(self.app).any(|s| s.long_about.is_some()) } - + // fn _help(&self, mut use_long: bool) -> ClapError { // debugln!("Parser::_help: use_long={:?}", use_long && self.use_long_help()); // use_long = use_long && self.use_long_help(); diff --git a/src/app/validator.rs b/src/app/validator.rs index 05947439..deef95b7 100644 --- a/src/app/validator.rs +++ b/src/app/validator.rs @@ -109,7 +109,7 @@ impl<'a, 'b, 'c, 'z> Validator<'a, 'b, 'c, 'z> { )); } } - if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty() + if !arg.is_set(ArgSettings::AllowEmptyValues) && val.is_empty() && matcher.contains(&*arg.name) { debugln!("Validator::validate_arg_values: illegal empty val found"); From 746640fafb7095e1b35a5ae0cd60ec48524c9335 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Tue, 12 Jun 2018 10:09:34 -0400 Subject: [PATCH 07/10] imp(Help): always uses long about with the main help message in subcommands. Thanks to @savish --- src/app/help.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/app/help.rs b/src/app/help.rs index 627975f2..0ea272df 100644 --- a/src/app/help.rs +++ b/src/app/help.rs @@ -845,20 +845,12 @@ impl<'w> Help<'w> { if let Some(author) = parser.app.author { write_thing!(author) } - if self.use_long { - if let Some(about) = parser.app.long_about { - debugln!("Help::write_default_help: writing long about"); - write_thing!(about) - } else if let Some(about) = parser.app.about { - debugln!("Help::write_default_help: writing about"); - write_thing!(about) - } + if let Some(about) = parser.app.long_about { + debugln!("Help::write_default_help: writing long about"); + write_thing!(about) } else if let Some(about) = parser.app.about { debugln!("Help::write_default_help: writing about"); write_thing!(about) - } else if let Some(about) = parser.app.long_about { - debugln!("Help::write_default_help: writing long about"); - write_thing!(about) } color!(self, "\nUSAGE:", warning)?; From c010a9d445e1d3945005fe6daa3ce44c188795b6 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Tue, 12 Jun 2018 10:10:03 -0400 Subject: [PATCH 08/10] chore: removes doc profile --- Cargo.toml | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2a11f4e3..ed41dee9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,12 +5,12 @@ version = "3.0.0-alpha1" authors = ["Kevin K. "] exclude = [ ".github/*", - "examples/*", - "tests/*", - "benches/*", - "clap-perf/*", + "examples/*", + "tests/*", + "benches/*", + "clap-perf/*", "etc/*", - "*.png", + "*.png", "*.dot", "*.yml", "*.toml", @@ -18,8 +18,8 @@ exclude = [ "clap-test.rs" ] include = [ - "src/**/*", - "Cargo.toml", + "src/**/*", + "Cargo.toml", "README.md" ] repository = "https://github.com/kbknapp/clap-rs" @@ -28,10 +28,10 @@ homepage = "https://clap.rs/" readme = "README.md" license = "MIT" keywords = [ - "argument", - "cli", - "arg", - "parser", + "argument", + "cli", + "arg", + "parser", "parse" ] categories = ["command-line-interface"] @@ -112,13 +112,5 @@ lto = true debug-assertions = false codegen-units = 1 -[profile.doc] -opt-level = 0 -debug = true -rpath = false -lto = false -debug-assertions = true -codegen-units = 4 - [package.metadata.docs.rs] features = ["doc"] From b7e38fb62aa6e8a30d72dec063b1adccd089d0aa Mon Sep 17 00:00:00 2001 From: Kevin K Date: Tue, 12 Jun 2018 10:18:16 -0400 Subject: [PATCH 09/10] chore: update deps --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ed41dee9..7bc8ba92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ maintenance = {status = "actively-developed"} [dependencies] bitflags = "1.0" unicode-width = "0.1.4" -textwrap = "0.9.0" +textwrap = "0.10.0" ordermap = "0.3.5" strsim = { version = "0.7.0", optional = true } yaml-rust = { version = "0.3.5", optional = true } @@ -60,10 +60,10 @@ vec_map = { version = "0.8", optional = true } term_size = { version = "1.0.0-beta1", optional = true } [target.'cfg(not(windows))'.dependencies] -ansi_term = { version = "0.10.0", optional = true } +ansi_term = { version = "0.11.0", optional = true } [dev-dependencies] -regex = "0.2" +regex = "1.0" lazy_static = "1" version-sync = "0.5" From b033bb5abc7f27f4d640e9fd5605d8c92b1b3b5e Mon Sep 17 00:00:00 2001 From: Kevin K Date: Tue, 12 Jun 2018 10:22:18 -0400 Subject: [PATCH 10/10] chore: ordermap to indexmap --- Cargo.toml | 2 +- src/args/arg_matcher.rs | 8 ++++---- src/args/arg_matches.rs | 6 +++--- src/lib.rs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7bc8ba92..cdcfd5b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ maintenance = {status = "actively-developed"} bitflags = "1.0" unicode-width = "0.1.4" textwrap = "0.10.0" -ordermap = "0.3.5" +indexmap = "1.0.1" strsim = { version = "0.7.0", optional = true } yaml-rust = { version = "0.3.5", optional = true } clippy = { version = "~0.0.166", optional = true } diff --git a/src/args/arg_matcher.rs b/src/args/arg_matcher.rs index e2969f34..f5e301ff 100644 --- a/src/args/arg_matcher.rs +++ b/src/args/arg_matcher.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use std::mem; // Third Party -use ordermap; +use indexmap; // Internal use args::{Arg, ArgMatches, MatchedArg, SubCommand}; @@ -90,9 +90,9 @@ impl<'a> ArgMatcher<'a> { pub fn usage(&mut self, usage: String) { self.0.usage = Some(usage); } - pub fn arg_names(&'a self) -> ordermap::Keys<&'a str, MatchedArg> { self.0.args.keys() } + pub fn arg_names(&'a self) -> indexmap::map::Keys<&'a str, MatchedArg> { self.0.args.keys() } - pub fn entry(&mut self, arg: &'a str) -> ordermap::Entry<&'a str, MatchedArg> { + pub fn entry(&mut self, arg: &'a str) -> indexmap::map::Entry<&'a str, MatchedArg> { self.0.args.entry(arg) } @@ -100,7 +100,7 @@ impl<'a> ArgMatcher<'a> { pub fn subcommand_name(&self) -> Option<&str> { self.0.subcommand_name() } - pub fn iter(&self) -> ordermap::Iter<&str, MatchedArg> { self.0.args.iter() } + pub fn iter(&self) -> indexmap::map::Iter<&str, MatchedArg> { self.0.args.iter() } pub fn inc_occurrence_of(&mut self, arg: &'a str) { debugln!("ArgMatcher::inc_occurrence_of: arg={}", arg); diff --git a/src/args/arg_matches.rs b/src/args/arg_matches.rs index c07ba8e4..17ec4d17 100644 --- a/src/args/arg_matches.rs +++ b/src/args/arg_matches.rs @@ -5,7 +5,7 @@ use std::iter::Map; use std::slice::Iter; // Third Party -use ordermap::OrderMap; +use indexmap::IndexMap; // Internal use INVALID_UTF8; @@ -62,7 +62,7 @@ use args::SubCommand; #[derive(Debug, Clone)] pub struct ArgMatches<'a> { #[doc(hidden)] - pub args: OrderMap<&'a str, MatchedArg>, + pub args: IndexMap<&'a str, MatchedArg>, #[doc(hidden)] pub subcommand: Option>>, #[doc(hidden)] @@ -72,7 +72,7 @@ pub struct ArgMatches<'a> { impl<'a> Default for ArgMatches<'a> { fn default() -> Self { ArgMatches { - args: OrderMap::new(), + args: IndexMap::new(), subcommand: None, usage: None, } diff --git a/src/lib.rs b/src/lib.rs index 5fa720aa..8bba431a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -536,7 +536,7 @@ extern crate ansi_term; extern crate atty; #[macro_use] extern crate bitflags; -extern crate ordermap; +extern crate indexmap; #[cfg(feature = "suggestions")] extern crate strsim; #[cfg(feature = "wrap_help")]