mirror of
https://github.com/clap-rs/clap
synced 2024-12-14 14:52:33 +00:00
commit
37cc3c367f
6 changed files with 66 additions and 32 deletions
|
@ -9,6 +9,7 @@ rust:
|
|||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
- rust: beta
|
||||
before_script:
|
||||
- |
|
||||
pip install 'travis-cargo<0.2' --user &&
|
||||
|
|
|
@ -150,7 +150,7 @@ impl<'a> Help<'a> {
|
|||
debugln!("fn=Help::write_help;");
|
||||
if let Some(h) = parser.meta.help_str {
|
||||
try!(write!(self.writer, "{}", h).map_err(Error::from));
|
||||
} else if let Some(ref tmpl) = parser.meta.template {
|
||||
} else if let Some(tmpl) = parser.meta.template {
|
||||
try!(self.write_templated_help(&parser, tmpl));
|
||||
} else {
|
||||
try!(self.write_default_help(&parser));
|
||||
|
@ -282,7 +282,7 @@ impl<'a> Help<'a> {
|
|||
if !arg.takes_value() {
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(ref vec) = arg.val_names() {
|
||||
if let Some(vec) = arg.val_names() {
|
||||
let mut it = vec.iter().peekable();
|
||||
while let Some((_, val)) = it.next() {
|
||||
try!(color!(self, "<{}>", val, good));
|
||||
|
@ -524,7 +524,7 @@ impl<'a> Help<'a> {
|
|||
|
||||
fn spec_vals(&self, a: &ArgWithDisplay) -> String {
|
||||
debugln!("fn=spec_vals;");
|
||||
if let Some(ref pv) = a.default_val() {
|
||||
if let Some(pv) = a.default_val() {
|
||||
debugln!("Writing defaults");
|
||||
return format!(" [default: {}] {}",
|
||||
if self.color {
|
||||
|
@ -562,7 +562,7 @@ impl<'a> Help<'a> {
|
|||
});
|
||||
} else if !self.hide_pv {
|
||||
debugln!("Writing values");
|
||||
if let Some(ref pv) = a.possible_vals() {
|
||||
if let Some(pv) = a.possible_vals() {
|
||||
debugln!("Possible vals...{:?}", pv);
|
||||
return if self.color {
|
||||
format!(" [values: {}]",
|
||||
|
@ -943,7 +943,7 @@ impl<'a> Help<'a> {
|
|||
parser.meta.pre_help.unwrap_or("unknown before-help")));
|
||||
}
|
||||
// Unknown tag, write it back.
|
||||
ref r => {
|
||||
r => {
|
||||
try!(self.writer.write(b"{"));
|
||||
try!(self.writer.write(r));
|
||||
try!(self.writer.write(b"}"));
|
||||
|
|
|
@ -235,6 +235,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
} else {
|
||||
sdebugln!("No");
|
||||
}
|
||||
|
||||
debug!("Using Setting VersionlessSubcommands...");
|
||||
if self.settings.is_set(AppSettings::VersionlessSubcommands) {
|
||||
sdebugln!("Yes");
|
||||
|
@ -495,7 +496,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
// Firt we verify that the index highest supplied index, is equal to the number of
|
||||
// positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
|
||||
// but no 2)
|
||||
if let Some((idx, ref p)) = self.positionals.iter().rev().next() {
|
||||
if let Some((idx, p)) = self.positionals.iter().rev().next() {
|
||||
debug_assert!(!(idx != self.positionals.len()),
|
||||
format!("Found positional argument \"{}\" who's index is {} but there are \
|
||||
only {} positional arguments defined",
|
||||
|
@ -620,6 +621,10 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
self.settings.is_set(AppSettings::NeedsSubcommandHelp) {
|
||||
let cmds: Vec<OsString> = it.map(|c| c.into()).collect();
|
||||
let mut help_help = false;
|
||||
let mut bin_name = self.meta
|
||||
.bin_name
|
||||
.as_ref()
|
||||
.unwrap_or(&self.meta.name).clone();
|
||||
let mut sc = {
|
||||
let mut sc: &Parser = self;
|
||||
for (i, cmd) in cmds.iter().enumerate() {
|
||||
|
@ -663,6 +668,9 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
.unwrap_or(&self.meta.name),
|
||||
self.color()));
|
||||
}
|
||||
bin_name = format!("{} {}",
|
||||
bin_name,
|
||||
&*sc.meta.name);
|
||||
}
|
||||
sc.clone()
|
||||
};
|
||||
|
@ -678,17 +686,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
sc.create_help_and_version();
|
||||
}
|
||||
if sc.meta.bin_name != self.meta.bin_name {
|
||||
sc.meta.bin_name = Some(format!("{}{}{}",
|
||||
self.meta
|
||||
.bin_name
|
||||
.as_ref()
|
||||
.unwrap_or(&self.meta.name.clone()),
|
||||
if self.meta.bin_name.is_some() {
|
||||
" "
|
||||
} else {
|
||||
""
|
||||
},
|
||||
&*sc.meta.name));
|
||||
sc.meta.bin_name = Some(format!("{} {}", bin_name, sc.meta.name));
|
||||
}
|
||||
return sc._help();
|
||||
}
|
||||
|
@ -756,7 +754,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
if let Some(o) = self.opts.iter().filter(|o| &o.name == &a).next() {
|
||||
try!(self.validate_required(matcher));
|
||||
reqs_validated = true;
|
||||
let should_err = if let Some(ref v) = matcher.0.args.get(&*o.name) {
|
||||
let should_err = if let Some(v) = matcher.0.args.get(&*o.name) {
|
||||
v.vals.is_empty() && !(o.min_vals.is_some() && o.min_vals.unwrap() == 0)
|
||||
} else {
|
||||
true
|
||||
|
@ -1154,9 +1152,13 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
}
|
||||
|
||||
fn _help(&self) -> ClapResult<()> {
|
||||
try!(self.print_help());
|
||||
let mut buf = vec![];
|
||||
try!(Help::write_parser_help(&mut buf, self));
|
||||
let out = io::stdout();
|
||||
let mut out_buf = BufWriter::new(out.lock());
|
||||
try!(out_buf.write(&*buf));
|
||||
Err(Error {
|
||||
message: String::new(),
|
||||
message: unsafe { String::from_utf8_unchecked(buf) },
|
||||
kind: ErrorKind::HelpDisplayed,
|
||||
info: None,
|
||||
})
|
||||
|
@ -1387,7 +1389,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
if self.is_set(AppSettings::StrictUtf8) && val.to_str().is_none() {
|
||||
return Err(Error::invalid_utf8(&*self.create_current_usage(matcher), self.color()));
|
||||
}
|
||||
if let Some(ref p_vals) = arg.possible_vals() {
|
||||
if let Some(p_vals) = arg.possible_vals() {
|
||||
let val_str = val.to_string_lossy();
|
||||
if !p_vals.contains(&&*val_str) {
|
||||
return Err(Error::invalid_value(val_str,
|
||||
|
@ -1401,7 +1403,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
matcher.contains(&*arg.name()) {
|
||||
return Err(Error::empty_value(arg, &*self.create_current_usage(matcher), self.color()));
|
||||
}
|
||||
if let Some(ref vtor) = arg.validator() {
|
||||
if let Some(vtor) = arg.validator() {
|
||||
if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
|
||||
return Err(Error::value_validation(e, self.color()));
|
||||
}
|
||||
|
@ -1591,6 +1593,7 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
self._help().unwrap_err()
|
||||
} else {
|
||||
let mut reqs = self.required.iter().map(|&r| &*r).collect::<Vec<_>>();
|
||||
reqs.retain(|n| !matcher.contains(n));
|
||||
reqs.dedup();
|
||||
Error::missing_required_argument(
|
||||
&*self.get_required_from(&*reqs, Some(matcher))
|
||||
|
|
|
@ -111,7 +111,7 @@ impl<'a> ArgMatches<'a> {
|
|||
/// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of
|
||||
/// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html
|
||||
pub fn value_of<S: AsRef<str>>(&self, name: S) -> Option<&str> {
|
||||
if let Some(ref arg) = self.args.get(name.as_ref()) {
|
||||
if let Some(arg) = self.args.get(name.as_ref()) {
|
||||
if let Some(v) = arg.vals.values().nth(0) {
|
||||
return Some(v.to_str().expect(INVALID_UTF8));
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ impl<'a> ArgMatches<'a> {
|
|||
/// [`Values`]: ./struct.Values.html
|
||||
/// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
|
||||
pub fn values_of<S: AsRef<str>>(&'a self, name: S) -> Option<Values<'a>> {
|
||||
if let Some(ref arg) = self.args.get(name.as_ref()) {
|
||||
if let Some(arg) = self.args.get(name.as_ref()) {
|
||||
fn to_str_slice(o: &OsString) -> &str {
|
||||
o.to_str().expect(INVALID_UTF8)
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ impl<'a> ArgMatches<'a> {
|
|||
/// assert_eq!(itr.next(), None);
|
||||
/// ```
|
||||
pub fn values_of_lossy<S: AsRef<str>>(&'a self, name: S) -> Option<Vec<String>> {
|
||||
if let Some(ref arg) = self.args.get(name.as_ref()) {
|
||||
if let Some(arg) = self.args.get(name.as_ref()) {
|
||||
return Some(arg.vals
|
||||
.values()
|
||||
.map(|v| v.to_string_lossy().into_owned())
|
||||
|
@ -284,7 +284,7 @@ impl<'a> ArgMatches<'a> {
|
|||
&*o
|
||||
}
|
||||
let to_str_slice: fn(&'a OsString) -> &'a OsStr = to_str_slice; // coerce to fn pointer
|
||||
if let Some(ref arg) = self.args.get(name.as_ref()) {
|
||||
if let Some(arg) = self.args.get(name.as_ref()) {
|
||||
return Some(OsValues { iter: arg.vals.values().map(to_str_slice) });
|
||||
}
|
||||
None
|
||||
|
|
|
@ -211,7 +211,7 @@ end
|
|||
};
|
||||
|
||||
let mut buffer = detect_subcommand_function;
|
||||
gen_fish_inner(command, &self, vec![], &mut buffer, has_subcommands);
|
||||
gen_fish_inner(command, self, vec![], &mut buffer, has_subcommands);
|
||||
w!(buf, buffer.as_bytes());
|
||||
}
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ pub fn get_all_subcommands(p: &Parser) -> Vec<String> {
|
|||
}
|
||||
subcmds.push(sc.p.meta.name.clone());
|
||||
}
|
||||
for sc_v in p.subcommands.iter().map(|ref s| get_all_subcommands(&s.p)) {
|
||||
for sc_v in p.subcommands.iter().map(|s| get_all_subcommands(&s.p)) {
|
||||
subcmds.extend(sc_v);
|
||||
}
|
||||
subcmds.sort();
|
||||
|
@ -269,7 +269,7 @@ pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
|
|||
}
|
||||
}
|
||||
}
|
||||
for sc_v in p.subcommands.iter().map(|ref s| get_all_subcommand_paths(&s.p, false)) {
|
||||
for sc_v in p.subcommands.iter().map(|s| get_all_subcommand_paths(&s.p, false)) {
|
||||
subcmds.extend(sc_v);
|
||||
}
|
||||
subcmds
|
||||
|
@ -279,10 +279,10 @@ fn vals_for(o: &OptBuilder) -> String {
|
|||
use args::AnyArg;
|
||||
let mut ret = String::new();
|
||||
let mut needs_quotes = true;
|
||||
if let Some(ref vals) = o.possible_vals() {
|
||||
if let Some(vals) = o.possible_vals() {
|
||||
needs_quotes = false;
|
||||
ret = format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" "));
|
||||
} else if let Some(ref vec) = o.val_names() {
|
||||
} else if let Some(vec) = o.val_names() {
|
||||
let mut it = vec.iter().peekable();
|
||||
while let Some((_, val)) = it.next() {
|
||||
ret = format!("{}<{}>{}", ret, val,
|
||||
|
@ -321,7 +321,7 @@ fn vals_for(o: &OptBuilder) -> String {
|
|||
ret
|
||||
}
|
||||
|
||||
fn gen_fish_inner(root_command: &String,
|
||||
fn gen_fish_inner(root_command: &str,
|
||||
comp_gen: &ComplGen,
|
||||
parent_cmds: Vec<&String>,
|
||||
buffer: &mut String,
|
||||
|
|
|
@ -66,6 +66,21 @@ OPTIONS:
|
|||
ARGS:
|
||||
<scpositional> tests positionals";
|
||||
|
||||
static MULTI_SC_HELP: &'static str = "ctest-subcmd-multi 0.1
|
||||
Kevin K. <kbknapp@gmail.com>
|
||||
tests subcommands
|
||||
|
||||
USAGE:
|
||||
ctest subcmd multi [FLAGS] [OPTIONS]
|
||||
|
||||
FLAGS:
|
||||
-f, --flag tests flags
|
||||
-h, --help Prints help information
|
||||
-V, --version Prints version information
|
||||
|
||||
OPTIONS:
|
||||
-o, --option <scoption>... tests options";
|
||||
|
||||
#[test]
|
||||
fn help_short() {
|
||||
let m = App::new("test")
|
||||
|
@ -159,6 +174,21 @@ fn after_and_before_help_output() {
|
|||
test::check_help(app, AFTER_HELP);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_level_sc_help() {
|
||||
let app = App::new("ctest")
|
||||
.subcommand(SubCommand::with_name("subcmd")
|
||||
.subcommand(SubCommand::with_name("multi")
|
||||
.about("tests subcommands")
|
||||
.author("Kevin K. <kbknapp@gmail.com>")
|
||||
.version("0.1")
|
||||
.args_from_usage("
|
||||
-f, --flag 'tests flags'
|
||||
-o, --option [scoption]... 'tests options'
|
||||
")));
|
||||
test::check_err_output(app, "ctest help subcmd multi", MULTI_SC_HELP, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complex_subcommand_help_output() {
|
||||
let mut a = test::complex_app();
|
||||
|
|
Loading…
Reference in a new issue