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