Merge pull request #1295 from kbknapp/v3-dev

updates v3 to latest v2 changes and fixes
This commit is contained in:
Kevin K 2018-06-12 10:26:15 -04:00 committed by GitHub
commit b7704575f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 108 additions and 100 deletions

View file

@ -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
<details>
<summary> Debug Output </summary>
<pre>
<code>
Paste Debug Output Here
</code>
</pre>
</details>

View file

@ -5,12 +5,12 @@ version = "3.0.0-alpha1"
authors = ["Kevin K. <kbknapp@gmail.com>"]
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"]
@ -50,8 +50,8 @@ maintenance = {status = "actively-developed"}
[dependencies]
bitflags = "1.0"
unicode-width = "0.1.4"
textwrap = "0.9.0"
ordermap = "0.3.5"
textwrap = "0.10.0"
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 }
@ -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"
@ -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"]

View file

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

View file

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

View file

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

View file

@ -1,8 +1,10 @@
// 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::slice::Iter;
use std::iter::Peekable;
use std::mem;
@ -384,8 +386,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 +433,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)
@ -795,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;
@ -804,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
@ -928,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();
@ -1149,7 +1152,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 +1160,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 +1211,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;

View file

@ -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::AllowEmptyValues) && val.is_empty()
&& matcher.contains(&*arg.name)
{
debugln!("Validator::validate_arg_values: illegal empty val found");

View file

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

View file

@ -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<Box<SubCommand<'a>>>,
#[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,
}

View file

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

View file

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

View file

@ -1443,4 +1443,49 @@ fn multiple_custom_help_headers() {
MULTIPLE_CUSTOM_HELP_SECTIONS,
false
));
}
}
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));
}