Auto merge of #646 - kbknapp:vks-custom-error, r=kbknapp

Vks custom error
This commit is contained in:
Homu 2016-09-06 04:57:40 +09:00
commit 48bc038e5a
20 changed files with 599 additions and 459 deletions

View file

@ -2,14 +2,12 @@ sudo: false
language: rust
rust:
- nightly
- nightly-2016-07-20
- nightly-2016-09-04
- beta
- stable
# Only while clippy is failing
matrix:
allow_failures:
- rust: nightly
- rust: beta
before_script:
- |
pip install 'travis-cargo<0.2' --user &&

View file

@ -21,10 +21,10 @@ libc = { version = "~0.2.9", optional = true }
ansi_term = { version = "~0.8.0", optional = true }
strsim = { version = "~0.5.1", optional = true }
yaml-rust = { version = "~0.3.2", optional = true }
clippy = { version = "~0.0.85", optional = true }
clippy = { version = "~0.0.88", optional = true }
unicode-width = "~0.1.3"
unicode-segmentation = "~0.1.2"
term_size = { version = "~0.1.0", optional = true }
term_size = { version = "~0.2.0", optional = true }
[dev-dependencies]
regex = "~0.1.69"

View file

@ -1,21 +1,24 @@
use std::io::{self, Cursor, Read, Write};
use std::collections::BTreeMap;
use std::fmt::Display;
use std::cmp;
use std::usize;
// Std
use vec_map::VecMap;
use unicode_segmentation::UnicodeSegmentation;
use errors::{Error, Result as ClapResult};
// Internal
use args::{AnyArg, ArgSettings, DispOrder};
use app::{App, AppSettings};
use app::parser::Parser;
use args::{AnyArg, ArgSettings, DispOrder};
use errors::{Error, Result as ClapResult};
use fmt::{Format, Colorizer};
use std::cmp;
use std::collections::BTreeMap;
use std::fmt::Display;
use std::io::{self, Cursor, Read, Write};
use std::usize;
#[cfg(feature = "wrap_help")]
use term_size;
use unicode_segmentation::UnicodeSegmentation;
use vec_map::VecMap;
#[cfg(not(feature = "wrap_help"))]
mod term_size {
pub fn dimensions() -> Option<(usize, usize)> {
@ -90,19 +93,21 @@ pub struct Help<'a> {
// Public Functions
impl<'a> Help<'a> {
/// Create a new `Help` instance.
pub fn new(w: &'a mut Write, next_line_help: bool, hide_pv: bool, color: bool, cizer: Colorizer, term_w: Option<usize>) -> Self {
pub fn new(w: &'a mut Write,
next_line_help: bool,
hide_pv: bool,
color: bool,
cizer: Colorizer,
term_w: Option<usize>)
-> Self {
debugln!("fn=Help::new;");
Help {
writer: w,
next_line_help: next_line_help,
hide_pv: hide_pv,
term_w: match term_w {
Some(width) => if width == 0 {
usize::MAX
} else {
width
},
None => term_size::dimensions().map_or(120, |(w, _)| w),
Some(width) => if width == 0 { usize::MAX } else { width },
None => term_size::dimensions().map_or(120, |(w, _)| w),
},
color: color,
cizer: cizer,
@ -312,7 +317,8 @@ impl<'a> Help<'a> {
let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp);
let width = self.term_w;
let taken = (longest + 12) + str_width(&*spec_vals);
let force_next_line = !nlh && width >= taken && str_width(h) > (width - taken) && (taken as f32 / width as f32) > 0.25;
let force_next_line = !nlh && width >= taken && str_width(h) > (width - taken) &&
(taken as f32 / width as f32) > 0.25;
if arg.has_switch() {
if !(nlh || force_next_line) {
@ -400,9 +406,13 @@ impl<'a> Help<'a> {
// We calculate with longest+12 since if it's already NLH we don't care
let taken = (longest + 12) + str_width(&*spec_vals);
let force_next_line = !nlh && width >= taken && str_width(h) > (width - taken) && (taken as f32 / width as f32) > 0.25;
let force_next_line = !nlh && width >= taken && str_width(h) > (width - taken) &&
(taken as f32 / width as f32) > 0.25;
debugln!("Force Next Line...{:?}", force_next_line);
debugln!("Force Next Line math (help_len > (width - flags/opts/spcs))...{} > ({} - {})", str_width(h), width, taken);
debugln!("Force Next Line math (help_len > (width - flags/opts/spcs))...{} > ({} - {})",
str_width(h),
width,
taken);
let spcs = if nlh || force_next_line {
8 // "tab" + "tab"
@ -488,9 +498,9 @@ impl<'a> Help<'a> {
if self.color {
format!(" [values: {}]",
pv.iter()
.map(|v| format!("{}", self.cizer.good(v)))
.collect::<Vec<_>>()
.join(", "))
.map(|v| format!("{}", self.cizer.good(v)))
.collect::<Vec<_>>()
.join(", "))
} else {
format!(" [values: {}]", pv.join(", "))
}
@ -501,14 +511,14 @@ impl<'a> Help<'a> {
} else if let Some(ref aliases) = a.aliases() {
debugln!("Writing aliases");
return format!(" [aliases: {}]",
if self.color {
aliases.iter()
.map(|v| format!("{}", self.cizer.good(v)))
.collect::<Vec<_>>()
.join(", ")
} else {
aliases.join(", ")
});
if self.color {
aliases.iter()
.map(|v| format!("{}", self.cizer.good(v)))
.collect::<Vec<_>>()
.join(", ")
} else {
aliases.join(", ")
});
} else if !self.hide_pv {
debugln!("Writing values");
if let Some(pv) = a.possible_vals() {
@ -516,9 +526,9 @@ impl<'a> Help<'a> {
return if self.color {
format!(" [values: {}]",
pv.iter()
.map(|v| format!("{}", self.cizer.good(v)))
.collect::<Vec<_>>()
.join(", "))
.map(|v| format!("{}", self.cizer.good(v)))
.collect::<Vec<_>>()
.join(", "))
} else {
format!(" [values: {}]", pv.join(", "))
};
@ -547,8 +557,8 @@ impl<'a> Help<'a> {
if unified_help && (flags || opts) {
let opts_flags = parser.iter_flags()
.map(as_arg_trait)
.chain(parser.iter_opts().map(as_arg_trait));
.map(as_arg_trait)
.chain(parser.iter_opts().map(as_arg_trait));
try!(color!(self, "OPTIONS:\n", warning));
try!(self.write_args(opts_flags));
first = false;
@ -556,7 +566,7 @@ impl<'a> Help<'a> {
if flags {
try!(color!(self, "FLAGS:\n", warning));
try!(self.write_args(parser.iter_flags()
.map(as_arg_trait)));
.map(as_arg_trait)));
first = false;
}
if opts {
@ -826,11 +836,11 @@ impl<'a> Help<'a> {
_ => continue,
};
debugln!("iter;tag_buf={};", unsafe {
String::from_utf8_unchecked(tag_buf.get_ref()[0..tag_length]
.iter()
.map(|&i|i)
.collect::<Vec<_>>())
debugln!("iter;tag_buf={};", unsafe {
String::from_utf8_unchecked(tag_buf.get_ref()[0..tag_length]
.iter()
.map(|&i| i)
.collect::<Vec<_>>())
});
match &tag_buf.get_ref()[0..tag_length] {
b"?" => {
@ -862,21 +872,21 @@ impl<'a> Help<'a> {
}
b"unified" => {
let opts_flags = parser.iter_flags()
.map(as_arg_trait)
.chain(parser.iter_opts().map(as_arg_trait));
.map(as_arg_trait)
.chain(parser.iter_opts().map(as_arg_trait));
try!(self.write_args(opts_flags));
}
b"flags" => {
try!(self.write_args(parser.iter_flags()
.map(as_arg_trait)));
.map(as_arg_trait)));
}
b"options" => {
try!(self.write_args(parser.iter_opts()
.map(as_arg_trait)));
.map(as_arg_trait)));
}
b"positionals" => {
try!(self.write_args(parser.iter_positionals()
.map(as_arg_trait)));
.map(as_arg_trait)));
}
b"subcommands" => {
try!(self.write_subcommands(&parser));
@ -904,7 +914,9 @@ impl<'a> Help<'a> {
#[cfg_attr(feature = "lints", allow(explicit_counter_loop))]
fn wrap_help(help: &mut String, longest_w: usize, avail_chars: usize) {
debugln!("fn=wrap_help;longest_w={},avail_chars={}", longest_w, avail_chars);
debugln!("fn=wrap_help;longest_w={},avail_chars={}",
longest_w,
avail_chars);
debug!("Enough space to wrap...");
if longest_w < avail_chars {
sdebugln!("Yes");
@ -913,9 +925,11 @@ fn wrap_help(help: &mut String, longest_w: usize, avail_chars: usize) {
let mut i = 0;
for (idx, g) in (&*help.clone()).grapheme_indices(true) {
debugln!("iter;idx={},g={}", idx, g);
if g != " " { continue; }
if g != " " {
continue;
}
if str_width(&help[j..idx + (2 * i)]) < avail_chars {
debugln!("Still enough space...");
debugln!("Still enough space...");
prev_space = idx;
continue;
}

View file

@ -104,8 +104,10 @@ macro_rules! validate_multiples {
($_self:ident, $a:ident, $m:ident) => {
debugln!("macro=validate_multiples!;");
if $m.contains(&$a.name) && !$a.settings.is_set(ArgSettings::Multiple) {
// Not the first time, and we don't allow multiples
return Err(Error::unexpected_multiple_usage($a, &*$_self.create_current_usage($m), $_self.color()))
// Not the first time, and we don't allow multiples
return Err(Error::unexpected_multiple_usage($a,
&*$_self.create_current_usage($m),
$_self.color()))
}
};
}

View file

@ -6,28 +6,31 @@ pub mod parser;
mod meta;
mod help;
pub use self::settings::AppSettings;
// Std
// Internal
use app::help::Help;
use app::parser::Parser;
use args::{AnyArg, Arg, ArgGroup, ArgMatcher, ArgMatches, ArgSettings};
use errors::Error;
use errors::Result as ClapResult;
pub use self::settings::AppSettings;
use shell::Shell;
use std::borrow::Borrow;
use std::env;
use std::ffi::OsString;
use std::fmt;
use std::io::{self, BufRead, BufWriter, Write};
use std::path::Path;
use std::process;
use std::ffi::OsString;
use std::borrow::Borrow;
use std::result::Result as StdResult;
use std::rc::Rc;
use std::fmt;
use std::result::Result as StdResult;
// Third Party
use vec_map::VecMap;
#[cfg(feature = "yaml")]
use yaml_rust::Yaml;
use vec_map::VecMap;
use args::{AnyArg, Arg, ArgGroup, ArgMatcher, ArgMatches, ArgSettings};
use app::parser::Parser;
use app::help::Help;
use errors::Error;
use errors::Result as ClapResult;
use shell::Shell;
/// Used to create a representation of a command line program and all possible command line
/// arguments. Application settings are set using the "builder pattern" with the
@ -1086,7 +1089,10 @@ impl<'a, 'b> App<'a, 'b> {
/// `<project>/target/debug/build/myapp-<hash>/out/myapp.bash-completion`.
///
/// Fish shell completions will use the file format `{bin_name}.fish`
pub fn gen_completions<T: Into<OsString>, S: Into<String>>(&mut self, bin_name: S, for_shell: Shell, out_dir: T) {
pub fn gen_completions<T: Into<OsString>, S: Into<String>>(&mut self,
bin_name: S,
for_shell: Shell,
out_dir: T) {
self.p.meta.bin_name = Some(bin_name.into());
self.p.gen_completions(for_shell, out_dir.into());
}
@ -1124,7 +1130,10 @@ impl<'a, 'b> App<'a, 'b> {
/// ```shell
/// $ myapp generate-bash-completions > /etc/bash_completion.d/myapp
/// ```
pub fn gen_completions_to<W: Write, S: Into<String>>(&mut self, bin_name: S, for_shell: Shell, buf: &mut W) {
pub fn gen_completions_to<W: Write, S: Into<String>>(&mut self,
bin_name: S,
for_shell: Shell,
buf: &mut W) {
self.p.meta.bin_name = Some(bin_name.into());
self.p.gen_completions_to(for_shell, buf);
}
@ -1342,11 +1351,7 @@ impl<'a> From<&'a Yaml> for App<'a, 'a> {
is_sc = Some(yaml_hash.get(sc_key).unwrap());
App::new(sc_key.as_str().unwrap())
};
yaml = if let Some(sc) = is_sc {
sc
} else {
yaml
};
yaml = if let Some(sc) = is_sc { sc } else { yaml };
macro_rules! yaml_str {
($a:ident, $y:ident, $i:ident) => {
@ -1402,7 +1407,9 @@ impl<'a> From<&'a Yaml> for App<'a, 'a> {
if let Some(v) = yaml["global_settings"].as_vec() {
for ys in v {
if let Some(s) = ys.as_str() {
a = a.global_setting(s.parse().ok().expect("unknown AppSetting found in YAML file"));
a = a.global_setting(s.parse()
.ok()
.expect("unknown AppSetting found in YAML file"));
}
}
} else {
@ -1531,7 +1538,8 @@ impl<'n, 'e> AnyArg<'n, 'e> for App<'n, 'e> {
}
fn aliases(&self) -> Option<Vec<&'e str>> {
if let Some(ref aliases) = self.p.meta.aliases {
let vis_aliases: Vec<_> = aliases.iter().filter_map(|&(n,v)| if v { Some(n) } else {None}).collect();
let vis_aliases: Vec<_> =
aliases.iter().filter_map(|&(n, v)| if v { Some(n) } else { None }).collect();
if vis_aliases.is_empty() {
None
} else {

View file

@ -1,33 +1,38 @@
use std::collections::{BTreeMap, HashMap, VecDeque};
use std::slice::Iter;
use std::io::{self, BufWriter, Write};
use std::ffi::{OsStr, OsString};
use std::fmt::Display;
#[cfg(feature = "debug")]
use std::os::unix::ffi::OsStrExt;
// Std
use vec_map::{self, VecMap};
use app::help::Help;
// Internal
use INTERNAL_ERROR_MSG;
use INVALID_UTF8;
use SubCommand;
use app::App;
use args::{Arg, ArgGroup, FlagBuilder, OptBuilder, PosBuilder};
use app::help::Help;
use app::meta::AppMeta;
use app::settings::{AppFlags, AppSettings};
use args::{AnyArg, ArgMatcher};
use args::{Arg, ArgGroup, FlagBuilder, OptBuilder, PosBuilder};
use args::MatchedArg;
use args::settings::ArgSettings;
use completions::ComplGen;
use errors::{Error, ErrorKind};
use errors::Result as ClapResult;
use INVALID_UTF8;
use suggestions;
use INTERNAL_ERROR_MSG;
use SubCommand;
use fmt::{Format, ColorWhen};
use osstringext::OsStrExt2;
use app::meta::AppMeta;
use args::MatchedArg;
use shell::Shell;
use completions::ComplGen;
use std::collections::{BTreeMap, HashMap, VecDeque};
use std::ffi::{OsStr, OsString};
use std::fmt::Display;
use std::fs::File;
use std::io::{self, BufWriter, Write};
#[cfg(feature = "debug")]
use std::os::unix::ffi::OsStrExt;
use std::path::PathBuf;
use std::slice::Iter;
use suggestions;
// Third Party
use vec_map::{self, VecMap};
#[allow(missing_debug_implementations)]
#[doc(hidden)]
@ -91,14 +96,14 @@ impl<'a, 'b> Parser<'a, 'b>
pub fn help_short(&mut self, s: &str) {
self.help_short = s.trim_left_matches(|c| c == '-')
.chars()
.nth(0);
.chars()
.nth(0);
}
pub fn version_short(&mut self, s: &str) {
self.version_short = s.trim_left_matches(|c| c == '-')
.chars()
.nth(0);
.chars()
.nth(0);
}
pub fn gen_completions_to<W: Write>(&mut self, for_shell: Shell, buf: &mut W) {
@ -134,8 +139,8 @@ impl<'a, 'b> Parser<'a, 'b>
format!("Non-unique argument name: {} is already in use", a.name));
if let Some(ref grps) = a.group {
for g in grps {
let ag = self.groups.entry(g).or_insert_with(|| ArgGroup::with_name(g));
ag.args.push(a.name);
let ag = self.groups.entry(g).or_insert_with(|| ArgGroup::with_name(g));
ag.args.push(a.name);
}
}
if let Some(s) = a.short {
@ -248,7 +253,7 @@ impl<'a, 'b> Parser<'a, 'b>
self.meta.version.is_some() {
sdebugln!("Yes");
subcmd = subcmd.setting(AppSettings::GlobalVersion)
.version(self.meta.version.unwrap());
.version(self.meta.version.unwrap());
} else {
sdebugln!("No");
}
@ -355,7 +360,7 @@ impl<'a, 'b> Parser<'a, 'b>
if matcher.is_some() && matcher.as_ref().unwrap().contains(p) {
continue;
}
if let Some(p) = self.positionals.values().filter(|x| &x.name == &p).next() {
if let Some(p) = self.positionals.values().find(|x| &x.name == &p) {
if args_in_groups.contains(&p.name) {
continue;
}
@ -365,7 +370,7 @@ impl<'a, 'b> Parser<'a, 'b>
debugln!("args_in_groups={:?}", args_in_groups);
for (_, s) in pmap {
if (!args_in_groups.is_empty()) && (args_in_groups.contains(&&*s)) {
continue;
continue;
}
ret_val.push_back(s);
@ -385,7 +390,7 @@ impl<'a, 'b> Parser<'a, 'b>
let mut g_vec = vec![];
for g in grps.into_iter() {
let g_string = self.args_in_group(g)
.join("|");
.join("|");
g_vec.push(format!("<{}>", &g_string[..g_string.len()]));
}
g_vec.dedup();
@ -413,10 +418,10 @@ impl<'a, 'b> Parser<'a, 'b>
}
}
debugln!("Arg not required...");
count +=1;
count += 1;
} else {
debugln!("Arg not required...");
count +=1;
count += 1;
}
}
if count > 1 || self.positionals.len() > 1 {
@ -578,19 +583,23 @@ impl<'a, 'b> Parser<'a, 'b>
if !self.trailing_vals {
// Does the arg match a subcommand name, or any of it's aliases (if defined)
let pos_sc = self.subcommands
.iter()
.any(|s| &s.p.meta.name[..] == &*arg_os ||
(s.p.meta.aliases.is_some() &&
s.p.meta.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(a, _)| a == &*arg_os)));
.iter()
.any(|s| {
&s.p.meta.name[..] == &*arg_os ||
(s.p.meta.aliases.is_some() &&
s.p
.meta
.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(a, _)| a == &*arg_os))
});
if (!starts_new_arg || self.is_set(AppSettings::AllowLeadingHyphen)) && !pos_sc {
// Check to see if parsing a value from an option
if let Some(nvo) = needs_val_of {
// get the OptBuilder so we can check the settings
if let Some(opt) = self.opts.iter().filter(|o| &o.name == &nvo).next() {
if let Some(opt) = self.opts.iter().find(|o| &o.name == &nvo) {
needs_val_of = try!(self.add_val_to_arg(opt, &arg_os, matcher));
// get the next value from the iterator
continue;
@ -622,38 +631,36 @@ impl<'a, 'b> Parser<'a, 'b>
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();
.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() {
if &*cmd.to_string_lossy() == "help" { // cmd help help
if &*cmd.to_string_lossy() == "help" {
// cmd help help
help_help = true;
}
if let Some(c) = sc.subcommands
.iter()
.filter(|s| &*s.p.meta.name == cmd)
.next()
.map(|sc| &sc.p) {
.iter()
.find(|s| &*s.p.meta.name == cmd)
.map(|sc| &sc.p) {
sc = c;
if i == cmds.len() - 1 {
break;
}
} else if let Some(c) = sc.subcommands
.iter()
.filter(|s|
if let Some(ref als) = s.p
.meta
.aliases {
als.iter()
.any(|&(a, _)| &a == &&*cmd.to_string_lossy())
} else {
false
}
)
.next()
.map(|sc| &sc.p) {
.iter()
.find(|s| if let Some(ref als) = s.p
.meta
.aliases {
als.iter()
.any(|&(a, _)| &a == &&*cmd.to_string_lossy())
} else {
false
})
.map(|sc| &sc.p) {
sc = c;
if i == cmds.len() - 1 {
break;
@ -693,9 +700,11 @@ impl<'a, 'b> Parser<'a, 'b>
subcmd_name = Some(arg_os.to_str().expect(INVALID_UTF8).to_owned());
break;
} else if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(),
self.subcommands
.iter()
.map(|s| &s.p.meta.name)) {
self.subcommands
.iter()
.map(|s| {
&s.p.meta.name
})) {
return Err(Error::invalid_subcommand(arg_os.to_string_lossy().into_owned(),
cdate,
self.meta
@ -715,9 +724,8 @@ impl<'a, 'b> Parser<'a, 'b>
Some(s) => s.to_string(),
None => {
if !self.settings.is_set(AppSettings::StrictUtf8) {
return Err(
Error::invalid_utf8(&*self.create_current_usage(matcher), self.color())
);
return Err(Error::invalid_utf8(&*self.create_current_usage(matcher),
self.color()));
}
arg_os.to_string_lossy().into_owned()
}
@ -729,9 +737,8 @@ impl<'a, 'b> Parser<'a, 'b>
let a = v.into();
if let None = a.to_str() {
if !self.settings.is_set(AppSettings::StrictUtf8) {
return Err(
Error::invalid_utf8(&*self.create_current_usage(matcher), self.color())
);
return Err(Error::invalid_utf8(&*self.create_current_usage(matcher),
self.color()));
}
}
sc_m.add_val_to("", &a);
@ -751,7 +758,7 @@ impl<'a, 'b> Parser<'a, 'b>
let mut reqs_validated = false;
if let Some(a) = needs_val_of {
if let Some(o) = self.opts.iter().filter(|o| &o.name == &a).next() {
if let Some(o) = self.opts.iter().find(|o| &o.name == &a) {
try!(self.validate_required(matcher));
reqs_validated = true;
let should_err = if let Some(v) = matcher.0.args.get(&*o.name) {
@ -760,13 +767,14 @@ impl<'a, 'b> Parser<'a, 'b>
true
};
if should_err {
return Err(Error::empty_value(o, &*self.create_current_usage(matcher), self.color()));
return Err(Error::empty_value(o,
&*self.create_current_usage(matcher),
self.color()));
}
} else {
return Err(Error::empty_value(self.positionals
.values()
.filter(|p| &p.name == &a)
.next()
.find(|p| &p.name == &a)
.expect(INTERNAL_ERROR_MSG),
&*self.create_current_usage(matcher),
self.color()));
@ -790,22 +798,26 @@ impl<'a, 'b> Parser<'a, 'b>
self.subcommands
.iter()
.filter(|sc| sc.p.meta.aliases.is_some())
.filter_map(|sc| if sc.p.meta.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(a, _)| &a == &&*pos_sc_name) {
Some(sc.p.meta.name.clone())
} else {
None
})
.filter_map(|sc| if sc.p
.meta
.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(a, _)| &a == &&*pos_sc_name) {
Some(sc.p.meta.name.clone())
} else {
None
})
.next()
.expect(INTERNAL_ERROR_MSG)
};
try!(self.parse_subcommand(sc_name, matcher, it));
} else if self.is_set(AppSettings::SubcommandRequired) {
let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name);
return Err(Error::missing_subcommand(bn, &self.create_current_usage(matcher), self.color()));
return Err(Error::missing_subcommand(bn,
&self.create_current_usage(matcher),
self.color()));
} else if self.is_set(AppSettings::SubcommandRequiredElseHelp) {
let mut out = vec![];
try!(self.write_help_err(&mut out));
@ -887,9 +899,8 @@ impl<'a, 'b> Parser<'a, 'b>
}
mid_string.push_str(" ");
if let Some(ref mut sc) = self.subcommands
.iter_mut()
.filter(|s| &s.p.meta.name == &sc_name)
.next() {
.iter_mut()
.find(|s| &s.p.meta.name == &sc_name) {
let mut sc_matcher = ArgMatcher::new();
// bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
// a space
@ -923,21 +934,21 @@ impl<'a, 'b> Parser<'a, 'b>
fn blacklisted_from(&self, name: &str, matcher: &ArgMatcher) -> Option<String> {
for k in matcher.arg_names() {
if let Some(f) = self.flags.iter().filter(|f| &f.name == &k).next() {
if let Some(f) = self.flags.iter().find(|f| &f.name == &k) {
if let Some(ref bl) = f.blacklist {
if bl.contains(&name) {
return Some(f.to_string());
}
}
}
if let Some(o) = self.opts.iter().filter(|o| &o.name == &k).next() {
if let Some(o) = self.opts.iter().find(|o| &o.name == &k) {
if let Some(ref bl) = o.blacklist {
if bl.contains(&name) {
return Some(o.to_string());
}
}
}
if let Some(pos) = self.positionals.values().filter(|p| &p.name == &k).next() {
if let Some(pos) = self.positionals.values().find(|p| &p.name == &k) {
if let Some(ref bl) = pos.blacklist {
if bl.contains(&name) {
return Some(pos.name.to_owned());
@ -950,21 +961,21 @@ impl<'a, 'b> Parser<'a, 'b>
fn overriden_from(&self, name: &str, matcher: &ArgMatcher) -> Option<&'a str> {
for k in matcher.arg_names() {
if let Some(f) = self.flags.iter().filter(|f| &f.name == &k).next() {
if let Some(f) = self.flags.iter().find(|f| &f.name == &k) {
if let Some(ref bl) = f.overrides {
if bl.contains(&name.into()) {
return Some(f.name);
}
}
}
if let Some(o) = self.opts.iter().filter(|o| &o.name == &k).next() {
if let Some(o) = self.opts.iter().find(|o| &o.name == &k) {
if let Some(ref bl) = o.overrides {
if bl.contains(&name.into()) {
return Some(o.name);
}
}
}
if let Some(pos) = self.positionals.values().filter(|p| &p.name == &k).next() {
if let Some(pos) = self.positionals.values().find(|p| &p.name == &k) {
if let Some(ref bl) = pos.overrides {
if bl.contains(&name.into()) {
return Some(pos.name);
@ -1004,16 +1015,15 @@ impl<'a, 'b> Parser<'a, 'b>
let mut args = vec![];
for n in &self.groups.get(group).unwrap().args {
if let Some(f) = self.flags.iter().filter(|f| &f.name == n).next() {
if let Some(f) = self.flags.iter().find(|f| &f.name == n) {
args.push(f.to_string());
} else if let Some(f) = self.opts.iter().filter(|o| &o.name == n).next() {
} else if let Some(f) = self.opts.iter().find(|o| &o.name == n) {
args.push(f.to_string());
} else if self.groups.contains_key(&**n) {
g_vec.push(*n);
} else if let Some(p) = self.positionals
.values()
.filter(|p| &p.name == n)
.next() {
.values()
.find(|p| &p.name == n) {
args.push(p.name.to_owned());
}
}
@ -1066,7 +1076,7 @@ impl<'a, 'b> Parser<'a, 'b>
self.flags.push(arg);
}
if !self.settings.is_set(AppSettings::DisableVersion) &&
self.is_set(AppSettings::NeedsLongVersion) {
self.is_set(AppSettings::NeedsLongVersion) {
debugln!("Building --version");
if self.version_short.is_none() && !self.short_list.contains(&'V') {
self.version_short = Some('V');
@ -1089,7 +1099,7 @@ impl<'a, 'b> Parser<'a, 'b>
debugln!("Building help");
self.subcommands
.push(App::new("help")
.about("Prints this message or the help of the given subcommand(s)"));
.about("Prints this message or the help of the given subcommand(s)"));
}
}
@ -1097,24 +1107,22 @@ impl<'a, 'b> Parser<'a, 'b>
// because those will be listed in self.required
pub fn create_current_usage(&self, matcher: &'b ArgMatcher<'a>) -> String {
self.create_usage(&*matcher.arg_names()
.iter()
.filter(|n| {
if let Some(o) = self.opts
.iter()
.filter(|&o| &&o.name == n)
.next() {
!o.settings.is_set(ArgSettings::Required)
} else if let Some(p) = self.positionals
.values()
.filter(|&p| &&p.name == n)
.next() {
!p.settings.is_set(ArgSettings::Required)
} else {
true // flags can't be required, so they're always true
}
})
.map(|&n| n)
.collect::<Vec<_>>())
.iter()
.filter(|n| {
if let Some(o) = self.opts
.iter()
.find(|&o| &&o.name == n) {
!o.settings.is_set(ArgSettings::Required)
} else if let Some(p) = self.positionals
.values()
.find(|&p| &&p.name == n) {
!p.settings.is_set(ArgSettings::Required)
} else {
true // flags can't be required, so they're always true
}
})
.map(|&n| n)
.collect::<Vec<_>>())
}
fn check_for_help_and_version_str(&self, arg: &OsStr) -> ClapResult<()> {
@ -1194,18 +1202,16 @@ impl<'a, 'b> Parser<'a, 'b>
};
if let Some(opt) = self.opts
.iter()
.filter(|v| v.long.is_some() && &*v.long.unwrap() == arg)
.next() {
.iter()
.find(|v| v.long.is_some() && &*v.long.unwrap() == arg) {
debugln!("Found valid opt '{}'", opt.to_string());
let ret = try!(self.parse_opt(val, opt, matcher));
arg_post_processing!(self, opt, matcher);
return Ok(ret);
} else if let Some(flag) = self.flags
.iter()
.filter(|v| v.long.is_some() && &*v.long.unwrap() == arg)
.next() {
.iter()
.find(|v| v.long.is_some() && &*v.long.unwrap() == arg) {
debugln!("Found valid flag '{}'", flag.to_string());
// Only flags could be help or version, and we need to check the raw long
// so this is the first point to check
@ -1240,9 +1246,8 @@ impl<'a, 'b> Parser<'a, 'b>
// Option: -o
// Value: val
if let Some(opt) = self.opts
.iter()
.filter(|&v| v.short.is_some() && v.short.unwrap() == c)
.next() {
.iter()
.find(|&v| v.short.is_some() && v.short.unwrap() == c) {
debugln!("Found valid short opt -{} in '{}'", c, arg);
// Check for trailing concatenated value
let p: Vec<_> = arg.splitn(2, c).collect();
@ -1268,9 +1273,8 @@ impl<'a, 'b> Parser<'a, 'b>
return Ok(ret);
} else if let Some(flag) = self.flags
.iter()
.filter(|&v| v.short.is_some() && v.short.unwrap() == c)
.next() {
.iter()
.find(|&v| v.short.is_some() && v.short.unwrap() == c) {
debugln!("Found valid short flag -{}", c);
// Only flags can be help or version
try!(self.check_for_help_and_version_char(c));
@ -1306,7 +1310,9 @@ impl<'a, 'b> Parser<'a, 'b>
let v = fv.trim_left_matches(b'=');
if !opt.is_set(ArgSettings::EmptyValues) && v.len_() == 0 {
sdebugln!("Found Empty - Error");
return Err(Error::empty_value(opt, &*self.create_current_usage(matcher), self.color()));
return Err(Error::empty_value(opt,
&*self.create_current_usage(matcher),
self.color()));
}
sdebugln!("Found - {:?}, len: {}", v, v.len_());
debugln!("{:?} contains '='...{:?}", fv, fv.starts_with(&[b'=']));
@ -1319,7 +1325,8 @@ impl<'a, 'b> Parser<'a, 'b>
// Increment or create the group "args"
self.groups_for_arg(opt.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
if val.is_none() || !has_eq && (opt.is_set(ArgSettings::Multiple) && matcher.needs_more_vals(opt)) {
if val.is_none() ||
!has_eq && (opt.is_set(ArgSettings::Multiple) && matcher.needs_more_vals(opt)) {
return Ok(Some(opt.name));
}
Ok(None)
@ -1343,7 +1350,8 @@ impl<'a, 'b> Parser<'a, 'b>
ret = try!(self.add_single_val_to_arg(arg, v, matcher));
}
// If there was a delimiter used, we're not looking for more values
if val.contains_byte(delim as u32 as u8) || arg.is_set(ArgSettings::RequireDelimiter) {
if val.contains_byte(delim as u32 as u8) ||
arg.is_set(ArgSettings::RequireDelimiter) {
ret = None;
}
}
@ -1483,14 +1491,12 @@ impl<'a, 'b> Parser<'a, 'b>
if self.groups.contains_key(&**name) {
continue;
} else if let Some(opt) = self.opts
.iter()
.filter(|o| &o.name == name)
.next() {
.iter()
.find(|o| &o.name == name) {
try!(self._validate_num_vals(opt, ma, matcher));
} else if let Some(pos) = self.positionals
.values()
.filter(|p| &p.name == name)
.next() {
.values()
.find(|p| &p.name == name) {
try!(self._validate_num_vals(pos, ma, matcher));
}
}
@ -1534,13 +1540,13 @@ impl<'a, 'b> Parser<'a, 'b>
if (ma.vals.len() as u64) > num {
debugln!("Sending error TooManyValues");
return Err(Error::too_many_values(ma.vals
.get(ma.vals
.keys()
.last()
.expect(INTERNAL_ERROR_MSG))
.expect(INTERNAL_ERROR_MSG)
.to_str()
.expect(INVALID_UTF8),
.get(ma.vals
.keys()
.last()
.expect(INTERNAL_ERROR_MSG))
.expect(INTERNAL_ERROR_MSG)
.to_str()
.expect(INVALID_UTF8),
a,
&*self.create_current_usage(matcher),
self.color()));
@ -1575,34 +1581,34 @@ impl<'a, 'b> Parser<'a, 'b>
if self.groups.values().any(|g| g.args.contains(name)) {
continue 'outer;
}
if let Some(a) = self.flags.iter().filter(|f| &f.name == name).next() {
if let Some(a) = self.flags.iter().find(|f| &f.name == name) {
if self.is_missing_required_ok(a, matcher) {
continue 'outer;
}
} else if let Some(a) = self.opts.iter().filter(|o| &o.name == name).next() {
} else if let Some(a) = self.opts.iter().find(|o| &o.name == name) {
if self.is_missing_required_ok(a, matcher) {
continue 'outer;
}
} else if let Some(a) = self.positionals.values().filter(|p| &p.name == name).next() {
} else if let Some(a) = self.positionals.values().find(|p| &p.name == name) {
if self.is_missing_required_ok(a, matcher) {
continue 'outer;
}
}
let err = if self.settings.is_set(AppSettings::ArgRequiredElseHelp) &&
matcher.is_empty() {
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(
let err =
if self.settings.is_set(AppSettings::ArgRequiredElseHelp) && matcher.is_empty() {
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))
.iter()
.fold(String::new(),
|acc, s| acc + &format!("\n {}", Format::Error(s))[..]),
&*self.create_current_usage(matcher),
self.color())
};
};
return Err(err);
}
Ok(())
@ -1615,8 +1621,8 @@ impl<'a, 'b> Parser<'a, 'b>
for n in bl.iter() {
if matcher.contains(n) ||
self.groups
.get(n)
.map_or(false, |g| g.args.iter().any(|an| matcher.contains(an))) {
.get(n)
.map_or(false, |g| g.args.iter().any(|an| matcher.contains(an))) {
return true;
}
}
@ -1625,15 +1631,15 @@ impl<'a, 'b> Parser<'a, 'b>
for n in ru.iter() {
if matcher.contains(n) ||
self.groups
.get(n)
.map_or(false, |g| g.args.iter().any(|an| matcher.contains(an))) {
if !a.is_set(ArgSettings::RequiredUnlessAll) {
return true;
}
found_any = true;
} else if a.is_set(ArgSettings::RequiredUnlessAll) {
return false;
}
.get(n)
.map_or(false, |g| g.args.iter().any(|an| matcher.contains(an))) {
if !a.is_set(ArgSettings::RequiredUnlessAll) {
return true;
}
found_any = true;
} else if a.is_set(ArgSettings::RequiredUnlessAll) {
return false;
}
}
return found_any;
}
@ -1650,16 +1656,14 @@ impl<'a, 'b> Parser<'a, 'b>
// Add the arg to the matches to build a proper usage string
if let Some(name) = suffix.1 {
if let Some(opt) = self.opts
.iter()
.filter(|o| o.long.is_some() && o.long.unwrap() == name)
.next() {
.iter()
.find(|o| o.long.is_some() && o.long.unwrap() == name) {
self.groups_for_arg(&*opt.name)
.and_then(|grps| Some(matcher.inc_occurrences_of(&*grps)));
matcher.insert(&*opt.name);
} else if let Some(flg) = self.flags
.iter()
.filter(|f| f.long.is_some() && f.long.unwrap() == name)
.next() {
.iter()
.find(|f| f.long.is_some() && f.long.unwrap() == name) {
self.groups_for_arg(&*flg.name)
.and_then(|grps| Some(matcher.inc_occurrences_of(&*grps)));
matcher.insert(&*flg.name);
@ -1667,7 +1671,10 @@ impl<'a, 'b> Parser<'a, 'b>
}
let used_arg = format!("--{}", arg);
Err(Error::unknown_argument(&*used_arg, &*suffix.0, &*self.create_current_usage(matcher), self.color()))
Err(Error::unknown_argument(&*used_arg,
&*suffix.0,
&*self.create_current_usage(matcher),
self.color()))
}
// Creates a usage string if one was not provided by the user manually. This happens just
@ -1692,17 +1699,17 @@ impl<'a, 'b> Parser<'a, 'b>
usage.push_str(&*u);
} else if used.is_empty() {
usage.push_str(&*self.meta
.usage
.as_ref()
.unwrap_or(self.meta
.bin_name
.as_ref()
.unwrap_or(&self.meta.name)));
.usage
.as_ref()
.unwrap_or(self.meta
.bin_name
.as_ref()
.unwrap_or(&self.meta.name)));
let mut reqs: Vec<&str> = self.required().map(|r| &**r).collect();
reqs.dedup();
let req_string = self.get_required_from(&reqs, None)
.iter()
.fold(String::new(), |a, s| a + &format!(" {}", s)[..]);
.iter()
.fold(String::new(), |a, s| a + &format!(" {}", s)[..]);
let flags = self.needs_flags_tag();
if flags && !self.is_set(AppSettings::UnifiedHelpMessage) {
@ -1756,17 +1763,17 @@ impl<'a, 'b> Parser<'a, 'b>
hs.extend_from_slice(used);
let r_string = self.get_required_from(&hs, None)
.iter()
.fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
.iter()
.fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
usage.push_str(&self.meta
.usage
.as_ref()
.unwrap_or(self.meta
.bin_name
.as_ref()
.unwrap_or(&self.meta
.name))[..]);
.usage
.as_ref()
.unwrap_or(self.meta
.bin_name
.as_ref()
.unwrap_or(&self.meta
.name))[..]);
usage.push_str(&*r_string);
if self.is_set(AppSettings::SubcommandRequired) {
usage.push_str(" <SUBCOMMAND>");

View file

@ -1,5 +1,6 @@
use std::str::FromStr;
use std::ascii::AsciiExt;
use std::str::FromStr;
bitflags! {
flags Flags: u32 {
@ -655,7 +656,7 @@ mod test {
assert_eq!("hidden".parse::<AppSettings>().unwrap(),
AppSettings::Hidden);
assert_eq!("dontdelimittrailingvalues".parse::<AppSettings>().unwrap(),
AppSettings::DontDelimitTrailingValues);
AppSettings::DontDelimitTrailingValues);
assert!("hahahaha".parse::<AppSettings>().is_err());
}
}

View file

@ -1,8 +1,11 @@
use std::rc::Rc;
// Third Party
use vec_map::VecMap;
// Internal
use args::settings::ArgSettings;
use std::rc::Rc;
use vec_map::VecMap;
#[doc(hidden)]
pub trait AnyArg<'n, 'e> {

View file

@ -1,14 +1,18 @@
// use std::collections::HashSet;
use std::fmt::{Display, Formatter, Result};
use std::convert::From;
use std::rc::Rc;
use std::result::Result as StdResult;
// Std
use vec_map::VecMap;
// Internal
use Arg;
use args::{AnyArg, DispOrder};
use args::settings::{ArgFlags, ArgSettings};
use std::convert::From;
use std::fmt::{Display, Formatter, Result};
use std::rc::Rc;
use std::result::Result as StdResult;
// Third Party
use vec_map::VecMap;
#[derive(Debug)]
#[doc(hidden)]
@ -179,8 +183,8 @@ impl<'n, 'e> DispOrder for FlagBuilder<'n, 'e> {
#[cfg(test)]
mod test {
use super::FlagBuilder;
use args::settings::ArgSettings;
use super::FlagBuilder;
#[test]
fn flagbuilder_display() {

View file

@ -1,11 +1,16 @@
use std::rc::Rc;
use std::fmt::{Display, Formatter, Result};
use std::result::Result as StdResult;
// Std
use vec_map::VecMap;
// Internal
use args::{AnyArg, Arg, DispOrder};
use args::settings::{ArgFlags, ArgSettings};
use std::fmt::{Display, Formatter, Result};
use std::rc::Rc;
use std::result::Result as StdResult;
// Third Party
use vec_map::VecMap;
#[allow(missing_debug_implementations)]
#[doc(hidden)]
@ -261,9 +266,9 @@ impl<'n, 'e> DispOrder for OptBuilder<'n, 'e> {
#[cfg(test)]
mod test {
use args::settings::ArgSettings;
use super::OptBuilder;
use vec_map::VecMap;
use args::settings::ArgSettings;
#[test]
fn optbuilder_display1() {

View file

@ -1,13 +1,18 @@
use std::fmt::{Display, Formatter, Result};
use std::result::Result as StdResult;
use std::rc::Rc;
use std::borrow::Cow;
// Std
use vec_map::VecMap;
// Internal
use Arg;
use args::{AnyArg, DispOrder};
use args::settings::{ArgFlags, ArgSettings};
use std::borrow::Cow;
use std::fmt::{Display, Formatter, Result};
use std::rc::Rc;
use std::result::Result as StdResult;
// Third Party
use vec_map::VecMap;
#[allow(missing_debug_implementations)]
#[doc(hidden)]
@ -110,7 +115,7 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
pb
}
pub fn multiple_str(&self) -> &str {
pub fn multiple_str(&self) -> &str {
if self.settings.is_set(ArgSettings::Multiple) && self.val_names.is_none() {
"..."
} else {
@ -121,9 +126,9 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
pub fn name_no_brackets(&self) -> Cow<str> {
if let Some(ref names) = self.val_names {
Cow::Owned(names.values()
.map(|n| format!("<{}>", n))
.collect::<Vec<_>>()
.join(" "))
.map(|n| format!("<{}>", n))
.collect::<Vec<_>>()
.join(" "))
} else {
Cow::Borrowed(self.name)
}
@ -136,9 +141,9 @@ impl<'n, 'e> Display for PosBuilder<'n, 'e> {
try!(write!(f,
"{}",
names.values()
.map(|n| format!("<{}>", n))
.collect::<Vec<_>>()
.join(" ")));
.map(|n| format!("<{}>", n))
.collect::<Vec<_>>()
.join(" ")));
} else {
try!(write!(f, "<{}>", self.name));
}
@ -251,8 +256,8 @@ impl<'n, 'e> DispOrder for PosBuilder<'n, 'e> {
#[cfg(test)]
mod test {
use super::PosBuilder;
use args::settings::ArgSettings;
use super::PosBuilder;
use vec_map::VecMap;
#[test]

View file

@ -1,12 +1,17 @@
use std::ffi::OsStr;
use std::collections::hash_map::{Entry, Iter};
use std::ops::Deref;
// Std
use vec_map::VecMap;
// Internal
use args::{ArgMatches, MatchedArg, SubCommand};
use args::settings::ArgSettings;
use args::AnyArg;
use args::settings::ArgSettings;
use std::collections::hash_map::{Entry, Iter};
use std::ffi::OsStr;
use std::ops::Deref;
// Third Party
use vec_map::VecMap;
#[doc(hidden)]
#[allow(missing_debug_implementations)]

View file

@ -1,15 +1,20 @@
use std::ffi::{OsStr, OsString};
// Std
// Internal
use INVALID_UTF8;
use args::MatchedArg;
use args::SubCommand;
use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::{OsStr, OsString};
use std::iter::Map;
use std::slice;
use std::borrow::Cow;
// Third Party
use vec_map;
use args::SubCommand;
use args::MatchedArg;
use INVALID_UTF8;
/// Used to get information about the arguments that where supplied to the program at runtime by
/// the user. New instances of this struct are obtained by using the [`App::get_matches`] family of
/// methods.
@ -242,9 +247,9 @@ impl<'a> ArgMatches<'a> {
pub fn values_of_lossy<S: AsRef<str>>(&'a self, name: S) -> Option<Vec<String>> {
if let Some(arg) = self.args.get(name.as_ref()) {
return Some(arg.vals
.values()
.map(|v| v.to_string_lossy().into_owned())
.collect());
.values()
.map(|v| v.to_string_lossy().into_owned())
.collect());
}
None
}

View file

@ -1,12 +1,13 @@
pub use self::arg::Arg;
pub use self::arg_matches::{Values, OsValues, ArgMatches};
pub use self::arg_matcher::ArgMatcher;
pub use self::subcommand::SubCommand;
pub use self::arg_builder::{FlagBuilder, OptBuilder, PosBuilder};
pub use self::matched_arg::MatchedArg;
pub use self::group::ArgGroup;
pub use self::any_arg::{AnyArg, DispOrder};
pub use self::arg::Arg;
pub use self::arg_builder::{FlagBuilder, OptBuilder, PosBuilder};
pub use self::arg_matcher::ArgMatcher;
pub use self::arg_matches::{Values, OsValues, ArgMatches};
pub use self::group::ArgGroup;
pub use self::matched_arg::MatchedArg;
pub use self::settings::ArgSettings;
pub use self::subcommand::SubCommand;
#[macro_use]
mod macros;

View file

@ -1,5 +1,7 @@
use std::str::FromStr;
// Std
use std::ascii::AsciiExt;
use std::str::FromStr;
bitflags! {
flags Flags: u16 {

View file

@ -1,8 +1,12 @@
use std::io::Write;
// Std
// Internal
use app::parser::Parser;
use shell::Shell;
use args::{ArgSettings, OptBuilder};
use shell::Shell;
use std::io::Write;
macro_rules! w {
($buf:expr, $to_w:expr) => {
@ -13,15 +17,15 @@ macro_rules! w {
};
}
pub struct ComplGen<'a, 'b> where 'a: 'b {
pub struct ComplGen<'a, 'b>
where 'a: 'b
{
p: &'b Parser<'a, 'b>,
}
impl<'a, 'b> ComplGen<'a, 'b> {
pub fn new(p: &'b Parser<'a, 'b>) -> Self {
ComplGen {
p: p,
}
ComplGen { p: p }
}
pub fn generate<W: Write>(&self, for_shell: Shell, buf: &mut W) {
@ -32,8 +36,8 @@ impl<'a, 'b> ComplGen<'a, 'b> {
}
fn gen_bash<W: Write>(&self, buf: &mut W) {
w!(buf, format!(
"_{name}() {{
w!(buf,
format!("_{name}() {{
local i cur prev opts cmds
COMPREPLY=()
cur=\"${{COMP_WORDS[COMP_CWORD]}}\"
@ -75,12 +79,13 @@ impl<'a, 'b> ComplGen<'a, 'b> {
complete -F _{name} {name}
",
name=self.p.meta.bin_name.as_ref().unwrap(),
name_opts=self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()),
name_opts_details=self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
subcmds=self.all_subcommands(),
subcmd_details=self.subcommand_details()
).as_bytes());
name = self.p.meta.bin_name.as_ref().unwrap(),
name_opts = self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()),
name_opts_details =
self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
subcmds = self.all_subcommands(),
subcmd_details = self.subcommand_details())
.as_bytes());
}
fn all_subcommands(&self) -> String {
@ -88,13 +93,12 @@ complete -F _{name} {name}
let scs = get_all_subcommands(self.p);
for sc in &scs {
subcmds = format!(
"{}
subcmds = format!("{}
{name})
cmd+=\"_{name}\"
;;",
subcmds,
name=sc.replace("-", "_"));
subcmds,
name = sc.replace("-", "_"));
}
subcmds
@ -107,8 +111,7 @@ complete -F _{name} {name}
scs.dedup();
for sc in &scs {
subcmd_dets = format!(
"{}
subcmd_dets = format!("{}
{subcmd})
opts=\"{sc_opts}\"
if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then
@ -124,12 +127,11 @@ complete -F _{name} {name}
COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
return 0
;;",
subcmd_dets,
subcmd=sc.replace("-", "_"),
sc_opts=self.all_options_for_path(&*sc),
level=sc.split("_").map(|_|1).fold(0, |acc, n| acc + n),
opts_details=self.option_details_for_path(&*sc)
);
subcmd_dets,
subcmd = sc.replace("-", "_"),
sc_opts = self.all_options_for_path(&*sc),
level = sc.split("_").map(|_| 1).fold(0, |acc, n| acc + n),
opts_details = self.option_details_for_path(&*sc));
}
subcmd_dets
@ -139,25 +141,45 @@ complete -F _{name} {name}
let mut p = self.p;
for sc in path.split('_').skip(1) {
debugln!("iter;sc={}", sc);
p = &p.subcommands.iter()
.filter(|s| s.p.meta.name == sc
|| (s.p.meta.aliases.is_some() && s.p.meta.aliases.as_ref()
.unwrap()
.iter()
.any(|&(n,_)| n==sc )))
.next()
.unwrap().p;
p = &p.subcommands
.iter()
.find(|s| {
s.p.meta.name == sc ||
(s.p.meta.aliases.is_some() &&
s.p
.meta
.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(n, _)| n == sc))
})
.unwrap()
.p;
}
let mut opts = p.short_list.iter().fold(String::new(), |acc, s| format!("{} -{}", acc, s));
opts = format!("{} {}", opts, p.long_list.iter()
.fold(String::new(), |acc, l| format!("{} --{}", acc, l)));
opts = format!("{} {}", opts, p.positionals.values()
.fold(String::new(), |acc, p| format!("{} {}", acc, p)));
opts = format!("{} {}", opts, p.subcommands.iter()
.fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name)));
opts = format!("{} {}",
opts,
p.long_list
.iter()
.fold(String::new(), |acc, l| format!("{} --{}", acc, l)));
opts = format!("{} {}",
opts,
p.positionals
.values()
.fold(String::new(), |acc, p| format!("{} {}", acc, p)));
opts = format!("{} {}",
opts,
p.subcommands
.iter()
.fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name)));
for sc in &p.subcommands {
if let Some(ref aliases) = sc.p.meta.aliases {
opts = format!("{} {}", opts, aliases.iter().map(|&(n,_)| n).fold(String::new(), |acc, a| format!("{} {}", acc, a)));
opts = format!("{} {}",
opts,
aliases.iter()
.map(|&(n, _)| n)
.fold(String::new(), |acc, a| format!("{} {}", acc, a)));
}
}
opts
@ -167,7 +189,21 @@ complete -F _{name} {name}
let mut p = self.p;
for sc in path.split('_').skip(1) {
debugln!("iter;sc={}", sc);
p = &p.subcommands.iter().filter(|s| s.p.meta.name == sc || (s.p.meta.aliases.is_some() && s.p.meta.aliases.as_ref().unwrap().iter().any(|&(n,_)| n==sc ))).next().unwrap().p;
p = &p.subcommands
.iter()
.find(|s| {
s.p.meta.name == sc ||
(s.p.meta.aliases.is_some() &&
s.p
.meta
.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(n, _)| n == sc))
})
.unwrap()
.p;
}
let mut opts = String::new();
for o in &p.opts {
@ -176,21 +212,27 @@ complete -F _{name} {name}
--{})
COMPREPLY=({})
return 0
;;", opts, l, vals_for(o));
;;",
opts,
l,
vals_for(o));
}
if let Some(s) = o.short {
opts = format!("{}
-{})
COMPREPLY=({})
return 0
;;", opts, s, vals_for(o));
;;",
opts,
s,
vals_for(o));
}
}
opts
}
fn gen_fish<W: Write>(&self, buf: &mut W) {
let command = self.p.meta.bin_name.as_ref().unwrap();
let command = self.p.meta.bin_name.as_ref().unwrap();
let subcommands: Vec<_> = get_all_subcommands(self.p);
let has_subcommands = subcommands.len() > 1;
@ -285,12 +327,10 @@ fn vals_for(o: &OptBuilder) -> String {
} else if let Some(vec) = o.val_names() {
let mut it = vec.iter().peekable();
while let Some((_, val)) = it.next() {
ret = format!("{}<{}>{}", ret, val,
if it.peek().is_some() {
" "
} else {
""
});
ret = format!("{}<{}>{}",
ret,
val,
if it.peek().is_some() { " " } else { "" });
}
let num = vec.len();
if o.is_set(ArgSettings::Multiple) && num == 1 {
@ -299,12 +339,10 @@ fn vals_for(o: &OptBuilder) -> String {
} else if let Some(num) = o.num_vals() {
let mut it = (0..num).peekable();
while let Some(_) = it.next() {
ret = format!("{}<{}>{}", ret, o.name(),
if it.peek().is_some() {
" "
} else {
""
});
ret = format!("{}<{}>{}",
ret,
o.name(),
if it.peek().is_some() { " " } else { "" });
}
if o.is_set(ArgSettings::Multiple) && num == 1 {
ret = format!("{}...", ret);
@ -344,11 +382,11 @@ fn gen_fish_inner(root_command: &str,
for option in &comp_gen.p.opts {
let mut template = format!("complete -c {}", root_command);
if !parent_cmds.is_empty() {
template.push_str(format!(" -n '__fish_seen_subcommand_from {}'",
command).as_str());
template.push_str(format!(" -n '__fish_seen_subcommand_from {}'", command).as_str());
} else if has_no_subcommand_fn {
template.push_str(format!(" -n '__fish_{}_no_subcommand'",
comp_gen.p.meta.bin_name.as_ref().unwrap()).as_str());
comp_gen.p.meta.bin_name.as_ref().unwrap())
.as_str());
}
if let Some(data) = option.short {
template.push_str(format!(" -s {}", data).as_str());
@ -369,11 +407,11 @@ fn gen_fish_inner(root_command: &str,
for flag in &comp_gen.p.flags {
let mut template = format!("complete -c {}", root_command);
if !parent_cmds.is_empty() {
template.push_str(format!(" -n '__fish_seen_subcommand_from {}'",
command).as_str());
template.push_str(format!(" -n '__fish_seen_subcommand_from {}'", command).as_str());
} else if has_no_subcommand_fn {
template.push_str(format!(" -n '__fish_{}_no_subcommand'",
comp_gen.p.meta.bin_name.as_ref().unwrap()).as_str());
comp_gen.p.meta.bin_name.as_ref().unwrap())
.as_str());
}
if let Some(data) = flag.short {
template.push_str(format!(" -s {}", data).as_str());
@ -393,10 +431,12 @@ fn gen_fish_inner(root_command: &str,
let mut template = format!("complete -c {}", root_command);
if !parent_cmds.is_empty() {
template.push_str(format!(" -n '__fish_seen_subcommand_from {}'",
subcommand).as_str());
subcommand)
.as_str());
} else if has_no_subcommand_fn {
template.push_str(format!(" -n '__fish_{}_no_subcommand'",
comp_gen.p.meta.bin_name.as_ref().unwrap()).as_str());
comp_gen.p.meta.bin_name.as_ref().unwrap())
.as_str());
}
template.push_str(" -f");
template.push_str(format!(" -a '{}'", subcommand).as_str());

View file

@ -1,14 +1,17 @@
use std::process;
// Std
// Internal
use args::any_arg::AnyArg;
use fmt;
use std::convert::From;
use std::error::Error as StdError;
use std::fmt as std_fmt;
use std::fmt::Display;
use std::io::{self, Write};
use std::convert::From;
use std::process;
use std::result::Result as StdResult;
use fmt;
use suggestions;
use args::any_arg::AnyArg;
/// Short hand for [`Result`] type
/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
@ -383,7 +386,11 @@ impl Error {
}
#[doc(hidden)]
pub fn argument_conflict<'a, 'b, A, O, U>(arg: &A, other: Option<O>, usage: U, color: fmt::ColorWhen) -> Self
pub fn argument_conflict<'a, 'b, A, O, U>(arg: &A,
other: Option<O>,
usage: U,
color: fmt::ColorWhen)
-> Self
where A: AnyArg<'a, 'b> + Display,
O: Into<String>,
U: Display
@ -391,7 +398,7 @@ impl Error {
let mut v = vec![arg.name().to_owned()];
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} The argument '{}' cannot be used with {}\n\n\
@ -405,12 +412,15 @@ impl Error {
v.push(n.clone());
c.warning(format!("'{}'", n))
}
None => c.none("one or more of the other specified arguments".to_owned()),
None => {
c.none("one or more of the other specified arguments"
.to_owned())
}
},
usage,
c.good("--help")),
kind: ErrorKind::ArgumentConflict,
info: Some(v)
info: Some(v),
}
}
@ -421,7 +431,7 @@ impl Error {
{
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} The argument '{}' requires a value but none was supplied\
@ -438,7 +448,12 @@ impl Error {
}
#[doc(hidden)]
pub fn invalid_value<'a, 'b, B, G, A, U>(bad_val: B, good_vals: &[G], arg: &A, usage: U, color: fmt::ColorWhen) -> Self
pub fn invalid_value<'a, 'b, B, G, A, U>(bad_val: B,
good_vals: &[G],
arg: &A,
usage: U,
color: fmt::ColorWhen)
-> Self
where B: AsRef<str>,
G: AsRef<str> + Display,
A: AnyArg<'a, 'b> + Display,
@ -446,7 +461,7 @@ impl Error {
{
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
let suffix =
suggestions::did_you_mean_suffix(bad_val.as_ref(),
@ -479,7 +494,12 @@ impl Error {
}
#[doc(hidden)]
pub fn invalid_subcommand<S, D, N, U>(subcmd: S, did_you_mean: D, name: N, usage: U, color: fmt::ColorWhen) -> Self
pub fn invalid_subcommand<S, D, N, U>(subcmd: S,
did_you_mean: D,
name: N,
usage: U,
color: fmt::ColorWhen)
-> Self
where S: Into<String>,
D: AsRef<str> + Display,
N: Display,
@ -488,7 +508,7 @@ impl Error {
let s = subcmd.into();
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} The subcommand '{}' wasn't recognized\n\t\
@ -518,7 +538,7 @@ impl Error {
let s = subcmd.into();
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} The subcommand '{}' wasn't recognized\n\n\
@ -542,7 +562,7 @@ impl Error {
{
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} The following required arguments were not provided:{}\n\n\
@ -564,7 +584,7 @@ impl Error {
{
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} '{}' requires a subcommand, but one was not provided\n\n\
@ -586,7 +606,7 @@ impl Error {
{
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} Invalid UTF-8 was detected in one or more arguments\n\n\
@ -601,7 +621,11 @@ impl Error {
}
#[doc(hidden)]
pub fn too_many_values<'a, 'b, V, A, U>(val: V, arg: &A, usage: U, color: fmt::ColorWhen) -> Self
pub fn too_many_values<'a, 'b, V, A, U>(val: V,
arg: &A,
usage: U,
color: fmt::ColorWhen)
-> Self
where V: AsRef<str> + Display + ToOwned,
A: AnyArg<'a, 'b> + Display,
U: Display
@ -609,7 +633,7 @@ impl Error {
let v = val.as_ref();
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} The value '{}' was provided to '{}', but it wasn't expecting \
@ -627,13 +651,18 @@ impl Error {
}
#[doc(hidden)]
pub fn too_few_values<'a, 'b, A, U>(arg: &A, min_vals: u64, curr_vals: usize, usage: U, color: fmt::ColorWhen) -> Self
pub fn too_few_values<'a, 'b, A, U>(arg: &A,
min_vals: u64,
curr_vals: usize,
usage: U,
color: fmt::ColorWhen)
-> Self
where A: AnyArg<'a, 'b> + Display,
U: Display
{
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} The argument '{}' requires at least {} values, but only {} w{} \
@ -644,11 +673,7 @@ impl Error {
c.warning(arg.to_string()),
c.warning(min_vals.to_string()),
c.warning(curr_vals.to_string()),
if curr_vals > 1 {
"ere"
} else {
"as"
},
if curr_vals > 1 { "ere" } else { "as" },
usage,
c.good("--help")),
kind: ErrorKind::TooFewValues,
@ -660,7 +685,7 @@ impl Error {
pub fn value_validation(err: String, color: fmt::ColorWhen) -> Self {
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} {}", c.error("error:"), err),
@ -679,7 +704,8 @@ impl Error {
num_vals: u64,
curr_vals: usize,
suffix: S,
usage: U, color: fmt::ColorWhen)
usage: U,
color: fmt::ColorWhen)
-> Self
where A: AnyArg<'a, 'b> + Display,
S: Display,
@ -687,7 +713,7 @@ impl Error {
{
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} The argument '{}' requires {} values, but {} w{} \
@ -713,7 +739,7 @@ impl Error {
{
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} The argument '{}' was provided more than once, but cannot \
@ -730,14 +756,18 @@ impl Error {
}
#[doc(hidden)]
pub fn unknown_argument<A, U>(arg: A, did_you_mean: &str, usage: U, color: fmt::ColorWhen) -> Self
pub fn unknown_argument<A, U>(arg: A,
did_you_mean: &str,
usage: U,
color: fmt::ColorWhen)
-> Self
where A: Into<String>,
U: Display
{
let a = arg.into();
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} Found argument '{}' which wasn't expected, or isn't valid in \
@ -762,7 +792,7 @@ impl Error {
pub fn io_error(e: &Error, color: fmt::ColorWhen) -> Self {
let c = fmt::Colorizer {
use_stderr: true,
when: color
when: color,
};
Error {
message: format!("{} {}", c.error("error:"), e.description()),
@ -778,7 +808,7 @@ impl Error {
let a = arg.into();
let c = fmt::Colorizer {
use_stderr: true,
when: fmt::ColorWhen::Auto
when: fmt::ColorWhen::Auto,
};
Error {
message: format!("{} The argument '{}' wasn't found",
@ -788,6 +818,22 @@ impl Error {
info: Some(vec![a]),
}
}
/// Create an error with a custom description.
///
/// 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 {
let c = fmt::Colorizer {
use_stderr: true,
when: fmt::ColorWhen::Auto,
};
Error {
message: format!("{} {}", c.error("error:"), description),
kind: kind,
info: None,
}
}
}
impl StdError for Error {
@ -804,28 +850,12 @@ impl Display for Error {
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
let c = fmt::Colorizer {
use_stderr: true,
when: fmt::ColorWhen::Auto
};
Error {
message: format!("{} {}", c.error("error:"), e.description()),
kind: ErrorKind::Io,
info: None,
}
Error::with_description(e.description(), ErrorKind::Io)
}
}
impl From<std_fmt::Error> for Error {
fn from(e: std_fmt::Error) -> Self {
let c = fmt::Colorizer {
use_stderr: true,
when: fmt::ColorWhen::Auto
};
Error {
message: format!("{} {}", c.error("error:"), e),
kind: ErrorKind::Format,
info: None,
}
Error::with_description(e.description(), ErrorKind::Format)
}
}

View file

@ -1,12 +1,11 @@
use std::fmt;
#[cfg(all(feature = "color", not(target_os = "windows")))]
use ansi_term::Colour::{Green, Red, Yellow};
#[cfg(all(feature = "color", not(target_os = "windows")))]
use ansi_term::ANSIString;
#[cfg(all(feature = "color", not(target_os = "windows")))]
use ansi_term::Colour::{Green, Red, Yellow};
#[cfg(feature = "color")]
use libc;
use libc;use std::fmt;
#[cfg(all(feature = "color", not(target_os = "windows")))]
const STDERR: i32 = libc::STDERR_FILENO;
@ -23,7 +22,7 @@ const STDOUT: i32 = 0;
pub enum ColorWhen {
Auto,
Always,
Never
Never,
}
#[cfg(feature = "color")]
@ -43,7 +42,7 @@ pub fn is_a_tty(_: bool) -> bool {
#[doc(hidden)]
pub struct Colorizer {
pub use_stderr: bool,
pub when: ColorWhen
pub when: ColorWhen,
}
macro_rules! color {
@ -61,22 +60,30 @@ macro_rules! color {
}
impl Colorizer {
pub fn good<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str> {
pub fn good<T>(&self, msg: T) -> Format<T>
where T: fmt::Display + AsRef<str>
{
debugln!("exec=good;");
color!(self, Good, msg)
}
pub fn warning<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str> {
pub fn warning<T>(&self, msg: T) -> Format<T>
where T: fmt::Display + AsRef<str>
{
debugln!("exec=warning;");
color!(self, Warning, msg)
}
pub fn error<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str> {
pub fn error<T>(&self, msg: T) -> Format<T>
where T: fmt::Display + AsRef<str>
{
debugln!("exec=error;");
color!(self, Error, msg)
}
pub fn none<T>(&self, msg: T) -> Format<T> where T: fmt::Display + AsRef<str> {
pub fn none<T>(&self, msg: T) -> Format<T>
where T: fmt::Display + AsRef<str>
{
debugln!("exec=none;");
Format::None(msg)
}
@ -86,7 +93,7 @@ impl Default for Colorizer {
fn default() -> Self {
Colorizer {
use_stderr: true,
when: ColorWhen::Auto
when: ColorWhen::Auto,
}
}
}
@ -147,9 +154,9 @@ impl<T: fmt::Display> fmt::Display for Format<T> {
#[cfg(all(test, feature = "color", not(target_os = "windows")))]
mod test {
use super::Format;
use ansi_term::Colour::{Green, Red, Yellow};
use ansi_term::ANSIString;
use ansi_term::Colour::{Green, Red, Yellow};
use super::Format;
#[test]
fn colored_output() {
@ -161,6 +168,7 @@ mod test {
let warn = Format::Warning("warn");
assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn")));
let none = Format::None("none");
assert_eq!(&*format!("{}", none), &*format!("{}", ANSIString::from("none")));
assert_eq!(&*format!("{}", none),
&*format!("{}", ANSIString::from("none")));
}
}

View file

@ -1,10 +1,8 @@
use std::ffi::OsStr;
#[cfg(target_os = "windows")]
use INVALID_UTF8;use std::ffi::OsStr;
#[cfg(not(target_os = "windows"))]
use std::os::unix::ffi::OsStrExt;
#[cfg(target_os = "windows")]
use INVALID_UTF8;
#[cfg(target_os = "windows")]
trait OsStrExt3 {
fn from_bytes(b: &[u8]) -> &Self;

View file

@ -1,8 +1,12 @@
use vec_map::VecMap;
// Third Party
// Internal
use INTERNAL_ERROR_MSG;
use args::Arg;
use args::settings::ArgSettings;
use INTERNAL_ERROR_MSG;
use vec_map::VecMap;
type ParseResult = Result<(), ()>;