wip: changes to builders in prep for v3

This commit is contained in:
Kevin K 2018-01-22 18:19:53 -05:00
parent 969c3adb41
commit acdbd47152
27 changed files with 3091 additions and 3772 deletions

View file

@ -2,17 +2,16 @@
use std::borrow::Cow;
use std::cmp;
use std::collections::BTreeMap;
use std::fmt::Display;
use std::io::{self, Cursor, Read, Write};
use std::usize;
// Internal
use app::{App, AppSettings};
use app::parser::Parser;
use args::{AnyArg, ArgSettings, DispOrder};
use args::{ArgSettings, DispOrder, Arg};
use errors::{Error, Result as ClapResult};
use fmt::{Colorizer, ColorizerOption, Format};
use app::usage;
use app::usage::Usage;
use map::VecMap;
use INTERNAL_ERROR_MSG;
@ -31,29 +30,16 @@ fn str_width(s: &str) -> usize { UnicodeWidthStr::width(s) }
const TAB: &'static str = " ";
// These are just convenient traits to make the code easier to read.
trait ArgWithDisplay<'b, 'c>: AnyArg<'b, 'c> + Display {}
impl<'b, 'c, T> ArgWithDisplay<'b, 'c> for T
where
T: AnyArg<'b, 'c> + Display,
{
}
trait ArgWithOrder<'b, 'c>: ArgWithDisplay<'b, 'c> + DispOrder {
fn as_base(&self) -> &ArgWithDisplay<'b, 'c>;
}
impl<'b, 'c, T> ArgWithOrder<'b, 'c> for T
where
T: ArgWithDisplay<'b, 'c> + DispOrder,
{
fn as_base(&self) -> &ArgWithDisplay<'b, 'c> { self }
}
fn as_arg_trait<'a, 'b, T: ArgWithOrder<'a, 'b>>(x: &T) -> &ArgWithOrder<'a, 'b> { x }
impl<'b, 'c> DispOrder for App<'b, 'c> {
fn disp_ord(&self) -> usize { 999 }
}
// trait ArgWithOrder<'b, 'c>: Display + DispOrder {
// fn as_base(&self) -> &Arg<'b, 'c>;
// }
// impl<'b, 'c, T> ArgWithOrder<'b, 'c> for T
// where
// T: Display + DispOrder,
// {
// fn as_base(&self) -> &Arg<'b, 'c> { self }
// }
// fn as_arg_trait<'w, 'b, T: ArgWithOrder<'w, 'b>>(x: &T) -> &ArgWithOrder<'w, 'b> { x }
macro_rules! color {
($_self:ident, $s:expr, $c:ident) => {
@ -75,8 +61,8 @@ macro_rules! color {
/// `clap` Help Writer.
///
/// Wraps a writer stream providing different methods to generate help for `clap` objects.
pub struct Help<'a> {
writer: &'a mut Write,
pub struct Help<'w> {
writer: &'w mut Write,
next_line_help: bool,
hide_pv: bool,
term_w: usize,
@ -88,11 +74,11 @@ pub struct Help<'a> {
}
// Public Functions
impl<'a> Help<'a> {
impl<'w> Help<'w> {
/// Create a new `Help` instance.
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
pub fn new(
w: &'a mut Write,
w: &'w mut Write,
next_line_help: bool,
hide_pv: bool,
color: bool,
@ -130,14 +116,15 @@ impl<'a> Help<'a> {
/// Reads help settings from an App
/// and write its help to the wrapped stream.
pub fn write_app_help(w: &'a mut Write, app: &App, use_long: bool) -> ClapResult<()> {
pub fn write_app_help(w: &'w mut Write, app: &App, use_long: bool) -> ClapResult<()> {
debugln!("Help::write_app_help;");
Self::write_parser_help(w, &app.p, use_long)
let p = RefParser::new(app);
Self::write_parser_help(w, &p, use_long)
}
/// Reads help settings from a Parser
/// and write its help to the wrapped stream.
pub fn write_parser_help(w: &'a mut Write, parser: &Parser, use_long: bool) -> ClapResult<()> {
pub fn write_parser_help(w: &'w mut Write, parser: &Parser, use_long: bool) -> ClapResult<()> {
debugln!("Help::write_parser_help;");
Self::_write_parser_help(w, parser, false, use_long)
}
@ -145,14 +132,14 @@ impl<'a> Help<'a> {
/// Reads help settings from a Parser
/// and write its help to the wrapped stream which will be stderr. This method prevents
/// formatting when required.
pub fn write_parser_help_to_stderr(w: &'a mut Write, parser: &Parser) -> ClapResult<()> {
pub fn write_parser_help_to_stderr(w: &'w mut Write, parser: &Parser) -> ClapResult<()> {
debugln!("Help::write_parser_help;");
Self::_write_parser_help(w, parser, true, false)
}
#[doc(hidden)]
pub fn _write_parser_help(
w: &'a mut Write,
w: &'w mut Write,
parser: &Parser,
stderr: bool,
use_long: bool,
@ -163,7 +150,7 @@ impl<'a> Help<'a> {
let color = parser.is_set(AppSettings::ColoredHelp);
let cizer = Colorizer::new(ColorizerOption {
use_stderr: stderr,
when: parser.color(),
when: parser.app.color(),
});
Self::new(
w,
@ -171,8 +158,8 @@ impl<'a> Help<'a> {
hide_v,
color,
cizer,
parser.meta.term_w,
parser.meta.max_w,
parser.app.term_w,
parser.app.max_w,
use_long,
).write_help(parser)
}
@ -180,9 +167,9 @@ impl<'a> Help<'a> {
/// Writes the parser help to the wrapped stream.
pub fn write_help(&mut self, parser: &Parser) -> ClapResult<()> {
debugln!("Help::write_help;");
if let Some(h) = parser.meta.help_str {
if let Some(h) = parser.app.help_str {
write!(self.writer, "{}", h).map_err(Error::from)?;
} else if let Some(tmpl) = parser.meta.template {
} else if let Some(tmpl) = parser.app.template {
self.write_templated_help(parser, tmpl)?;
} else {
self.write_default_help(parser)?;
@ -191,12 +178,13 @@ impl<'a> Help<'a> {
}
}
// Methods to write AnyArg help.
impl<'a> Help<'a> {
// Methods to write Arg help.
impl<'w> Help<'w> {
/// Writes help for each argument in the order they were declared to the wrapped stream.
fn write_args_unsorted<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()>
fn write_args_unsorted<'a, 'b, I>(&mut self, args: I) -> io::Result<()>
where
I: Iterator<Item = &'d ArgWithOrder<'b, 'c>>,
'a: 'b,
I: Iterator<Item = &'b Arg<'a, 'b>>,
{
debugln!("Help::write_args_unsorted;");
// The shortest an arg can legally be is 2 (i.e. '-x')
@ -217,15 +205,16 @@ impl<'a> Help<'a> {
} else {
self.writer.write_all(b"\n")?;
}
self.write_arg(arg.as_base())?;
self.write_arg(arg)?;
}
Ok(())
}
/// Sorts arguments by length and display order and write their help to the wrapped stream.
fn write_args<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()>
fn write_args<'a, 'b, I>(&mut self, args: I) -> io::Result<()>
where
I: Iterator<Item = &'d ArgWithOrder<'b, 'c>>,
'a: 'b,
I: Iterator<Item = &'b Arg<'a, 'b>>,
{
debugln!("Help::write_args;");
// The shortest an arg can legally be is 2 (i.e. '-x')
@ -244,7 +233,7 @@ impl<'a> Help<'a> {
debugln!("Help::write_args: New Longest...{}", self.longest);
}
let btm = ord_m.entry(arg.disp_ord()).or_insert(BTreeMap::new());
btm.insert(arg.name(), arg);
btm.insert(arg.name, arg);
}
let mut first = true;
for btm in ord_m.values() {
@ -254,14 +243,14 @@ impl<'a> Help<'a> {
} else {
self.writer.write_all(b"\n")?;
}
self.write_arg(arg.as_base())?;
self.write_arg(arg)?;
}
}
Ok(())
}
/// Writes help for an argument to the wrapped stream.
fn write_arg<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> {
fn write_arg<'b, 'c>(&mut self, arg: &Arg<'b, 'c>) -> io::Result<()> {
debugln!("Help::write_arg;");
self.short(arg)?;
self.long(arg)?;
@ -271,10 +260,10 @@ impl<'a> Help<'a> {
}
/// Writes argument's short command to the wrapped stream.
fn short<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> {
fn short<'b, 'c>(&mut self, arg: &Arg<'b, 'c>) -> io::Result<()> {
debugln!("Help::short;");
write!(self.writer, "{}", TAB)?;
if let Some(s) = arg.short() {
if let Some(s) = arg.short {
color!(self, "-{}", s, good)
} else if arg.has_switch() {
write!(self.writer, "{}", TAB)
@ -284,14 +273,14 @@ impl<'a> Help<'a> {
}
/// Writes argument's long command to the wrapped stream.
fn long<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> {
fn long<'b, 'c>(&mut self, arg: &Arg<'b, 'c>) -> io::Result<()> {
debugln!("Help::long;");
if !arg.has_switch() {
return Ok(());
}
if arg.takes_value() {
if let Some(l) = arg.long() {
if arg.short().is_some() {
if arg.is_set(ArgSettings::TakesValue) {
if let Some(l) = arg.long {
if arg.short.is_some() {
write!(self.writer, ", ")?;
}
color!(self, "--{}", l, good)?
@ -303,8 +292,8 @@ impl<'a> Help<'a> {
" "
};
write!(self.writer, "{}", sep)?;
} else if let Some(l) = arg.long() {
if arg.short().is_some() {
} else if let Some(l) = arg.long {
if arg.short.is_some() {
write!(self.writer, ", ")?;
}
color!(self, "--{}", l, good)?;
@ -313,15 +302,15 @@ impl<'a> Help<'a> {
}
/// Writes argument's possible values to the wrapped stream.
fn val<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> Result<String, io::Error> {
fn val<'b, 'c>(&mut self, arg: &Arg<'b, 'c>) -> Result<String, io::Error> {
debugln!("Help::val: arg={}", arg);
if arg.takes_value() {
if arg.is_set(ArgSettings::TakesValue) {
let delim = if arg.is_set(ArgSettings::RequireDelimiter) {
arg.val_delim().expect(INTERNAL_ERROR_MSG)
arg.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
};
if let Some(vec) = arg.val_names() {
if let Some(vec) = arg.val_names {
let mut it = vec.iter().peekable();
while let Some((_, val)) = it.next() {
color!(self, "<{}>", val, good)?;
@ -333,10 +322,10 @@ impl<'a> Help<'a> {
if arg.is_set(ArgSettings::Multiple) && num == 1 {
color!(self, "...", good)?;
}
} else if let Some(num) = arg.num_vals() {
} else if let Some(num) = arg.num_vals {
let mut it = (0..num).peekable();
while let Some(_) = it.next() {
color!(self, "<{}>", arg.name(), good)?;
color!(self, "<{}>", arg.name, good)?;
if it.peek().is_some() {
write!(self.writer, "{}", delim)?;
}
@ -345,7 +334,7 @@ impl<'a> Help<'a> {
color!(self, "...", good)?;
}
} else if arg.has_switch() {
color!(self, "<{}>", arg.name(), good)?;
color!(self, "<{}>", arg.name, good)?;
if arg.is_set(ArgSettings::Multiple) {
color!(self, "...", good)?;
}
@ -355,7 +344,7 @@ impl<'a> Help<'a> {
}
let spec_vals = self.spec_vals(arg);
let h = arg.help().unwrap_or("");
let h = arg.help.unwrap_or("");
let h_w = str_width(h) + str_width(&*spec_vals);
let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp);
let taken = self.longest + 12;
@ -384,7 +373,7 @@ impl<'a> Help<'a> {
let mut spcs = self.longest - self_len;
// Since we're writing spaces from the tab point we first need to know if we
// had a long and short, or just short
if arg.long().is_some() {
if arg.long.is_some() {
// Only account 4 after the val
spcs += 4;
} else {
@ -440,12 +429,12 @@ impl<'a> Help<'a> {
}
/// Writes argument's help to the wrapped stream.
fn help<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>, spec_vals: &str) -> io::Result<()> {
fn help<'b, 'c>(&mut self, arg: &Arg<'b, 'c>, spec_vals: &str) -> io::Result<()> {
debugln!("Help::help;");
let h = if self.use_long {
arg.long_help().unwrap_or_else(|| arg.help().unwrap_or(""))
arg.long_help.unwrap_or_else(|| arg.help.unwrap_or(""))
} else {
arg.help().unwrap_or_else(|| arg.long_help().unwrap_or(""))
arg.help.unwrap_or_else(|| arg.long_help.unwrap_or(""))
};
let mut help = String::from(h) + spec_vals;
let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || self.use_long;
@ -496,10 +485,10 @@ impl<'a> Help<'a> {
Ok(())
}
fn spec_vals(&self, a: &ArgWithDisplay) -> String {
fn spec_vals(&self, a: &Arg) -> String {
debugln!("Help::spec_vals: a={}", a);
let mut spec_vals = vec![];
if let Some(ref env) = a.env() {
if let Some(ref env) = a.env {
debugln!(
"Help::spec_vals: Found environment variable...[{:?}:{:?}]",
env.0,
@ -518,7 +507,7 @@ impl<'a> Help<'a> {
spec_vals.push(env_info);
}
if !a.is_set(ArgSettings::HideDefaultValue) {
if let Some(pv) = a.default_val() {
if let Some(pv) = a.default_val {
debugln!("Help::spec_vals: Found default value...[{:?}]", pv);
spec_vals.push(format!(
" [default: {}]",
@ -530,23 +519,24 @@ impl<'a> Help<'a> {
));
}
}
if let Some(ref aliases) = a.aliases() {
if let Some(ref aliases) = a.aliases {
debugln!("Help::spec_vals: Found aliases...{:?}", aliases);
spec_vals.push(format!(
" [aliases: {}]",
if self.color {
aliases
.iter()
.map(|v| format!("{}", self.cizer.good(v)))
.filter(|&als| als.1) // visible
.map(|&als| format!("{}", self.cizer.good(als.0))) // name
.collect::<Vec<_>>()
.join(", ")
} else {
aliases.join(", ")
aliases.iter().filter(|&als| als.1).map(|&als| als.0).collect::<Vec<_>>().join(", ")
}
));
}
if !self.hide_pv && !a.is_set(ArgSettings::HidePossibleValues) {
if let Some(pv) = a.possible_vals() {
if let Some(pv) = a.possible_vals {
debugln!("Help::spec_vals: Found possible vals...{:?}", pv);
spec_vals.push(if self.color {
format!(
@ -565,9 +555,117 @@ impl<'a> Help<'a> {
}
}
/// Methods to write a single subcommand
impl<'w> Help<'w> {
fn write_subcommand<'a, 'b>(&mut self, app: &App<'a, 'b>) -> io::Result<()> {
debugln!("Help::write_subcommand;");
let spec_vals = self.sc_val(app)?;
self.sc_help(app, &*spec_vals)?;
Ok(())
}
fn sc_val<'a, 'b>(&mut self, app: &App<'a, 'b>) -> Result<String, io::Error> {
debugln!("Help::sc_val: app={}", app.name);
let spec_vals = self.sc_spec_vals(app);
let h = app.about.unwrap_or("");
let h_w = str_width(h) + str_width(&*spec_vals);
let nlh = self.next_line_help;
let taken = self.longest + 12;
self.force_next_line = !nlh && self.term_w >= taken
&& (taken as f32 / self.term_w as f32) > 0.40
&& h_w > (self.term_w - taken);
if !(nlh || self.force_next_line) {
write_nspaces!(
self.writer,
self.longest + 4 - (str_width(app.to_string().as_str()))
);
}
Ok(spec_vals)
}
fn sc_spec_vals(&self, a: &App) -> String {
debugln!("Help::sc_spec_vals: a={}", a.name);
let mut spec_vals = vec![];
if let Some(ref aliases) = a.aliases {
debugln!("Help::spec_vals: Found aliases...{:?}", aliases);
spec_vals.push(format!(
" [aliases: {}]",
if self.color {
aliases
.iter()
.filter(|&als| als.1) // visible
.map(|&als| format!("{}", self.cizer.good(als.0))) // name
.collect::<Vec<_>>()
.join(", ")
} else {
aliases.iter().filter(|&als| als.1).map(|&als| als.0).collect::<Vec<_>>().join(", ")
}
));
}
spec_vals.join(" ")
}
fn sc_help<'a, 'b>(&mut self, app: &App<'a, 'b>, spec_vals: &str) -> io::Result<()> {
debugln!("Help::sc_help;");
let h = if self.use_long {
app.long_about.unwrap_or_else(|| app.about.unwrap_or(""))
} else {
app.about.unwrap_or_else(|| app.long_about.unwrap_or(""))
};
let mut help = String::from(h) + spec_vals;
let nlh = self.next_line_help || self.use_long;
debugln!("Help::sc_help: Next Line...{:?}", nlh);
let spcs = if nlh || self.force_next_line {
12 // "tab" * 3
} else {
self.longest + 12
};
let too_long = spcs + str_width(h) + str_width(&*spec_vals) >= self.term_w;
// Is help on next line, if so then indent
if nlh || self.force_next_line {
write!(self.writer, "\n{}{}{}", TAB, TAB, TAB)?;
}
debug!("Help::sc_help: Too long...");
if too_long && spcs <= self.term_w || h.contains("{n}") {
sdebugln!("Yes");
debugln!("Help::sc_help: help...{}", help);
debugln!("Help::sc_help: help width...{}", str_width(&*help));
// Determine how many newlines we need to insert
let avail_chars = self.term_w - spcs;
debugln!("Help::sc_help: Usable space...{}", avail_chars);
help = wrap_help(&help.replace("{n}", "\n"), avail_chars);
} else {
sdebugln!("No");
}
if let Some(part) = help.lines().next() {
write!(self.writer, "{}", part)?;
}
for part in help.lines().skip(1) {
write!(self.writer, "\n")?;
if nlh || self.force_next_line {
write!(self.writer, "{}{}{}", TAB, TAB, TAB)?;
} else {
write_nspaces!(self.writer, self.longest + 8);
}
write!(self.writer, "{}", part)?;
}
if !help.contains('\n') && (nlh || self.force_next_line) {
write!(self.writer, "\n")?;
}
Ok(())
}
}
// Methods to write Parser help.
impl<'a> Help<'a> {
impl<'w> Help<'w> {
/// Writes help for all arguments (options, flags, args, subcommands)
/// including titles of a Parser Object to the wrapped stream.
#[cfg_attr(feature = "lints", allow(useless_let_if_seq))]
@ -575,8 +673,7 @@ impl<'a> Help<'a> {
pub fn write_all_args(&mut self, parser: &Parser) -> ClapResult<()> {
debugln!("Help::write_all_args;");
let flags = parser.has_flags();
let pos = parser
.positionals()
let pos = positionals!(parser.app)
.filter(|arg| !arg.is_set(ArgSettings::Hidden))
.count() > 0;
let opts = parser.has_opts();
@ -587,17 +684,14 @@ impl<'a> Help<'a> {
let mut first = true;
if unified_help && (flags || opts) {
let opts_flags = parser
.flags()
.map(as_arg_trait)
.chain(parser.opts().map(as_arg_trait));
let opts_flags = parser.app.args.iter().filter(|a| a.has_switch());
color!(self, "OPTIONS:\n", warning)?;
self.write_args(opts_flags)?;
first = false;
} else {
if flags {
color!(self, "FLAGS:\n", warning)?;
self.write_args(parser.flags().map(as_arg_trait))?;
self.write_args(flags!(parser.app))?;
first = false;
}
if opts {
@ -605,7 +699,7 @@ impl<'a> Help<'a> {
self.writer.write_all(b"\n\n")?;
}
color!(self, "OPTIONS:\n", warning)?;
self.write_args(parser.opts().map(as_arg_trait))?;
self.write_args(opts!(parser.app))?;
first = false;
}
}
@ -615,7 +709,7 @@ impl<'a> Help<'a> {
self.writer.write_all(b"\n\n")?;
}
color!(self, "ARGS:\n", warning)?;
self.write_args_unsorted(parser.positionals().map(as_arg_trait))?;
self.write_args_unsorted(positionals!(parser.app))?;
first = false;
}
@ -624,27 +718,25 @@ impl<'a> Help<'a> {
self.writer.write_all(b"\n\n")?;
}
color!(self, "SUBCOMMANDS:\n", warning)?;
self.write_subcommands(parser)?;
self.write_subcommands(&parser.app)?;
}
Ok(())
}
/// Writes help for subcommands of a Parser Object to the wrapped stream.
fn write_subcommands(&mut self, parser: &Parser) -> io::Result<()> {
fn write_subcommands(&mut self, app: &App) -> io::Result<()> {
debugln!("Help::write_subcommands;");
// The shortest an arg can legally be is 2 (i.e. '-x')
self.longest = 2;
let mut ord_m = VecMap::new();
for sc in parser
.subcommands
.iter()
.filter(|s| !s.p.is_set(AppSettings::Hidden))
for sc in subcommands!(app)
.filter(|s| !s.is_set(AppSettings::Hidden))
{
let btm = ord_m.entry(sc.p.meta.disp_ord).or_insert(BTreeMap::new());
self.longest = cmp::max(self.longest, str_width(sc.p.meta.name.as_str()));
let btm = ord_m.entry(sc.disp_ord).or_insert(BTreeMap::new());
self.longest = cmp::max(self.longest, str_width(sc.name.as_str()));
//self.longest = cmp::max(self.longest, sc.p.meta.name.len());
btm.insert(sc.p.meta.name.clone(), sc.clone());
btm.insert(sc.name.clone(), sc.clone());
}
let mut first = true;
@ -655,7 +747,7 @@ impl<'a> Help<'a> {
} else {
self.writer.write_all(b"\n")?;
}
self.write_arg(sc)?;
self.write_subcommand(sc)?;
}
}
Ok(())
@ -664,7 +756,7 @@ impl<'a> Help<'a> {
/// Writes version of a Parser Object to the wrapped stream.
fn write_version(&mut self, parser: &Parser) -> io::Result<()> {
debugln!("Help::write_version;");
write!(self.writer, "{}", parser.meta.version.unwrap_or(""))?;
write!(self.writer, "{}", parser.app.version.unwrap_or(""))?;
Ok(())
}
@ -673,12 +765,12 @@ impl<'a> Help<'a> {
debugln!("Help::write_bin_name;");
macro_rules! write_name {
() => {{
let mut name = parser.meta.name.clone();
let mut name = parser.app.name.clone();
name = name.replace("{n}", "\n");
color!(self, wrap_help(&name, self.term_w), good)?;
}};
}
if let Some(bn) = parser.meta.bin_name.as_ref() {
if let Some(bn) = parser.app.bin_name.as_ref() {
if bn.contains(' ') {
// Incase we're dealing with subcommands i.e. git mv is translated to git-mv
color!(self, bn.replace(" ", "-"), good)?
@ -694,7 +786,7 @@ impl<'a> Help<'a> {
/// Writes default help for a Parser Object to the wrapped stream.
pub fn write_default_help(&mut self, parser: &Parser) -> ClapResult<()> {
debugln!("Help::write_default_help;");
if let Some(h) = parser.meta.pre_help {
if let Some(h) = parser.app.pre_help {
self.write_before_after_help(h)?;
self.writer.write_all(b"\n\n")?;
}
@ -712,21 +804,21 @@ impl<'a> Help<'a> {
self.writer.write_all(b" ")?;
self.write_version(parser)?;
self.writer.write_all(b"\n")?;
if let Some(author) = parser.meta.author {
if let Some(author) = parser.app.author {
write_thing!(author)
}
if self.use_long {
if let Some(about) = parser.meta.long_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.meta.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.meta.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.meta.long_about {
} else if let Some(about) = parser.app.long_about {
debugln!("Help::write_default_help: writing long about");
write_thing!(about)
}
@ -736,7 +828,7 @@ impl<'a> Help<'a> {
self.writer,
"\n{}{}\n\n",
TAB,
usage::create_usage_no_title(parser, &[])
Usage::new(parser).create_usage_no_title(&[])
)?;
let flags = parser.has_flags();
@ -748,7 +840,7 @@ impl<'a> Help<'a> {
self.write_all_args(parser)?;
}
if let Some(h) = parser.meta.more_help {
if let Some(h) = parser.app.more_help {
if flags || opts || pos || subcmds {
self.writer.write_all(b"\n\n")?;
}
@ -858,7 +950,7 @@ fn copy_and_capture<R: Read, W: Write>(
// Methods to write Parser help using templates.
impl<'a> Help<'a> {
impl<'w> Help<'w> {
/// Write help to stream for the parser in the format defined by the template.
///
/// Tags arg given inside curly brackets:
@ -917,67 +1009,64 @@ impl<'a> Help<'a> {
write!(
self.writer,
"{}",
parser.meta.version.unwrap_or("unknown version")
parser.app.version.unwrap_or("unknown version")
)?;
}
b"author" => {
write!(
self.writer,
"{}",
parser.meta.author.unwrap_or("unknown author")
parser.app.author.unwrap_or("unknown author")
)?;
}
b"about" => {
write!(
self.writer,
"{}",
parser.meta.about.unwrap_or("unknown about")
parser.app.about.unwrap_or("unknown about")
)?;
}
b"long-about" => {
write!(
self.writer,
"{}",
parser.meta.long_about.unwrap_or("unknown about")
parser.app.long_about.unwrap_or("unknown about")
)?;
}
b"usage" => {
write!(self.writer, "{}", usage::create_usage_no_title(parser, &[]))?;
write!(self.writer, "{}", Usage::new(parser).create_usage_no_title(&[]))?;
}
b"all-args" => {
self.write_all_args(parser)?;
}
b"unified" => {
let opts_flags = parser
.flags()
.map(as_arg_trait)
.chain(parser.opts().map(as_arg_trait));
let opts_flags = parser.app.args.iter().filter(|a| a.has_switch());
self.write_args(opts_flags)?;
}
b"flags" => {
self.write_args(parser.flags().map(as_arg_trait))?;
self.write_args(flags!(parser.app))?;
}
b"options" => {
self.write_args(parser.opts().map(as_arg_trait))?;
self.write_args(opts!(parser.app))?;
}
b"positionals" => {
self.write_args(parser.positionals().map(as_arg_trait))?;
self.write_args(positionals!(parser.app))?;
}
b"subcommands" => {
self.write_subcommands(parser)?;
self.write_subcommands(parser.app)?;
}
b"after-help" => {
write!(
self.writer,
"{}",
parser.meta.more_help.unwrap_or("unknown after-help")
parser.app.more_help.unwrap_or("unknown after-help")
)?;
}
b"before-help" => {
write!(
self.writer,
"{}",
parser.meta.pre_help.unwrap_or("unknown before-help")
parser.app.pre_help.unwrap_or("unknown before-help")
)?;
}
// Unknown tag, write it back.

View file

@ -1,33 +0,0 @@
#[doc(hidden)]
#[allow(missing_debug_implementations)]
#[derive(Default, Clone)]
pub struct AppMeta<'b> {
pub name: String,
pub bin_name: Option<String>,
pub author: Option<&'b str>,
pub version: Option<&'b str>,
pub long_version: Option<&'b str>,
pub about: Option<&'b str>,
pub long_about: Option<&'b str>,
pub more_help: Option<&'b str>,
pub pre_help: Option<&'b str>,
pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
pub usage_str: Option<&'b str>,
pub usage: Option<String>,
pub help_str: Option<&'b str>,
pub disp_ord: usize,
pub term_w: Option<usize>,
pub max_w: Option<usize>,
pub template: Option<&'b str>,
}
impl<'b> AppMeta<'b> {
pub fn new() -> Self { Default::default() }
pub fn with_name(s: String) -> Self {
AppMeta {
name: s,
disp_ord: 999,
..Default::default()
}
}
}

View file

@ -1,32 +1,32 @@
mod settings;
pub mod parser;
mod meta;
mod help;
mod validator;
mod usage;
// Std
use std::env;
use std::ffi::{OsStr, OsString};
use std::ffi::OsString;
use std::fmt;
use std::io::{self, BufRead, BufWriter, Write};
use std::path::Path;
use std::path::{PathBuf, Path};
use std::process;
use std::rc::Rc;
use std::result::Result as StdResult;
use std::fs::File;
use std::iter::Peekable;
// Third Party
#[cfg(feature = "yaml")]
use yaml_rust::Yaml;
// Internal
use app::help::Help;
use app::parser::Parser;
use args::{AnyArg, Arg, ArgGroup, ArgMatcher, ArgMatches, ArgSettings};
use app::help::Help;
use args::{DispOrder, Arg, ArgGroup, ArgMatcher, ArgMatches};
use args::settings::ArgSettings;
use errors::Result as ClapResult;
pub use self::settings::AppSettings;
use completions::Shell;
use map::{self, VecMap};
pub use self::settings::{AppFlags, AppSettings};
use completions::{ComplGen, Shell};
use fmt::ColorWhen;
/// 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
@ -56,12 +56,37 @@ use map::{self, VecMap};
/// // Your program logic starts here...
/// ```
/// [`App::get_matches`]: ./struct.App.html#method.get_matches
#[allow(missing_debug_implementations)]
#[derive(Default, Debug, Clone)]
pub struct App<'a, 'b>
where
'a: 'b,
{
#[doc(hidden)] pub p: Parser<'a, 'b>,
pub name: String,
pub bin_name: Option<String>,
pub author: Option<&'b str>,
pub version: Option<&'b str>,
pub long_version: Option<&'b str>,
pub about: Option<&'b str>,
pub long_about: Option<&'b str>,
pub more_help: Option<&'b str>,
pub pre_help: Option<&'b str>,
pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
pub usage_str: Option<&'b str>,
pub usage: Option<String>,
pub help_str: Option<&'b str>,
pub disp_ord: usize,
pub term_w: Option<usize>,
pub max_w: Option<usize>,
pub template: Option<&'b str>,
settings: AppFlags,
pub g_settings: AppFlags,
pub args: Vec<Arg<'a, 'b>>,
pub subcommands: Vec<App<'a, 'b>>,
pub groups: Vec<ArgGroup<'a>>,
help_short: Option<char>,
version_short: Option<char>,
pub help_message: Option<&'a str>,
pub version_message: Option<&'a str>,
}
@ -79,15 +104,16 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
pub fn new<S: Into<String>>(n: S) -> Self {
App {
p: Parser::with_name(n.into()),
name: n.into(),
..Default::default()
}
}
/// Get the name of the app
pub fn get_name(&self) -> &str { &self.p.meta.name }
pub fn get_name(&self) -> &str { &self.name }
/// Get the name of the binary
pub fn get_bin_name(&self) -> Option<&str> { self.p.meta.bin_name.as_ref().map(|s| s.as_str()) }
pub fn get_bin_name(&self) -> Option<&str> { self.bin_name.as_ref().map(|s| s.as_str()) }
/// Creates a new instance of an application requiring a name, but uses the [`crate_authors!`]
/// and [`crate_version!`] macros to fill in the [`App::author`] and [`App::version`] fields.
@ -105,12 +131,12 @@ impl<'a, 'b> App<'a, 'b> {
/// [`App::version`]: ./struct.App.html#method.author
#[deprecated(since="2.14.1", note="Can never work; use explicit App::author() and App::version() calls instead")]
pub fn with_defaults<S: Into<String>>(n: S) -> Self {
let mut a = App {
p: Parser::with_name(n.into()),
};
a.p.meta.author = Some("Kevin K. <kbknapp@gmail.com>");
a.p.meta.version = Some("2.19.2");
a
App {
name: n.into(),
author: Some("Kevin K. <kbknapp@gmail.com>"),
version: Some("2.19.2"),
..Default::default()
}
}
/// Creates a new instance of [`App`] from a .yml (YAML) file. A full example of supported YAML
@ -176,7 +202,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`crate_authors!`]: ./macro.crate_authors!.html
/// [`examples/`]: https://github.com/kbknapp/clap-rs/tree/master/examples
pub fn author<S: Into<&'b str>>(mut self, author: S) -> Self {
self.p.meta.author = Some(author.into());
self.author = Some(author.into());
self
}
@ -199,7 +225,7 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`SubCommand`]: ./struct.SubCommand.html
pub fn bin_name<S: Into<String>>(mut self, name: S) -> Self {
self.p.meta.bin_name = Some(name.into());
self.bin_name = Some(name.into());
self
}
@ -222,7 +248,7 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`App::long_about`]: ./struct.App.html#method.long_about
pub fn about<S: Into<&'b str>>(mut self, about: S) -> Self {
self.p.meta.about = Some(about.into());
self.about = Some(about.into());
self
}
@ -248,7 +274,7 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`App::about`]: ./struct.App.html#method.about
pub fn long_about<S: Into<&'b str>>(mut self, about: S) -> Self {
self.p.meta.long_about = Some(about.into());
self.long_about = Some(about.into());
self
}
@ -275,7 +301,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`App::from_yaml`]: ./struct.App.html#method.from_yaml
/// [`crate_name!`]: ./macro.crate_name.html
pub fn name<S: Into<String>>(mut self, name: S) -> Self {
self.p.meta.name = name.into();
self.name = name.into();
self
}
@ -292,7 +318,7 @@ impl<'a, 'b> App<'a, 'b> {
/// # ;
/// ```
pub fn after_help<S: Into<&'b str>>(mut self, help: S) -> Self {
self.p.meta.more_help = Some(help.into());
self.more_help = Some(help.into());
self
}
@ -309,7 +335,7 @@ impl<'a, 'b> App<'a, 'b> {
/// # ;
/// ```
pub fn before_help<S: Into<&'b str>>(mut self, help: S) -> Self {
self.p.meta.pre_help = Some(help.into());
self.pre_help = Some(help.into());
self
}
@ -335,7 +361,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`examples/`]: https://github.com/kbknapp/clap-rs/tree/master/examples
/// [`App::long_version`]: ./struct.App.html#method.long_version
pub fn version<S: Into<&'b str>>(mut self, ver: S) -> Self {
self.p.meta.version = Some(ver.into());
self.version = Some(ver.into());
self
}
@ -366,7 +392,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`examples/`]: https://github.com/kbknapp/clap-rs/tree/master/examples
/// [`App::version`]: ./struct.App.html#method.version
pub fn long_version<S: Into<&'b str>>(mut self, ver: S) -> Self {
self.p.meta.long_version = Some(ver.into());
self.long_version = Some(ver.into());
self
}
@ -395,7 +421,7 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`ArgMatches::usage`]: ./struct.ArgMatches.html#method.usage
pub fn usage<S: Into<&'b str>>(mut self, usage: S) -> Self {
self.p.meta.usage_str = Some(usage.into());
self.usage_str = Some(usage.into());
self
}
@ -434,7 +460,7 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`Arg::help`]: ./struct.Arg.html#method.help
pub fn help<S: Into<&'b str>>(mut self, help: S) -> Self {
self.p.meta.help_str = Some(help.into());
self.help_str = Some(help.into());
self
}
@ -460,7 +486,11 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`short`]: ./struct.Arg.html#method.short
pub fn help_short<S: AsRef<str> + 'b>(mut self, s: S) -> Self {
self.p.help_short(s.as_ref());
let c = s.as_ref().trim_left_matches(|c| c == '-')
.chars()
.nth(0)
.unwrap_or('h');
self.help_short = Some(c);
self
}
@ -486,7 +516,11 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`short`]: ./struct.Arg.html#method.short
pub fn version_short<S: AsRef<str>>(mut self, s: S) -> Self {
self.p.version_short(s.as_ref());
let c = s.as_ref().trim_left_matches(|c| c == '-')
.chars()
.nth(0)
.unwrap_or('V');
self.version_short = Some(c);
self
}
@ -506,7 +540,7 @@ impl<'a, 'b> App<'a, 'b> {
/// # ;
/// ```
pub fn help_message<S: Into<&'a str>>(mut self, s: S) -> Self {
self.p.help_message = Some(s.into());
self.help_message = Some(s.into());
self
}
@ -524,7 +558,7 @@ impl<'a, 'b> App<'a, 'b> {
/// # ;
/// ```
pub fn version_message<S: Into<&'a str>>(mut self, s: S) -> Self {
self.p.version_message = Some(s.into());
self.version_message = Some(s.into());
self
}
@ -567,7 +601,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`App::before_help`]: ./struct.App.html#method.before_help
/// [`AppSettings::UnifiedHelpMessage`]: ./enum.AppSettings.html#variant.UnifiedHelpMessage
pub fn template<S: Into<&'b str>>(mut self, s: S) -> Self {
self.p.meta.template = Some(s.into());
self.template = Some(s.into());
self
}
@ -587,7 +621,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`SubCommand`]: ./struct.SubCommand.html
/// [`AppSettings`]: ./enum.AppSettings.html
pub fn setting(mut self, setting: AppSettings) -> Self {
self.p.set(setting);
self.settings.set(setting);
self
}
@ -608,7 +642,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`AppSettings`]: ./enum.AppSettings.html
pub fn settings(mut self, settings: &[AppSettings]) -> Self {
for s in settings {
self.p.set(*s);
self.settings.set(*s);
}
self
}
@ -630,8 +664,8 @@ impl<'a, 'b> App<'a, 'b> {
/// [`SubCommand`]: ./struct.SubCommand.html
/// [`AppSettings`]: ./enum.AppSettings.html
pub fn global_setting(mut self, setting: AppSettings) -> Self {
self.p.set(setting);
self.p.g_settings.set(setting);
self.settings.set(setting);
self.g_settings.set(setting);
self
}
@ -654,8 +688,8 @@ impl<'a, 'b> App<'a, 'b> {
/// [`AppSettings`]: ./enum.AppSettings.html
pub fn global_settings(mut self, settings: &[AppSettings]) -> Self {
for s in settings {
self.p.set(*s);
self.p.g_settings.set(*s)
self.settings.set(*s);
self.g_settings.set(*s)
}
self
}
@ -675,7 +709,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`SubCommand`]: ./struct.SubCommand.html
/// [`AppSettings`]: ./enum.AppSettings.html
pub fn unset_setting(mut self, setting: AppSettings) -> Self {
self.p.unset(setting);
self.settings.unset(setting);
self
}
@ -696,7 +730,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`AppSettings`]: ./enum.AppSettings.html
pub fn unset_settings(mut self, settings: &[AppSettings]) -> Self {
for s in settings {
self.p.unset(*s);
self.settings.unset(*s);
}
self
}
@ -727,7 +761,7 @@ impl<'a, 'b> App<'a, 'b> {
/// # ;
/// ```
pub fn set_term_width(mut self, width: usize) -> Self {
self.p.meta.term_w = Some(width);
self.term_w = Some(width);
self
}
@ -755,7 +789,7 @@ impl<'a, 'b> App<'a, 'b> {
/// # ;
/// ```
pub fn max_term_width(mut self, w: usize) -> Self {
self.p.meta.max_w = Some(w);
self.max_w = Some(w);
self
}
@ -781,7 +815,7 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [argument]: ./struct.Arg.html
pub fn arg<A: Into<Arg<'a, 'b>>>(mut self, a: A) -> Self {
self.p.add_arg(a.into());
self.args.push(a.into());
self
}
@ -801,7 +835,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [arguments]: ./struct.Arg.html
pub fn args(mut self, args: &[Arg<'a, 'b>]) -> Self {
for arg in args {
self.p.add_arg_ref(arg);
self.args.push(arg.clone());
}
self
}
@ -824,7 +858,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`Arg`]: ./struct.Arg.html
/// [`Arg::from_usage`]: ./struct.Arg.html#method.from_usage
pub fn arg_from_usage(mut self, usage: &'a str) -> Self {
self.p.add_arg(Arg::from_usage(usage));
self.args.push(Arg::from_usage(usage));
self
}
@ -856,7 +890,7 @@ impl<'a, 'b> App<'a, 'b> {
if l.is_empty() {
continue;
}
self.p.add_arg(Arg::from_usage(l));
self.args.push(Arg::from_usage(l));
}
self
}
@ -878,10 +912,10 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`SubCommand`]: ./struct.SubCommand.html
pub fn alias<S: Into<&'b str>>(mut self, name: S) -> Self {
if let Some(ref mut als) = self.p.meta.aliases {
if let Some(ref mut als) = self.aliases {
als.push((name.into(), false));
} else {
self.p.meta.aliases = Some(vec![(name.into(), false)]);
self.aliases = Some(vec![(name.into(), false)]);
}
self
}
@ -907,12 +941,12 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`SubCommand`]: ./struct.SubCommand.html
pub fn aliases(mut self, names: &[&'b str]) -> Self {
if let Some(ref mut als) = self.p.meta.aliases {
if let Some(ref mut als) = self.aliases {
for n in names {
als.push((n, false));
}
} else {
self.p.meta.aliases = Some(names.iter().map(|n| (*n, false)).collect::<Vec<_>>());
self.aliases = Some(names.iter().map(|n| (*n, false)).collect::<Vec<_>>());
}
self
}
@ -933,10 +967,10 @@ impl<'a, 'b> App<'a, 'b> {
/// [`SubCommand`]: ./struct.SubCommand.html
/// [`App::alias`]: ./struct.App.html#method.alias
pub fn visible_alias<S: Into<&'b str>>(mut self, name: S) -> Self {
if let Some(ref mut als) = self.p.meta.aliases {
if let Some(ref mut als) = self.aliases {
als.push((name.into(), true));
} else {
self.p.meta.aliases = Some(vec![(name.into(), true)]);
self.aliases = Some(vec![(name.into(), true)]);
}
self
}
@ -957,12 +991,12 @@ impl<'a, 'b> App<'a, 'b> {
/// [`SubCommand`]: ./struct.SubCommand.html
/// [`App::aliases`]: ./struct.App.html#method.aliases
pub fn visible_aliases(mut self, names: &[&'b str]) -> Self {
if let Some(ref mut als) = self.p.meta.aliases {
if let Some(ref mut als) = self.aliases {
for n in names {
als.push((n, true));
}
} else {
self.p.meta.aliases = Some(names.iter().map(|n| (*n, true)).collect::<Vec<_>>());
self.aliases = Some(names.iter().map(|n| (*n, true)).collect::<Vec<_>>());
}
self
}
@ -1002,7 +1036,7 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html
pub fn group(mut self, group: ArgGroup<'a>) -> Self {
self.p.add_group(group);
self.groups.push(group);
self
}
@ -1056,7 +1090,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`SubCommand`]: ./struct.SubCommand.html
/// [`App`]: ./struct.App.html
pub fn subcommand(mut self, subcmd: App<'a, 'b>) -> Self {
self.p.add_subcommand(subcmd);
self.subcommands.push(subcmd);
self
}
@ -1081,7 +1115,7 @@ impl<'a, 'b> App<'a, 'b> {
I: IntoIterator<Item = App<'a, 'b>>,
{
for subcmd in subcmds {
self.p.add_subcommand(subcmd);
self.subcommands.push(subcmd);
}
self
}
@ -1134,7 +1168,7 @@ impl<'a, 'b> App<'a, 'b> {
/// ```
/// [`SubCommand`]: ./struct.SubCommand.html
pub fn display_order(mut self, ord: usize) -> Self {
self.p.meta.disp_ord = ord;
self.disp_ord = ord;
self
}
@ -1158,11 +1192,8 @@ impl<'a, 'b> App<'a, 'b> {
pub fn print_help(&mut self) -> ClapResult<()> {
// If there are global arguments, or settings we need to propgate them down to subcommands
// before parsing incase we run into a subcommand
self.p.propagate_globals();
self.p.propagate_settings();
self.p.derive_display_order();
self._build();
self.p.create_help_and_version();
let out = io::stdout();
let mut buf_w = BufWriter::new(out.lock());
self.write_help(&mut buf_w)
@ -1188,11 +1219,8 @@ impl<'a, 'b> App<'a, 'b> {
pub fn print_long_help(&mut self) -> ClapResult<()> {
// If there are global arguments, or settings we need to propgate them down to subcommands
// before parsing incase we run into a subcommand
self.p.propagate_globals();
self.p.propagate_settings();
self.p.derive_display_order();
self._build();
self.p.create_help_and_version();
let out = io::stdout();
let mut buf_w = BufWriter::new(out.lock());
self.write_long_help(&mut buf_w)
@ -1252,12 +1280,10 @@ impl<'a, 'b> App<'a, 'b> {
/// [`-h` (short)]: ./struct.Arg.html#method.help
/// [`--help` (long)]: ./struct.Arg.html#method.long_help
pub fn write_long_help<W: Write>(&mut self, w: &mut W) -> ClapResult<()> {
self.p.propagate_globals();
self.p.propagate_settings();
self.p.derive_display_order();
self.p.create_help_and_version();
self._build();
Help::write_app_help(w, self, true)
let p = Parser::new(self);
Help::write_parser_help(w, &p, true)
}
/// Writes the version message to the user to a [`io::Write`] object as if the user ran `-V`.
@ -1278,7 +1304,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`-V` (short)]: ./struct.App.html#method.version
/// [`--version` (long)]: ./struct.App.html#method.long_version
pub fn write_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
self.p.write_version(w, false).map_err(From::from)
self._write_version(w, false).map_err(From::from)
}
/// Writes the version message to the user to a [`io::Write`] object
@ -1299,7 +1325,7 @@ impl<'a, 'b> App<'a, 'b> {
/// [`-V` (short)]: ./struct.App.html#method.version
/// [`--version` (long)]: ./struct.App.html#method.long_version
pub fn write_long_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
self.p.write_version(w, true).map_err(From::from)
self._write_version(w, true).map_err(From::from)
}
/// Generate a completions file for a specified shell at compile time.
@ -1391,8 +1417,22 @@ impl<'a, 'b> App<'a, 'b> {
for_shell: Shell,
out_dir: T,
) {
self.p.meta.bin_name = Some(bin_name.into());
self.p.gen_completions(for_shell, out_dir.into());
use std::error::Error;
let out_dir = PathBuf::from(out_dir.into());
let name = &*self.bin_name.as_ref().unwrap().clone();
let file_name = match for_shell {
Shell::Bash => format!("{}.bash", name),
Shell::Fish => format!("{}.fish", name),
Shell::Zsh => format!("_{}", name),
Shell::PowerShell => format!("_{}.ps1", name),
};
let mut file = match File::create(out_dir.join(file_name)) {
Err(why) => panic!("couldn't create completion file: {}", why.description()),
Ok(file) => file,
};
self.gen_completions_to(bin_name.into(), for_shell, &mut file)
}
@ -1434,8 +1474,14 @@ impl<'a, 'b> App<'a, 'b> {
for_shell: Shell,
buf: &mut W,
) {
self.p.meta.bin_name = Some(bin_name.into());
self.p.gen_completions_to(for_shell, buf);
self.bin_name = Some(bin_name.into());
if !self.is_set(AppSettings::Propagated) {
self.propagate();
self.build_bin_names();
self.set(AppSettings::Propagated);
}
ComplGen::new(self).generate(for_shell, buf)
}
/// Starts the parsing process, upon a failed parse an error will be displayed to the user and
@ -1514,7 +1560,7 @@ impl<'a, 'b> App<'a, 'b> {
// Otherwise, write to stderr and exit
if e.use_stderr() {
wlnerr!("{}", e.message);
if self.p.is_set(AppSettings::WaitOnError) {
if self.settings.is_set(AppSettings::WaitOnError) {
wlnerr!("\nPress [ENTER] / [RETURN] to continue...");
let mut s = String::new();
let i = io::stdin();
@ -1596,17 +1642,6 @@ impl<'a, 'b> App<'a, 'b> {
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
// If there are global arguments, or settings we need to propgate them down to subcommands
// before parsing incase we run into a subcommand
if !self.p.is_set(AppSettings::Propagated) {
self.p.propagate_globals();
self.p.propagate_settings();
self.p.derive_display_order();
self.p.set(AppSettings::Propagated);
}
let mut matcher = ArgMatcher::new();
let mut it = itr.into_iter();
// Get the name of the program (argument 1 of env::args()) and determine the
// actual file
@ -1615,30 +1650,350 @@ impl<'a, 'b> App<'a, 'b> {
// will have two arguments, './target/release/my_prog', '-a' but we don't want
// to display
// the full path when displaying help messages and such
if !self.p.is_set(AppSettings::NoBinaryName) {
if !self.settings.is_set(AppSettings::NoBinaryName) {
if let Some(name) = it.next() {
let bn_os = name.into();
let p = Path::new(&*bn_os);
if let Some(f) = p.file_name() {
if let Some(s) = f.to_os_string().to_str() {
if self.p.meta.bin_name.is_none() {
self.p.meta.bin_name = Some(s.to_owned());
if self.bin_name.is_none() {
self.bin_name = Some(s.to_owned());
}
}
}
}
}
self._do_parse(&mut it.peekable())
}
}
// Internally used only
#[doc(hidden)]
impl<'a, 'b> App<'a, 'b> {
#[doc(hidden)]
fn _do_parse<I, T>(&mut self, it: &mut Peekable<I>) -> ClapResult<ArgMatches<'a>>
where
I: Iterator<Item = T>,
T: Into<OsString> + Clone,
{
let mut matcher = ArgMatcher::new();
// If there are global arguments, or settings we need to propgate them down to subcommands
// before parsing incase we run into a subcommand
if !self.settings.is_set(AppSettings::Propagated) {
self._build();
}
let mut parser = Parser::new(self);
// do the real parsing
if let Err(e) = self.p.get_matches_with(&mut matcher, &mut it.peekable()) {
if let Err(e) = parser.get_matches_with(&mut matcher, it) {
return Err(e);
}
let global_arg_vec: Vec<&str> = (&self).p.global_args.iter().map(|ga| ga.b.name).collect();
let global_arg_vec: Vec<&str> = (&self).args.iter().filter(|a| a.is_set(ArgSettings::Global)).map(|ga| ga.name).collect();
matcher.propagate_globals(&global_arg_vec);
Ok(matcher.into())
}
fn _build(&mut self) {
self.create_help_and_version();
self.propagate();
self.derive_display_order();
for a in &mut self.args {
self.fill_in_arg_groups(a);
self.implied_settings(a);
a._build();
}
}
fn implied_settings(&mut self, a: &Arg<'a, 'b>) {
if a.is_set(ArgSettings::Last) {
// if an arg has `Last` set, we need to imply DontCollapseArgsInUsage so that args
// in the usage string don't get confused or left out.
self.set(AppSettings::DontCollapseArgsInUsage);
self.set(AppSettings::ContainsLast);
}
if let Some(l) = a.long {
if l == "version" {
self.unset(AppSettings::NeedsLongVersion);
} else if l == "help" {
self.unset(AppSettings::NeedsLongHelp);
}
}
}
// @TODO @v3-alpha @perf: should only propagate globals to subcmd we find, or for help
pub fn propagate(&mut self) {
debugln!(
"Parser::propagate: self={}, g_settings={:#?}",
self.name,
self.g_settings
);
for sc in &mut self.subcommands {
// We have to create a new scope in order to tell rustc the borrow of `sc` is
// done and to recursively call this method
debugln!(
"Parser::propagate: sc={}, settings={:#?}, g_settings={:#?}",
sc.name,
sc.settings,
sc.g_settings
);
// We have to create a new scope in order to tell rustc the borrow of `sc` is
// done and to recursively call this method
{
let vsc = self.settings.is_set(AppSettings::VersionlessSubcommands);
let gv = self.settings.is_set(AppSettings::GlobalVersion);
if vsc {
sc.set(AppSettings::DisableVersion);
}
if gv && sc.version.is_none() && self.version.is_some() {
sc.set(AppSettings::GlobalVersion);
sc.version = Some(self.version.unwrap());
}
sc.settings = sc.settings | self.g_settings;
sc.g_settings = sc.g_settings | self.g_settings;
sc.term_w = self.term_w;
sc.max_w = self.max_w;
}
{
for a in self.args.iter().filter(|a| a.is_set(ArgSettings::Global)) {
sc.args.push(a.clone());
}
}
sc.create_help_and_version();
sc.propagate();
}
}
pub fn create_help_and_version(&mut self) {
debugln!("App::create_help_and_version;");
// name is "hclap_help" because flags are sorted by name
if !self.contains_long("help") {
debugln!("App::create_help_and_version: Building --help");
if self.help_short.is_none() && !self.contains_short('h') {
self.help_short = Some('h');
}
let arg = Arg {
name: "hclap_help",
help: self.help_message.or(Some("Prints help information")),
short: self.help_short,
long: Some("help"),
..Default::default()
};
self.args.push(arg);
}
if !self.is_set(AppSettings::DisableVersion) && !self.contains_long("version") {
debugln!("App::create_help_and_version: Building --version");
if self.version_short.is_none() && !self.contains_short('V') {
self.version_short = Some('V');
}
// name is "vclap_version" because flags are sorted by name
let arg = Arg {
name: "vclap_version",
help: self.version_message.or(Some("Prints version information")),
short: self.version_short,
long: Some("version"),
..Default::default()
};
self.args.push(arg);
}
if self.has_subcommands() && !self.is_set(AppSettings::DisableHelpSubcommand)
&& subcommands!(self).any(|s| s.name == "help")
{
debugln!("App::create_help_and_version: Building help");
self.subcommands.push(
App::new("help")
.about("Prints this message or the help of the given subcommand(s)"),
);
}
}
#[cfg_attr(feature = "lints", allow(needless_borrow))]
pub fn derive_display_order(&mut self) {
if self.is_set(AppSettings::DeriveDisplayOrder) {
let unified = self.is_set(AppSettings::UnifiedHelpMessage);
for (i, o) in opts_mut!(self)
.enumerate()
.filter(|&(_, ref o)| o.disp_ord == 999)
{
o.disp_ord = if unified { o.unified_ord } else { i };
}
for (i, f) in flags_mut!(self)
.enumerate()
.filter(|&(_, ref f)| f.disp_ord == 999)
{
f.disp_ord = if unified { f.unified_ord } else { i };
}
for (i, sc) in &mut subcommands_mut!(self)
.enumerate()
.filter(|&(_, ref sc)| sc.disp_ord == 999)
{
sc.disp_ord = i;
}
}
for sc in subcommands_mut!(self) {
sc.derive_display_order();
}
}
fn fill_in_arg_groups(&mut self, a: &Arg<'a, 'b>) {
if let Some(ref grps) = a.groups {
for g in grps {
let mut found = false;
if let Some(ref mut ag) = groups_mut!(self).find(|grp| &grp.name == g) {
ag.args.push(a.name);
found = true;
}
if !found {
let mut ag = ArgGroup::with_name(g);
ag.args.push(a.name);
self.groups.push(ag);
}
}
}
}
fn build_bin_names(&mut self) {
debugln!("Parser::build_bin_names;");
for sc in subcommands_mut!(self) {
debug!("Parser::build_bin_names:iter: bin_name set...");
if sc.bin_name.is_none() {
sdebugln!("No");
let bin_name = format!(
"{}{}{}",
self
.bin_name
.as_ref()
.unwrap_or(&self.name.clone()),
if self.bin_name.is_some() {
" "
} else {
""
},
&*sc.name
);
debugln!(
"Parser::build_bin_names:iter: Setting bin_name of {} to {}",
self.name,
bin_name
);
sc.bin_name = Some(bin_name);
} else {
sdebugln!("yes ({:?})", sc.bin_name);
}
debugln!(
"Parser::build_bin_names:iter: Calling build_bin_names from...{}",
sc.name
);
sc.build_bin_names();
}
}
pub fn _write_version<W: Write>(&self, w: &mut W, use_long: bool) -> io::Result<()> {
let ver = if use_long {
self
.long_version
.unwrap_or_else(|| self.version.unwrap_or(""))
} else {
self
.version
.unwrap_or_else(|| self.long_version.unwrap_or(""))
};
if let Some(bn) = self.bin_name.as_ref() {
if bn.contains(' ') {
// Incase we're dealing with subcommands i.e. git mv is translated to git-mv
write!(w, "{} {}", bn.replace(" ", "-"), ver)
} else {
write!(w, "{} {}", &self.name[..], ver)
}
} else {
write!(w, "{} {}", &self.name[..], ver)
}
}
// Should we color the output? None=determined by output location, true=yes, false=no
#[doc(hidden)]
pub fn color(&self) -> ColorWhen {
debugln!("App::color;");
debug!("App::color: Color setting...");
if self.is_set(AppSettings::ColorNever) {
sdebugln!("Never");
ColorWhen::Never
} else if self.is_set(AppSettings::ColorAlways) {
sdebugln!("Always");
ColorWhen::Always
} else {
sdebugln!("Auto");
ColorWhen::Auto
}
}
}
// Internal Query Methods
#[doc(hidden)]
impl<'a, 'b> App<'a, 'b> {
fn contains_long(&self, l: &str) -> bool { longs!(self).any(|al| al == l) }
fn contains_short(&self, s: char) -> bool { shorts!(self).any(|arg_s| arg_s == s) }
pub fn is_set(&self, s: AppSettings) -> bool { self.settings.is_set(s) || self.g_settings.is_set(s)}
pub fn set(&mut self, s: AppSettings) { self.settings.set(s) }
pub fn set_global(&mut self, s: AppSettings) { self.g_settings.set(s) }
pub fn unset_global(&mut self, s: AppSettings) { self.g_settings.unset(s) }
pub fn unset(&mut self, s: AppSettings) { self.settings.unset(s) }
pub fn has_subcommands(&self) -> bool {
!self.subcommands.is_empty()
}
pub fn has_args(&self) -> bool {
!self.args.is_empty()
}
pub fn has_opts(&self) -> bool {
opts!(self).count() > 0
}
pub fn has_flags(&self) -> bool {
flags!(self).count() > 0
}
pub fn has_positionals(&self) -> bool {
positionals!(self).count() > 0
}
pub fn has_visible_opts(&self) -> bool {
opts!(self).any(|o| !o.is_set(ArgSettings::Hidden))
}
pub fn has_visible_flags(&self) -> bool {
flags!(self).any(|o| !o.is_set(ArgSettings::Hidden))
}
pub fn has_visible_positionals(&self) -> bool {
positionals!(self).any(|o| !o.is_set(ArgSettings::Hidden))
}
pub fn has_visible_subcommands(&self) -> bool {
subcommands!(self)
.filter(|sc| sc.name != "help")
.any(|sc| !sc.is_set(AppSettings::Hidden))
}
fn use_long_help(&self) -> bool {
self.long_about.is_some() || self.args.iter().any(|f| f.long_help.is_some())
|| subcommands!(self)
.any(|s| s.long_about.is_some())
}
}
#[cfg(feature = "yaml")]
@ -1782,60 +2137,11 @@ impl<'a> From<&'a Yaml> for App<'a, 'a> {
}
}
impl<'a, 'b> Clone for App<'a, 'b> {
fn clone(&self) -> Self { App { p: self.p.clone() } }
}
impl<'n, 'e> AnyArg<'n, 'e> for App<'n, 'e> {
fn name(&self) -> &'n str {
unreachable!("App struct does not support AnyArg::name, this is a bug!")
}
fn overrides(&self) -> Option<&[&'e str]> { None }
fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { None }
fn blacklist(&self) -> Option<&[&'e str]> { None }
fn required_unless(&self) -> Option<&[&'e str]> { None }
fn val_names(&self) -> Option<&VecMap<&'e str>> { None }
fn is_set(&self, _: ArgSettings) -> bool { false }
fn val_terminator(&self) -> Option<&'e str> { None }
fn set(&mut self, _: ArgSettings) {
unreachable!("App struct does not support AnyArg::set, this is a bug!")
}
fn has_switch(&self) -> bool { false }
fn max_vals(&self) -> Option<u64> { None }
fn num_vals(&self) -> Option<u64> { None }
fn possible_vals(&self) -> Option<&[&'e str]> { None }
fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> { None }
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> { None }
fn min_vals(&self) -> Option<u64> { None }
fn short(&self) -> Option<char> { None }
fn long(&self) -> Option<&'e str> { None }
fn val_delim(&self) -> Option<char> { None }
fn takes_value(&self) -> bool { true }
fn help(&self) -> Option<&'e str> { self.p.meta.about }
fn long_help(&self) -> Option<&'e str> { self.p.meta.long_about }
fn default_val(&self) -> Option<&'e OsStr> { None }
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
None
}
fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { None }
fn longest_filter(&self) -> bool { true }
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();
if vis_aliases.is_empty() {
None
} else {
Some(vis_aliases)
}
} else {
None
}
}
}
impl<'n, 'e> fmt::Display for App<'n, 'e> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.p.meta.name) }
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.name) }
}
impl<'b, 'c> DispOrder for App<'b, 'c> {
fn disp_ord(&self) -> usize { 999 }
}

File diff suppressed because it is too large Load diff

View file

@ -3,477 +3,469 @@ use std::collections::{BTreeMap, VecDeque};
// Internal
use INTERNAL_ERROR_MSG;
use args::{AnyArg, ArgMatcher, PosBuilder};
use args::{Arg, ArgMatcher};
use args::settings::ArgSettings;
use app::settings::AppSettings as AS;
use app::parser::Parser;
// Creates a usage string for display. This happens just after all arguments were parsed, but before
// any subcommands have been parsed (so as to give subcommands their own usage recursively)
pub fn create_usage_with_title(p: &Parser, used: &[&str]) -> String {
debugln!("usage::create_usage_with_title;");
let mut usage = String::with_capacity(75);
usage.push_str("USAGE:\n ");
usage.push_str(&*create_usage_no_title(p, used));
usage
}
pub struct Usage<'a, 'b, 'c,'z>(&'z Parser<'a, 'b, 'c>)
where
'a: 'b,
'b: 'c,
'c: 'z;
// Creates a usage string to be used in error message (i.e. one with currently used args)
pub fn create_error_usage<'a, 'b>(
p: &Parser<'a, 'b>,
matcher: &'b ArgMatcher<'a>,
extra: Option<&str>,
) -> String {
let mut args: Vec<_> = matcher
.arg_names()
.iter()
.filter(|n| {
if let Some(o) = find_by_name!(p, **n, opts, iter) {
!o.b.is_set(ArgSettings::Required) && !o.b.is_set(ArgSettings::Hidden)
} else if let Some(p) = find_by_name!(p, **n, positionals, values) {
!p.b.is_set(ArgSettings::Required) && p.b.is_set(ArgSettings::Hidden)
} else {
true // flags can't be required, so they're always true
}
})
.map(|&n| n)
.collect();
if let Some(r) = extra {
args.push(r);
impl<'a, 'b, 'c,'z> Usage<'a, 'b, 'c, 'z> {
pub fn new(p: &'z Parser<'a, 'b, 'c>) -> Self { Usage(p) }
// Creates a usage string for display. This happens just after all arguments were parsed, but before
// any subcommands have been parsed (so as to give subcommands their own usage recursively)
pub fn create_usage_with_title(&self, used: &[&str]) -> String {
debugln!("usage::create_usage_with_title;");
let mut usage = String::with_capacity(75);
usage.push_str("USAGE:\n ");
usage.push_str(&*self.create_usage_no_title(used));
usage
}
create_usage_with_title(p, &*args)
}
// Creates a usage string (*without title*) if one was not provided by the user manually.
pub fn create_usage_no_title(p: &Parser, used: &[&str]) -> String {
debugln!("usage::create_usage_no_title;");
if let Some(u) = p.meta.usage_str {
String::from(&*u)
} else if used.is_empty() {
create_help_usage(p, true)
} else {
create_smart_usage(p, used)
}
}
// Creates a usage string for display in help messages (i.e. not for errors)
pub fn create_help_usage(p: &Parser, incl_reqs: bool) -> String {
let mut usage = String::with_capacity(75);
let name = p.meta
.usage
.as_ref()
.unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name));
usage.push_str(&*name);
let req_string = if incl_reqs {
let mut reqs: Vec<&str> = p.required().map(|r| &**r).collect();
reqs.sort();
reqs.dedup();
get_required_usage_from(p, &reqs, None, None, false)
// Creates a usage string to be used in error message (i.e. one with currently used args)
pub fn create_error_usage(&self,
matcher: &ArgMatcher<'a>,
extra: Option<&str>,
) -> String {
let mut args: Vec<_> = matcher
.arg_names()
.iter()
.fold(String::new(), |a, s| a + &format!(" {}", s)[..])
} else {
String::new()
};
let flags = needs_flags_tag(p);
if flags && !p.is_set(AS::UnifiedHelpMessage) {
usage.push_str(" [FLAGS]");
} else if flags {
usage.push_str(" [OPTIONS]");
}
if !p.is_set(AS::UnifiedHelpMessage) && p.opts.iter().any(|o| {
!o.is_set(ArgSettings::Required) && !o.is_set(ArgSettings::Hidden)
}) {
usage.push_str(" [OPTIONS]");
.filter(|n| {
if let Some(a) = find!(self.0.app, **n) {
!a.is_set(ArgSettings::Required) && !a.is_set(ArgSettings::Hidden)
} else {
true // flags can't be required, so they're always true
}
})
.map(|&n| n)
.collect();
if let Some(r) = extra {
args.push(r);
}
self.create_usage_with_title(&*args)
}
usage.push_str(&req_string[..]);
let has_last = p.positionals.values().any(|p| p.is_set(ArgSettings::Last));
// places a '--' in the usage string if there are args and options
// supporting multiple values
if p.opts.iter().any(|o| o.is_set(ArgSettings::Multiple))
&& p.positionals
.values()
.any(|p| !p.is_set(ArgSettings::Required))
&& !(p.has_visible_subcommands() || p.is_set(AS::AllowExternalSubcommands))
&& !has_last
{
usage.push_str(" [--]");
}
let not_req_or_hidden = |p: &PosBuilder| {
(!p.is_set(ArgSettings::Required) || p.is_set(ArgSettings::Last))
&& !p.is_set(ArgSettings::Hidden)
};
if p.has_positionals() && p.positionals.values().any(not_req_or_hidden) {
if let Some(args_tag) = get_args_tag(p, incl_reqs) {
usage.push_str(&*args_tag);
// Creates a usage string (*without title*) if one was not provided by the user manually.
pub fn create_usage_no_title(&self, used: &[&str]) -> String {
debugln!("usage::create_usage_no_title;");
if let Some(u) = self.0.app.usage_str {
String::from(&*u)
} else if used.is_empty() {
self.create_help_usage(true)
} else {
usage.push_str(" [ARGS]");
}
if has_last && incl_reqs {
let pos = p.positionals
.values()
.find(|p| p.b.is_set(ArgSettings::Last))
.expect(INTERNAL_ERROR_MSG);
debugln!("usage::create_help_usage: '{}' has .last(true)", pos.name());
let req = pos.is_set(ArgSettings::Required);
if req
&& p.positionals
.values()
.any(|p| !p.is_set(ArgSettings::Required))
{
usage.push_str(" -- <");
} else if req {
usage.push_str(" [--] <");
} else {
usage.push_str(" [-- <");
}
usage.push_str(&*pos.name_no_brackets());
usage.push_str(">");
usage.push_str(pos.multiple_str());
if !req {
usage.push_str("]");
}
self.create_smart_usage(used)
}
}
// incl_reqs is only false when this function is called recursively
if p.has_visible_subcommands() && incl_reqs || p.is_set(AS::AllowExternalSubcommands) {
if p.is_set(AS::SubcommandsNegateReqs) || p.is_set(AS::ArgsNegateSubcommands) {
if !p.is_set(AS::ArgsNegateSubcommands) {
usage.push_str("\n ");
usage.push_str(&*create_help_usage(p, false));
usage.push_str(" <SUBCOMMAND>");
} else {
usage.push_str("\n ");
usage.push_str(&*name);
usage.push_str(" <SUBCOMMAND>");
}
} else if p.is_set(AS::SubcommandRequired) || p.is_set(AS::SubcommandRequiredElseHelp) {
usage.push_str(" <SUBCOMMAND>");
} else {
usage.push_str(" [SUBCOMMAND]");
}
}
usage.shrink_to_fit();
debugln!("usage::create_help_usage: usage={}", usage);
usage
}
// Creates a context aware usage string, or "smart usage" from currently used
// args, and requirements
fn create_smart_usage(p: &Parser, used: &[&str]) -> String {
debugln!("usage::smart_usage;");
let mut usage = String::with_capacity(75);
let mut hs: Vec<&str> = p.required().map(|s| &**s).collect();
hs.extend_from_slice(used);
let r_string = get_required_usage_from(p, &hs, None, None, false)
.iter()
.fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
usage.push_str(
&p.meta
// Creates a usage string for display in help messages (i.e. not for errors)
pub fn create_help_usage(&self, incl_reqs: bool) -> String {
let mut usage = String::with_capacity(75);
let name = self.0.app
.usage
.as_ref()
.unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name))[..],
);
usage.push_str(&*r_string);
if p.is_set(AS::SubcommandRequired) {
usage.push_str(" <SUBCOMMAND>");
}
usage.shrink_to_fit();
usage
}
.unwrap_or_else(|| self.0.app.bin_name.as_ref().unwrap_or(&self.0.app.name));
usage.push_str(&*name);
let req_string = if incl_reqs {
let mut reqs: Vec<&str> = self.0.required().map(|r| &**r).collect();
reqs.sort();
reqs.dedup();
self.get_required_usage_from(&reqs, None, None, false)
.iter()
.fold(String::new(), |a, s| a + &format!(" {}", s)[..])
} else {
String::new()
};
// Gets the `[ARGS]` tag for the usage string
fn get_args_tag(p: &Parser, incl_reqs: bool) -> Option<String> {
debugln!("usage::get_args_tag;");
let mut count = 0;
'outer: for pos in p.positionals
.values()
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
{
debugln!("usage::get_args_tag:iter:{}:", pos.b.name);
if let Some(g_vec) = p.groups_for_arg(pos.b.name) {
for grp_s in &g_vec {
debugln!("usage::get_args_tag:iter:{}:iter:{};", pos.b.name, grp_s);
// if it's part of a required group we don't want to count it
if p.groups.iter().any(|g| g.required && (&g.name == grp_s)) {
continue 'outer;
let flags = self.needs_flags_tag();
if flags && !self.0.is_set(AS::UnifiedHelpMessage) {
usage.push_str(" [FLAGS]");
} else if flags {
usage.push_str(" [OPTIONS]");
}
if !self.0.is_set(AS::UnifiedHelpMessage) && opts!(self.0.app).any(|o| {
!o.is_set(ArgSettings::Required) && !o.is_set(ArgSettings::Hidden)
}) {
usage.push_str(" [OPTIONS]");
}
usage.push_str(&req_string[..]);
let has_last = positionals!(self.0.app).any(|p| p.is_set(ArgSettings::Last));
// places a '--' in the usage string if there are args and options
// supporting multiple values
if opts!(self.0.app).any(|o| o.is_set(ArgSettings::Multiple))
&& positionals!(self.0.app)
.any(|p| !p.is_set(ArgSettings::Required))
&& !(self.0.app.has_visible_subcommands() || self.0.is_set(AS::AllowExternalSubcommands))
&& !has_last
{
usage.push_str(" [--]");
}
let not_req_or_hidden = |p: &Arg| {
(!p.is_set(ArgSettings::Required) || p.is_set(ArgSettings::Last))
&& !p.is_set(ArgSettings::Hidden)
};
if positionals!(self.0.app).any(not_req_or_hidden) {
if let Some(args_tag) = self.get_args_tag(incl_reqs) {
usage.push_str(&*args_tag);
} else {
usage.push_str(" [ARGS]");
}
if has_last && incl_reqs {
let pos = positionals!(self.0.app)
.find(|p| p.is_set(ArgSettings::Last))
.expect(INTERNAL_ERROR_MSG);
debugln!("usage::create_help_usage: '{}' has .last(true)", pos.name);
let req = pos.is_set(ArgSettings::Required);
if req
&& positionals!(self.0.app)
.any(|p| !p.is_set(ArgSettings::Required))
{
usage.push_str(" -- <");
} else if req {
usage.push_str(" [--] <");
} else {
usage.push_str(" [-- <");
}
usage.push_str(&*pos.name_no_brackets());
usage.push_str(">");
usage.push_str(pos.multiple_str());
if !req {
usage.push_str("]");
}
}
}
count += 1;
debugln!(
"usage::get_args_tag:iter: {} Args not required or hidden",
count
);
}
if !p.is_set(AS::DontCollapseArgsInUsage) && count > 1 {
debugln!("usage::get_args_tag:iter: More than one, returning [ARGS]");
return None; // [ARGS]
} else if count == 1 && incl_reqs {
let pos = p.positionals
.values()
.find(|pos| {
!pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Hidden)
&& !pos.is_set(ArgSettings::Last)
})
.expect(INTERNAL_ERROR_MSG);
debugln!(
"usage::get_args_tag:iter: Exactly one, returning '{}'",
pos.name()
);
return Some(format!(
" [{}]{}",
pos.name_no_brackets(),
pos.multiple_str()
));
} else if p.is_set(AS::DontCollapseArgsInUsage) && !p.positionals.is_empty() && incl_reqs {
debugln!("usage::get_args_tag:iter: Don't collapse returning all");
return Some(
p.positionals
.values()
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.map(|pos| {
format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())
})
.collect::<Vec<_>>()
.join(""),
);
} else if !incl_reqs {
debugln!("usage::get_args_tag:iter: incl_reqs=false, building secondary usage string");
let highest_req_pos = p.positionals
.iter()
.filter_map(|(idx, pos)| {
if pos.b.is_set(ArgSettings::Required) && !pos.b.is_set(ArgSettings::Last) {
Some(idx)
// incl_reqs is only false when this function is called recursively
if self.0.app.has_visible_subcommands() && incl_reqs || self.0.is_set(AS::AllowExternalSubcommands) {
if self.0.is_set(AS::SubcommandsNegateReqs) || self.0.is_set(AS::ArgsNegateSubcommands) {
if !self.0.is_set(AS::ArgsNegateSubcommands) {
usage.push_str("\n ");
usage.push_str(&*self.create_help_usage(false));
usage.push_str(" <SUBCOMMAND>");
} else {
None
usage.push_str("\n ");
usage.push_str(&*name);
usage.push_str(" <SUBCOMMAND>");
}
})
.max()
.unwrap_or_else(|| p.positionals.len());
return Some(
p.positionals
.iter()
.filter_map(|(idx, pos)| {
if idx <= highest_req_pos {
Some(pos)
} else if self.0.is_set(AS::SubcommandRequired) || self.0.is_set(AS::SubcommandRequiredElseHelp) {
usage.push_str(" <SUBCOMMAND>");
} else {
usage.push_str(" [SUBCOMMAND]");
}
}
usage.shrink_to_fit();
debugln!("usage::create_help_usage: usage={}", usage);
usage
}
// Creates a context aware usage string, or "smart usage" from currently used
// args, and requirements
fn create_smart_usage(&self, used: &[&str]) -> String {
debugln!("usage::smart_usage;");
let mut usage = String::with_capacity(75);
let mut hs: Vec<&str> = self.0.required().map(|s| &**s).collect();
hs.extend_from_slice(used);
let r_string = self.get_required_usage_from(&hs, None, None, false)
.iter()
.fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]);
usage.push_str(
&self.0.app
.usage
.as_ref()
.unwrap_or_else(|| self.0.app.bin_name.as_ref().unwrap_or(&self.0.app.name))[..],
);
usage.push_str(&*r_string);
if self.0.is_set(AS::SubcommandRequired) {
usage.push_str(" <SUBCOMMAND>");
}
usage.shrink_to_fit();
usage
}
// Gets the `[ARGS]` tag for the usage string
fn get_args_tag(&self, incl_reqs: bool) -> Option<String> {
debugln!("usage::get_args_tag;");
let mut count = 0;
'outer: for pos in positionals!(self.0.app)
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
{
debugln!("usage::get_args_tag:iter:{}:", pos.name);
if let Some(g_vec) = self.0.groups_for_arg(pos.name) {
for grp_s in &g_vec {
debugln!("usage::get_args_tag:iter:{}:iter:{};", pos.name, grp_s);
// if it's part of a required group we don't want to count it
if groups!(self.0.app).any(|g| g.required && (&g.name == grp_s)) {
continue 'outer;
}
}
}
count += 1;
debugln!(
"usage::get_args_tag:iter: {} Args not required or hidden",
count
);
}
if !self.0.is_set(AS::DontCollapseArgsInUsage) && count > 1 {
debugln!("usage::get_args_tag:iter: More than one, returning [ARGS]");
return None; // [ARGS]
} else if count == 1 && incl_reqs {
let pos = positionals!(self.0.app)
.find(|pos| {
!pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Hidden)
&& !pos.is_set(ArgSettings::Last)
})
.expect(INTERNAL_ERROR_MSG);
debugln!(
"usage::get_args_tag:iter: Exactly one, returning '{}'",
pos.name
);
return Some(format!(
" [{}]{}",
pos.name_no_brackets(),
pos.multiple_str()
));
} else if self.0.is_set(AS::DontCollapseArgsInUsage) && self.0.has_positionals() && incl_reqs {
debugln!("usage::get_args_tag:iter: Don't collapse returning all");
return Some(
positionals!(self.0.app)
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.map(|pos| {
format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())
})
.collect::<Vec<_>>()
.join(""),
);
} else if !incl_reqs {
debugln!("usage::get_args_tag:iter: incl_reqs=false, building secondary usage string");
let highest_req_pos = positionals!(self.0.app)
.filter_map(|pos| {
if pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Last) {
Some(pos.index)
} else {
None
}
})
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.map(|pos| {
format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())
})
.collect::<Vec<_>>()
.join(""),
);
.max()
.unwrap_or_else(|| Some(positionals!(self.0.app).count() as u64));
return Some(
positionals!(self.0.app)
.filter_map(|pos| {
if pos.index <= highest_req_pos {
Some(pos)
} else {
None
}
})
.filter(|pos| !pos.is_set(ArgSettings::Required))
.filter(|pos| !pos.is_set(ArgSettings::Hidden))
.filter(|pos| !pos.is_set(ArgSettings::Last))
.map(|pos| {
format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())
})
.collect::<Vec<_>>()
.join(""),
);
}
Some("".into())
}
Some("".into())
}
// Determines if we need the `[FLAGS]` tag in the usage string
fn needs_flags_tag(p: &Parser) -> bool {
debugln!("usage::needs_flags_tag;");
'outer: for f in &p.flags {
debugln!("usage::needs_flags_tag:iter: f={};", f.b.name);
if let Some(l) = f.s.long {
if l == "help" || l == "version" {
// Don't print `[FLAGS]` just for help or version
// Determines if we need the `[FLAGS]` tag in the usage string
fn needs_flags_tag(&self) -> bool {
debugln!("usage::needs_flags_tag;");
'outer: for f in flags!(self.0.app) {
debugln!("usage::needs_flags_tag:iter: f={};", f.name);
if let Some(l) = f.long {
if l == "help" || l == "version" {
// Don't print `[FLAGS]` just for help or version
continue;
}
}
if let Some(g_vec) = self.0.groups_for_arg(f.name) {
for grp_s in &g_vec {
debugln!("usage::needs_flags_tag:iter:iter: grp_s={};", grp_s);
if groups!(self.0.app).any(|g| &g.name == grp_s && g.required) {
debugln!("usage::needs_flags_tag:iter:iter: Group is required");
continue 'outer;
}
}
}
if f.is_set(ArgSettings::Hidden) {
continue;
}
debugln!("usage::needs_flags_tag:iter: [FLAGS] required");
return true;
}
if let Some(g_vec) = p.groups_for_arg(f.b.name) {
for grp_s in &g_vec {
debugln!("usage::needs_flags_tag:iter:iter: grp_s={};", grp_s);
if p.groups.iter().any(|g| &g.name == grp_s && g.required) {
debugln!("usage::needs_flags_tag:iter:iter: Group is required");
continue 'outer;
}
}
}
if f.is_set(ArgSettings::Hidden) {
continue;
}
debugln!("usage::needs_flags_tag:iter: [FLAGS] required");
return true;
debugln!("usage::needs_flags_tag: [FLAGS] not required");
false
}
debugln!("usage::needs_flags_tag: [FLAGS] not required");
false
}
// Returns the required args in usage string form by fully unrolling all groups
pub fn get_required_usage_from<'a, 'b>(
p: &Parser<'a, 'b>,
reqs: &[&'a str],
matcher: Option<&ArgMatcher<'a>>,
extra: Option<&str>,
incl_last: bool,
) -> VecDeque<String> {
debugln!(
"usage::get_required_usage_from: reqs={:?}, extra={:?}",
reqs,
extra
);
let mut desc_reqs: Vec<&str> = vec![];
desc_reqs.extend(extra);
let mut new_reqs: Vec<&str> = vec![];
macro_rules! get_requires {
(@group $a: ident, $v:ident, $p:ident) => {{
if let Some(rl) = p.groups.iter()
.filter(|g| g.requires.is_some())
.find(|g| &g.name == $a)
.map(|g| g.requires.as_ref().unwrap()) {
for r in rl {
if !$p.contains(&r) {
debugln!("usage::get_required_usage_from:iter:{}: adding group req={:?}",
$a, r);
$v.push(r);
// Returns the required args in usage string form by fully unrolling all groups
pub fn get_required_usage_from(
&self,
reqs: &[&str],
matcher: Option<&ArgMatcher<'a>>,
extra: Option<&str>,
incl_last: bool,
) -> VecDeque<String> {
debugln!(
"usage::get_required_usage_from: reqs={:?}, extra={:?}",
reqs,
extra
);
let mut desc_reqs: Vec<&str> = vec![];
desc_reqs.extend(extra);
let mut new_reqs: Vec<&str> = vec![];
macro_rules! get_requires {
(@group $a: ident, $v:ident, $p:ident) => {{
if let Some(rl) = groups!(self.0.app)
.filter(|g| g.requires.is_some())
.find(|g| &g.name == $a)
.map(|g| g.requires.as_ref().unwrap()) {
for r in rl {
if !$p.contains(&r) {
debugln!("usage::get_required_usage_from:iter:{}: adding group req={:?}",
$a, r);
$v.push(r);
}
}
}
}
}};
($a:ident, $what:ident, $how:ident, $v:ident, $p:ident) => {{
if let Some(rl) = p.$what.$how()
.filter(|a| a.b.requires.is_some())
.find(|arg| &arg.b.name == $a)
.map(|a| a.b.requires.as_ref().unwrap()) {
for &(_, r) in rl.iter() {
if !$p.contains(&r) {
debugln!("usage::get_required_usage_from:iter:{}: adding arg req={:?}",
$a, r);
$v.push(r);
}};
($a:ident, $what:ident, $how:ident, $v:ident, $p:ident) => {{
if let Some(rl) = $what!(self.0.app)
.filter(|a| a.requires.is_some())
.find(|arg| &arg.name == $a)
.map(|a| a.requires.as_ref().unwrap()) {
for &(_, r) in rl.iter() {
if !$p.contains(&r) {
debugln!("usage::get_required_usage_from:iter:{}: adding arg req={:?}",
$a, r);
$v.push(r);
}
}
}
}
}};
}
// initialize new_reqs
for a in reqs {
get_requires!(a, flags, iter, new_reqs, reqs);
get_requires!(a, opts, iter, new_reqs, reqs);
get_requires!(a, positionals, values, new_reqs, reqs);
get_requires!(@group a, new_reqs, reqs);
}
desc_reqs.extend_from_slice(&*new_reqs);
debugln!(
"usage::get_required_usage_from: after init desc_reqs={:?}",
desc_reqs
);
loop {
let mut tmp = vec![];
for a in &new_reqs {
get_requires!(a, flags, iter, tmp, desc_reqs);
get_requires!(a, opts, iter, tmp, desc_reqs);
get_requires!(a, positionals, values, tmp, desc_reqs);
get_requires!(@group a, tmp, desc_reqs);
}};
}
if tmp.is_empty() {
debugln!("usage::get_required_usage_from: no more children");
break;
// initialize new_reqs
for a in reqs {
get_requires!(a, flags, iter, new_reqs, reqs);
get_requires!(a, opts, iter, new_reqs, reqs);
get_requires!(a, positionals, values, new_reqs, reqs);
get_requires!(@group a, new_reqs, reqs);
}
desc_reqs.extend_from_slice(&*new_reqs);
debugln!(
"usage::get_required_usage_from: after init desc_reqs={:?}",
desc_reqs
);
loop {
let mut tmp = vec![];
for a in &new_reqs {
get_requires!(a, flags, iter, tmp, desc_reqs);
get_requires!(a, opts, iter, tmp, desc_reqs);
get_requires!(a, positionals, values, tmp, desc_reqs);
get_requires!(@group a, tmp, desc_reqs);
}
if tmp.is_empty() {
debugln!("usage::get_required_usage_from: no more children");
break;
} else {
debugln!("usage::get_required_usage_from: after iter tmp={:?}", tmp);
debugln!(
"usage::get_required_usage_from: after iter new_reqs={:?}",
new_reqs
);
desc_reqs.extend_from_slice(&*new_reqs);
new_reqs.clear();
new_reqs.extend_from_slice(&*tmp);
debugln!(
"usage::get_required_usage_from: after iter desc_reqs={:?}",
desc_reqs
);
}
}
desc_reqs.extend_from_slice(reqs);
desc_reqs.sort();
desc_reqs.dedup();
debugln!(
"usage::get_required_usage_from: final desc_reqs={:?}",
desc_reqs
);
let mut ret_val = VecDeque::new();
let args_in_groups = groups!(self.0.app)
.filter(|gn| desc_reqs.contains(&gn.name))
.flat_map(|g| self.0.arg_names_in_group(g.name))
.collect::<Vec<_>>();
let pmap = if let Some(m) = matcher {
desc_reqs
.iter()
.filter(|a| self.0.positionals.values().any(|p| &p == a))
.filter(|&pos| !m.contains(pos))
.filter_map(|pos| find!(self.0.app, *pos))
.filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
.filter(|pos| !args_in_groups.contains(&pos.name))
.map(|pos| (pos.index.unwrap(), pos))
.collect::<BTreeMap<u64, &Arg>>() // sort by index
} else {
debugln!("usage::get_required_usage_from: after iter tmp={:?}", tmp);
debugln!(
"usage::get_required_usage_from: after iter new_reqs={:?}",
new_reqs
);
desc_reqs.extend_from_slice(&*new_reqs);
new_reqs.clear();
new_reqs.extend_from_slice(&*tmp);
debugln!(
"usage::get_required_usage_from: after iter desc_reqs={:?}",
desc_reqs
);
desc_reqs
.iter()
.filter(|a| self.0.positionals.values().any(|p| &p == a))
.filter_map(|pos| find!(self.0.app, *pos))
.filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
.filter(|pos| !args_in_groups.contains(&pos.name))
.map(|pos| (pos.index.unwrap(), pos))
.collect::<BTreeMap<u64, &Arg>>() // sort by index
};
debugln!(
"usage::get_required_usage_from: args_in_groups={:?}",
args_in_groups
);
for &p in pmap.values() {
let s = p.to_string();
if args_in_groups.is_empty() || !args_in_groups.contains(&&*s) {
ret_val.push_back(s);
}
}
}
desc_reqs.extend_from_slice(reqs);
desc_reqs.sort();
desc_reqs.dedup();
debugln!(
"usage::get_required_usage_from: final desc_reqs={:?}",
desc_reqs
);
let mut ret_val = VecDeque::new();
let args_in_groups = p.groups
.iter()
.filter(|gn| desc_reqs.contains(&gn.name))
.flat_map(|g| p.arg_names_in_group(g.name))
.collect::<Vec<_>>();
let pmap = if let Some(m) = matcher {
desc_reqs
for a in desc_reqs
.iter()
.filter(|a| p.positionals.values().any(|p| &&p.b.name == a))
.filter(|&pos| !m.contains(pos))
.filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos))
.filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
.filter(|pos| !args_in_groups.contains(&pos.b.name))
.map(|pos| (pos.index, pos))
.collect::<BTreeMap<u64, &PosBuilder>>() // sort by index
} else {
desc_reqs
.filter(|name| !positionals!(self.0.app).any(|p| &&p.name == name))
.filter(|name| !groups!(self.0.app).any(|g| &&g.name == name))
.filter(|name| !args_in_groups.contains(name))
.filter(|name| {
!(matcher.is_some() && matcher.as_ref().unwrap().contains(name))
}) {
debugln!("usage::get_required_usage_from:iter:{}:", a);
let arg = find!(self.0.app, *a).map(|f| f.to_string()).expect(INTERNAL_ERROR_MSG);
ret_val.push_back(arg);
}
let mut g_vec: Vec<String> = vec![];
for g in desc_reqs
.iter()
.filter(|a| p.positionals.values().any(|pos| &&pos.b.name == a))
.filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos))
.filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last))
.filter(|pos| !args_in_groups.contains(&pos.b.name))
.map(|pos| (pos.index, pos))
.collect::<BTreeMap<u64, &PosBuilder>>() // sort by index
};
debugln!(
"usage::get_required_usage_from: args_in_groups={:?}",
args_in_groups
);
for &p in pmap.values() {
let s = p.to_string();
if args_in_groups.is_empty() || !args_in_groups.contains(&&*s) {
ret_val.push_back(s);
.filter(|n| groups!(self.0.app).any(|g| &&g.name == n))
{
let g_string = self.0.args_in_group(g).join("|");
let elem = format!("<{}>", &g_string[..g_string.len()]);
if !g_vec.contains(&elem) {
g_vec.push(elem);
}
}
}
for a in desc_reqs
.iter()
.filter(|name| !p.positionals.values().any(|p| &&p.b.name == name))
.filter(|name| !p.groups.iter().any(|g| &&g.name == name))
.filter(|name| !args_in_groups.contains(name))
.filter(|name| {
!(matcher.is_some() && matcher.as_ref().unwrap().contains(name))
}) {
debugln!("usage::get_required_usage_from:iter:{}:", a);
let arg = find_by_name!(p, *a, flags, iter)
.map(|f| f.to_string())
.unwrap_or_else(|| {
find_by_name!(p, *a, opts, iter)
.map(|o| o.to_string())
.expect(INTERNAL_ERROR_MSG)
});
ret_val.push_back(arg);
}
let mut g_vec: Vec<String> = vec![];
for g in desc_reqs
.iter()
.filter(|n| p.groups.iter().any(|g| &&g.name == n))
{
let g_string = p.args_in_group(g).join("|");
let elem = format!("<{}>", &g_string[..g_string.len()]);
if !g_vec.contains(&elem) {
g_vec.push(elem);
for g in g_vec {
ret_val.push_back(g);
}
}
for g in g_vec {
ret_val.push_back(g);
}
ret_val
ret_val
}
}

View file

@ -1,12 +1,11 @@
// std
use std::fmt::Display;
#[allow(unused_imports)]
use std::ascii::AsciiExt;
// Internal
use INTERNAL_ERROR_MSG;
use INVALID_UTF8;
use args::{AnyArg, ArgMatcher, MatchedArg};
use args::{ArgMatcher, MatchedArg, Arg};
use args::settings::ArgSettings;
use errors::{Error, ErrorKind};
use errors::Result as ClapResult;
@ -14,15 +13,17 @@ use osstringext::OsStrExt2;
use app::settings::AppSettings as AS;
use app::parser::{ParseResult, Parser};
use fmt::{Colorizer, ColorizerOption};
use app::usage;
use app::usage::Usage;
pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>)
pub struct Validator<'a, 'b, 'c,'z>(&'z mut Parser<'a, 'b, 'c>)
where
'a: 'b,
'b: 'z;
'b: 'c,
'c: 'z;
impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
pub fn new(p: &'z mut Parser<'a, 'b>) -> Self { Validator(p) }
impl<'a, 'b, 'c,'z> Validator<'a, 'b, 'c, 'z> {
pub fn new(p: &'z mut Parser<'a, 'b, 'c>) -> Self { Validator(p) }
pub fn validate(
&mut self,
@ -36,23 +37,19 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
self.0.add_defaults(matcher)?;
if let ParseResult::Opt(a) = needs_val_of {
debugln!("Validator::validate: needs_val_of={:?}", a);
let o = self.0
.opts
.iter()
.find(|o| o.b.name == a)
.expect(INTERNAL_ERROR_MSG);
let o = find!(self.0.app, a).expect(INTERNAL_ERROR_MSG);
self.validate_required(matcher)?;
reqs_validated = true;
let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) {
v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0)
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
};
if should_err {
return Err(Error::empty_value(
o,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
&*Usage::new(self.0).create_error_usage(matcher, None),
self.0.app.color(),
));
}
}
@ -73,21 +70,19 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
self.validate_required(matcher)?;
}
self.validate_matched_args(matcher)?;
matcher.usage(usage::create_usage_with_title(self.0, &[]));
matcher.usage(Usage::new(self.0).create_usage_with_title(&[]));
Ok(())
}
fn validate_arg_values<A>(
fn validate_arg_values(
&self,
arg: &A,
arg: &Arg,
ma: &MatchedArg,
matcher: &ArgMatcher<'a>,
) -> ClapResult<()>
where
A: AnyArg<'a, 'b> + Display,
{
debugln!("Validator::validate_arg_values: arg={:?}", arg.name());
debugln!("Validator::validate_arg_values: arg={:?}", arg.name);
for val in &ma.vals {
if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() {
debugln!(
@ -95,11 +90,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
val
);
return Err(Error::invalid_utf8(
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
&*Usage::new(self.0).create_error_usage(matcher, None),
self.0.app.color(),
));
}
if let Some(p_vals) = arg.possible_vals() {
if let Some(ref p_vals) = arg.possible_vals {
debugln!("Validator::validate_arg_values: possible_vals={:?}", p_vals);
let val_str = val.to_string_lossy();
let ok = if arg.is_set(ArgSettings::CaseInsensitive) {
@ -112,38 +107,38 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
val_str,
p_vals,
arg,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
&*Usage::new(self.0).create_error_usage(matcher, None),
self.0.app.color(),
));
}
}
if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty_()
&& matcher.contains(&*arg.name())
&& matcher.contains(&*arg.name)
{
debugln!("Validator::validate_arg_values: illegal empty val found");
return Err(Error::empty_value(
arg,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
&*Usage::new(self.0).create_error_usage(matcher, None),
self.0.app.color(),
));
}
if let Some(vtor) = arg.validator() {
if let Some(ref vtor) = arg.validator {
debug!("Validator::validate_arg_values: checking validator...");
if let Err(e) = vtor(val.to_string_lossy().into_owned()) {
sdebugln!("error");
return Err(Error::value_validation(Some(arg), e, self.0.color()));
return Err(Error::value_validation(Some(arg), e, self.0.app.color()));
} else {
sdebugln!("good");
}
}
if let Some(vtor) = arg.validator_os() {
if let Some(ref vtor) = arg.validator_os {
debug!("Validator::validate_arg_values: checking validator_os...");
if let Err(e) = vtor(val) {
sdebugln!("error");
return Err(Error::value_validation(
Some(arg),
(*e).to_string_lossy().to_string(),
self.0.color(),
self.0.app.color(),
));
} else {
sdebugln!("good");
@ -153,44 +148,35 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(())
}
fn build_err(&self, name: &str, matcher: &ArgMatcher) -> ClapResult<()> {
fn build_err(&self, name: &str, matcher: &ArgMatcher<'a>) -> ClapResult<()> {
debugln!("build_err!: name={}", name);
let mut c_with = find_from!(self.0, &name, blacklist, &matcher);
let mut c_with = find_from!(self.0.app, &name, blacklist, &matcher);
c_with = c_with.or(
self.0.find_any_arg(&name).map_or(None, |aa| aa.blacklist())
find!(self.0.app, name).map_or(None, |aa| aa.blacklist)
.map_or(None,
|bl| bl.iter().find(|arg| matcher.contains(arg)))
.map_or(None, |an| self.0.find_any_arg(an))
.map_or(None, |an| find!(self.0.app, *an))
.map_or(None, |aa| Some(format!("{}", aa)))
);
debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name);
// matcher.remove(&name);
let usg = usage::create_error_usage(self.0, matcher, None);
if let Some(f) = find_by_name!(self.0, name, flags, iter) {
let usg = Usage::new(self.0).create_error_usage(matcher, None);
if let Some(f) = find!(self.0.app, name) {
debugln!("build_err!: It was a flag...");
Err(Error::argument_conflict(f, c_with, &*usg, self.0.color()))
} else if let Some(o) = find_by_name!(self.0, name, opts, iter) {
debugln!("build_err!: It was an option...");
Err(Error::argument_conflict(o, c_with, &*usg, self.0.color()))
Err(Error::argument_conflict(f, c_with, &*usg, self.0.app.color()))
} else {
match find_by_name!(self.0, name, positionals, values) {
Some(p) => {
debugln!("build_err!: It was a positional...");
Err(Error::argument_conflict(p, c_with, &*usg, self.0.color()))
},
None => panic!(INTERNAL_ERROR_MSG)
}
panic!(INTERNAL_ERROR_MSG);
}
}
fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> {
fn validate_blacklist(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> {
debugln!("Validator::validate_blacklist;");
let mut conflicts: Vec<&str> = vec![];
for (&name, _) in matcher.iter() {
debugln!("Validator::validate_blacklist:iter:{};", name);
if let Some(grps) = self.0.groups_for_arg(name) {
for grp in &grps {
if let Some(g) = self.0.groups.iter().find(|g| &g.name == grp) {
if let Some(g) = self.0.app.groups.iter().find(|g| &g.name == grp) {
if !g.multiple {
for arg in &g.args {
if arg == &name {
@ -205,8 +191,8 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
}
}
}
if let Some(arg) = find_any_by_name!(self.0, name) {
if let Some(bl) = arg.blacklist() {
if let Some(arg) = find!(self.0.app, name) {
if let Some(bl) = arg.blacklist {
for conf in bl {
if matcher.get(conf).is_some() {
conflicts.push(conf);
@ -218,7 +204,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
let args = self.0.arg_names_in_group(name);
for arg in &args {
debugln!("Validator::validate_blacklist:iter:{}:group:iter:{};", name, arg);
if let Some(bl) = find_any_by_name!(self.0, *arg).unwrap().blacklist() {
if let Some(bl) = find!(self.0.app, *arg).unwrap().blacklist {
for conf in bl {
if matcher.get(conf).is_some() {
conflicts.push(conf);
@ -235,7 +221,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
name
);
let mut should_err = false;
if self.0.groups.iter().any(|g| &g.name == name) {
if groups!(self.0.app).any(|g| &g.name == name) {
debugln!(
"Validator::validate_blacklist:iter:{}: groups contains it...",
name
@ -277,25 +263,13 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
name,
ma.vals
);
if let Some(opt) = find_by_name!(self.0, *name, opts, iter) {
self.validate_arg_num_vals(opt, ma, matcher)?;
self.validate_arg_values(opt, ma, matcher)?;
self.validate_arg_requires(opt, ma, matcher)?;
self.validate_arg_num_occurs(opt, ma, matcher)?;
} else if let Some(flag) = find_by_name!(self.0, *name, flags, iter) {
self.validate_arg_requires(flag, ma, matcher)?;
self.validate_arg_num_occurs(flag, ma, matcher)?;
} else if let Some(pos) = find_by_name!(self.0, *name, positionals, values) {
self.validate_arg_num_vals(pos, ma, matcher)?;
self.validate_arg_num_occurs(pos, ma, matcher)?;
self.validate_arg_values(pos, ma, matcher)?;
self.validate_arg_requires(pos, ma, matcher)?;
if let Some(arg) = find!(self.0.app, *name) {
self.validate_arg_num_vals(arg, ma, matcher)?;
self.validate_arg_values(arg, ma, matcher)?;
self.validate_arg_requires(arg, ma, matcher)?;
self.validate_arg_num_occurs(arg, ma, matcher)?;
} else {
let grp = self.0
.groups
.iter()
.find(|g| &g.name == name)
.expect(INTERNAL_ERROR_MSG);
let grp = find!(self.0.app, *name, groups).expect(INTERNAL_ERROR_MSG);
if let Some(ref g_reqs) = grp.requires {
if g_reqs.iter().any(|&n| !matcher.contains(n)) {
return self.missing_required_error(matcher, None);
@ -306,38 +280,34 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(())
}
fn validate_arg_num_occurs<A>(
fn validate_arg_num_occurs(
&self,
a: &A,
a: &Arg,
ma: &MatchedArg,
matcher: &ArgMatcher,
matcher: &ArgMatcher<'a>,
) -> ClapResult<()>
where
A: AnyArg<'a, 'b> + Display,
{
debugln!("Validator::validate_arg_num_occurs: a={};", a.name());
debugln!("Validator::validate_arg_num_occurs: a={};", a.name);
if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) {
// Not the first time, and we don't allow multiples
return Err(Error::unexpected_multiple_usage(
a,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
&*Usage::new(self.0).create_error_usage(matcher, None),
self.0.app.color(),
));
}
Ok(())
}
fn validate_arg_num_vals<A>(
fn validate_arg_num_vals(
&self,
a: &A,
a: &Arg,
ma: &MatchedArg,
matcher: &ArgMatcher,
matcher: &ArgMatcher<'a>,
) -> ClapResult<()>
where
A: AnyArg<'a, 'b> + Display,
{
debugln!("Validator::validate_arg_num_vals;");
if let Some(num) = a.num_vals() {
if let Some(num) = a.num_vals {
debugln!("Validator::validate_arg_num_vals: num_vals set...{}", num);
let should_err = if a.is_set(ArgSettings::Multiple) {
((ma.vals.len() as u64) % num) != 0
@ -361,12 +331,12 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
} else {
"ere"
},
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
&*Usage::new(self.0).create_error_usage(matcher, None),
self.0.app.color(),
));
}
}
if let Some(num) = a.max_vals() {
if let Some(num) = a.max_vals {
debugln!("Validator::validate_arg_num_vals: max_vals set...{}", num);
if (ma.vals.len() as u64) > num {
debugln!("Validator::validate_arg_num_vals: Sending error TooManyValues");
@ -378,12 +348,12 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
.to_str()
.expect(INVALID_UTF8),
a,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
&*Usage::new(self.0).create_error_usage(matcher, None),
self.0.app.color(),
));
}
}
let min_vals_zero = if let Some(num) = a.min_vals() {
let min_vals_zero = if let Some(num) = a.min_vals {
debugln!("Validator::validate_arg_num_vals: min_vals set: {}", num);
if (ma.vals.len() as u64) < num && num != 0 {
debugln!("Validator::validate_arg_num_vals: Sending error TooFewValues");
@ -391,8 +361,8 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
a,
num,
ma.vals.len(),
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
&*Usage::new(self.0).create_error_usage(matcher, None),
self.0.app.color(),
));
}
num == 0
@ -401,27 +371,25 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
};
// Issue 665 (https://github.com/kbknapp/clap-rs/issues/665)
// Issue 1105 (https://github.com/kbknapp/clap-rs/issues/1105)
if a.takes_value() && !min_vals_zero && ma.vals.is_empty() {
if a.is_set(ArgSettings::TakesValue) && !min_vals_zero && ma.vals.is_empty() {
return Err(Error::empty_value(
a,
&*usage::create_error_usage(self.0, matcher, None),
self.0.color(),
&*Usage::new(self.0).create_error_usage(matcher, None),
self.0.app.color(),
));
}
Ok(())
}
fn validate_arg_requires<A>(
fn validate_arg_requires(
&self,
a: &A,
a: &Arg,
ma: &MatchedArg,
matcher: &ArgMatcher,
matcher: &ArgMatcher<'a>,
) -> ClapResult<()>
where
A: AnyArg<'a, 'b> + Display,
{
debugln!("Validator::validate_arg_requires:{};", a.name());
if let Some(a_reqs) = a.requires() {
debugln!("Validator::validate_arg_requires:{};", a.name);
if let Some(ref a_reqs) = a.requires {
for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) {
let missing_req =
|v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name);
@ -438,7 +406,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(())
}
fn validate_required(&self, matcher: &ArgMatcher) -> ClapResult<()> {
fn validate_required(&self, matcher: &ArgMatcher<'a>) -> ClapResult<()> {
debugln!(
"Validator::validate_required: required={:?};",
self.0.required
@ -449,7 +417,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
if matcher.contains(name) {
continue 'outer;
}
if let Some(a) = find_any_by_name!(self.0, *name) {
if let Some(a) = find!(self.0.app, *name) {
if self.is_missing_required_ok(a, matcher) {
continue 'outer;
}
@ -468,28 +436,25 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
Ok(())
}
fn validate_arg_conflicts(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> {
debugln!("Validator::validate_arg_conflicts: a={:?};", a.name());
a.blacklist().map(|bl| {
fn validate_arg_conflicts(&self, a: &Arg, matcher: &ArgMatcher) -> Option<bool> {
debugln!("Validator::validate_arg_conflicts: a={:?};", a.name);
a.blacklist.map(|bl| {
bl.iter().any(|conf| {
matcher.contains(conf)
|| self.0
.groups
.iter()
.find(|g| &g.name == conf)
|| find!(self.0.app, *conf, groups)
.map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg)))
})
})
}
fn validate_required_unless(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option<bool> {
debugln!("Validator::validate_required_unless: a={:?};", a.name());
fn validate_required_unless(&self, a: &Arg, matcher: &ArgMatcher) -> Option<bool> {
debugln!("Validator::validate_required_unless: a={:?};", a.name);
macro_rules! check {
($how:ident, $_self:expr, $a:ident, $m:ident) => {{
$a.required_unless().map(|ru| {
$a.r_unless.map(|ru| {
ru.iter().$how(|n| {
$m.contains(n) || {
if let Some(grp) = $_self.groups.iter().find(|g| &g.name == n) {
if let Some(grp) = find!($_self.app, *n, groups) {
grp.args.iter().any(|arg| $m.contains(arg))
} else {
false
@ -506,11 +471,11 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
}
}
fn missing_required_error(&self, matcher: &ArgMatcher, extra: Option<&str>) -> ClapResult<()> {
fn missing_required_error(&self, matcher: &ArgMatcher<'a>, extra: Option<&str>) -> ClapResult<()> {
debugln!("Validator::missing_required_error: extra={:?}", extra);
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
when: self.0.color(),
when: self.0.app.color(),
});
let mut reqs = self.0.required.iter().map(|&r| &*r).collect::<Vec<_>>();
if let Some(r) = extra {
@ -520,7 +485,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
reqs.dedup();
debugln!("Validator::missing_required_error: reqs={:#?}", reqs);
let req_args =
usage::get_required_usage_from(self.0, &reqs[..], Some(matcher), extra, true)
Usage::new(self.0).get_required_usage_from(&reqs[..], Some(matcher), extra, true)
.iter()
.fold(String::new(), |acc, s| {
acc + &format!("\n {}", c.error(s))[..]
@ -531,14 +496,14 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> {
);
Err(Error::missing_required_argument(
&*req_args,
&*usage::create_error_usage(self.0, matcher, extra),
self.0.color(),
&*Usage::new(self.0).create_error_usage(matcher, extra),
self.0.app.color(),
))
}
#[inline]
fn is_missing_required_ok(&self, a: &AnyArg, matcher: &ArgMatcher) -> bool {
debugln!("Validator::is_missing_required_ok: a={}", a.name());
fn is_missing_required_ok(&self, a: &Arg, matcher: &ArgMatcher) -> bool {
debugln!("Validator::is_missing_required_ok: a={}", a.name);
self.validate_arg_conflicts(a, matcher).unwrap_or(false)
|| self.validate_required_unless(a, matcher).unwrap_or(false)
}

View file

@ -1,74 +0,0 @@
// Std
use std::rc::Rc;
use std::fmt as std_fmt;
use std::ffi::{OsStr, OsString};
// Internal
use args::settings::ArgSettings;
use map::{self, VecMap};
use INTERNAL_ERROR_MSG;
#[doc(hidden)]
pub trait AnyArg<'n, 'e>: std_fmt::Display {
fn name(&self) -> &'n str;
fn overrides(&self) -> Option<&[&'e str]>;
fn aliases(&self) -> Option<Vec<&'e str>>;
fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]>;
fn blacklist(&self) -> Option<&[&'e str]>;
fn required_unless(&self) -> Option<&[&'e str]>;
fn is_set(&self, ArgSettings) -> bool;
fn set(&mut self, ArgSettings);
fn has_switch(&self) -> bool;
fn max_vals(&self) -> Option<u64>;
fn min_vals(&self) -> Option<u64>;
fn num_vals(&self) -> Option<u64>;
fn possible_vals(&self) -> Option<&[&'e str]>;
fn validator(&self) -> Option<&Rc<Fn(String) -> Result<(), String>>>;
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> Result<(), OsString>>>;
fn short(&self) -> Option<char>;
fn long(&self) -> Option<&'e str>;
fn val_delim(&self) -> Option<char>;
fn takes_value(&self) -> bool;
fn val_names(&self) -> Option<&VecMap<&'e str>>;
fn help(&self) -> Option<&'e str>;
fn long_help(&self) -> Option<&'e str>;
fn default_val(&self) -> Option<&'e OsStr>;
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>>;
fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)>;
fn longest_filter(&self) -> bool;
fn val_terminator(&self) -> Option<&'e str>;
}
pub trait DispOrder {
fn disp_ord(&self) -> usize;
}
impl<'n, 'e, 'z, T: ?Sized> AnyArg<'n, 'e> for &'z T where T: AnyArg<'n, 'e> + 'z {
fn name(&self) -> &'n str { (*self).name() }
fn overrides(&self) -> Option<&[&'e str]> { (*self).overrides() }
fn aliases(&self) -> Option<Vec<&'e str>> { (*self).aliases() }
fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { (*self).requires() }
fn blacklist(&self) -> Option<&[&'e str]> { (*self).blacklist() }
fn required_unless(&self) -> Option<&[&'e str]> { (*self).required_unless() }
fn is_set(&self, a: ArgSettings) -> bool { (*self).is_set(a) }
fn set(&mut self, _: ArgSettings) { panic!(INTERNAL_ERROR_MSG) }
fn has_switch(&self) -> bool { (*self).has_switch() }
fn max_vals(&self) -> Option<u64> { (*self).max_vals() }
fn min_vals(&self) -> Option<u64> { (*self).min_vals() }
fn num_vals(&self) -> Option<u64> { (*self).num_vals() }
fn possible_vals(&self) -> Option<&[&'e str]> { (*self).possible_vals() }
fn validator(&self) -> Option<&Rc<Fn(String) -> Result<(), String>>> { (*self).validator() }
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> Result<(), OsString>>> { (*self).validator_os() }
fn short(&self) -> Option<char> { (*self).short() }
fn long(&self) -> Option<&'e str> { (*self).long() }
fn val_delim(&self) -> Option<char> { (*self).val_delim() }
fn takes_value(&self) -> bool { (*self).takes_value() }
fn val_names(&self) -> Option<&VecMap<&'e str>> { (*self).val_names() }
fn help(&self) -> Option<&'e str> { (*self).help() }
fn long_help(&self) -> Option<&'e str> { (*self).long_help() }
fn default_val(&self) -> Option<&'e OsStr> { (*self).default_val() }
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> { (*self).default_vals_ifs() }
fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { (*self).env() }
fn longest_filter(&self) -> bool { (*self).longest_filter() }
fn val_terminator(&self) -> Option<&'e str> { (*self).val_terminator() }
}

View file

@ -1,20 +1,24 @@
#[cfg(feature = "yaml")]
use std::collections::BTreeMap;
use std::rc::Rc;
use std::borrow::Cow;
use std::fmt::{self, Display, Formatter};
use std::ffi::{OsStr, OsString};
#[cfg(target_os = "windows")]
use osstringext::OsStrExt3;
#[cfg(not(target_os = "windows"))]
use std::os::unix::ffi::OsStrExt;
use std::env;
use std::cmp::{Ord, Ordering};
#[cfg(feature = "yaml")]
use yaml_rust::Yaml;
use map::VecMap;
use usage_parser::UsageParser;
use args::settings::ArgSettings;
use args::arg_builder::{Base, Switched, Valued};
use args::settings::{ArgSettings, ArgFlags};
use args::DispOrder;
use INTERNAL_ERROR_MSG;
/// The abstract representation of a command line argument. Used to set all the options and
/// relationships that define a valid argument for the program.
@ -44,9 +48,32 @@ pub struct Arg<'a, 'b>
where
'a: 'b,
{
#[doc(hidden)] pub b: Base<'a, 'b>,
#[doc(hidden)] pub s: Switched<'b>,
#[doc(hidden)] pub v: Valued<'a, 'b>,
pub name: &'a str,
pub help: Option<&'b str>,
pub long_help: Option<&'b str>,
pub blacklist: Option<Vec<&'a str>>,
pub settings: ArgFlags,
pub r_unless: Option<Vec<&'a str>>,
pub overrides: Option<Vec<&'a str>>,
pub groups: Option<Vec<&'a str>>,
pub requires: Option<Vec<(Option<&'b str>, &'a str)>>,
pub short: Option<char>,
pub long: Option<&'b str>,
pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
pub disp_ord: usize,
pub unified_ord: usize,
pub possible_vals: Option<Vec<&'b str>>,
pub val_names: Option<VecMap<&'b str>>,
pub num_vals: Option<u64>,
pub max_vals: Option<u64>,
pub min_vals: Option<u64>,
pub validator: Option<Rc<Fn(String) -> Result<(), String>>>,
pub validator_os: Option<Rc<Fn(&OsStr) -> Result<(), OsString>>>,
pub val_delim: Option<char>,
pub default_val: Option<&'b OsStr>,
pub default_vals_ifs: Option<VecMap<(&'a str, Option<&'b OsStr>, &'b OsStr)>>,
pub env: Option<(&'a OsStr, Option<OsString>)>,
pub terminator: Option<&'b str>,
#[doc(hidden)] pub index: Option<u64>,
#[doc(hidden)] pub r_ifs: Option<Vec<(&'a str, &'b str)>>,
}
@ -71,7 +98,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg`]: ./struct.Arg.html
pub fn with_name(n: &'a str) -> Self {
Arg {
b: Base::new(n),
name: n,
..Default::default()
}
}
@ -328,7 +355,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`short`]: ./struct.Arg.html#method.short
pub fn short<S: AsRef<str>>(mut self, s: S) -> Self {
self.s.short = s.as_ref().trim_left_matches(|c| c == '-').chars().nth(0);
self.short = s.as_ref().trim_left_matches(|c| c == '-').chars().nth(0);
self
}
@ -368,7 +395,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert!(m.is_present("cfg"));
/// ```
pub fn long(mut self, l: &'b str) -> Self {
self.s.long = Some(l.trim_left_matches(|c| c == '-'));
self.long = Some(l.trim_left_matches(|c| c == '-'));
self
}
@ -394,10 +421,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg`]: ./struct.Arg.html
pub fn alias<S: Into<&'b str>>(mut self, name: S) -> Self {
if let Some(ref mut als) = self.s.aliases {
if let Some(ref mut als) = self.aliases {
als.push((name.into(), false));
} else {
self.s.aliases = Some(vec![(name.into(), false)]);
self.aliases = Some(vec![(name.into(), false)]);
}
self
}
@ -424,12 +451,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg`]: ./struct.Arg.html
pub fn aliases(mut self, names: &[&'b str]) -> Self {
if let Some(ref mut als) = self.s.aliases {
if let Some(ref mut als) = self.aliases {
for n in names {
als.push((n, false));
}
} else {
self.s.aliases = Some(names.iter().map(|n| (*n, false)).collect::<Vec<_>>());
self.aliases = Some(names.iter().map(|n| (*n, false)).collect::<Vec<_>>());
}
self
}
@ -455,10 +482,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg`]: ./struct.Arg.html
/// [`App::alias`]: ./struct.Arg.html#method.alias
pub fn visible_alias<S: Into<&'b str>>(mut self, name: S) -> Self {
if let Some(ref mut als) = self.s.aliases {
if let Some(ref mut als) = self.aliases {
als.push((name.into(), true));
} else {
self.s.aliases = Some(vec![(name.into(), true)]);
self.aliases = Some(vec![(name.into(), true)]);
}
self
}
@ -482,12 +509,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg`]: ./struct.Arg.html
/// [`App::aliases`]: ./struct.Arg.html#method.aliases
pub fn visible_aliases(mut self, names: &[&'b str]) -> Self {
if let Some(ref mut als) = self.s.aliases {
if let Some(ref mut als) = self.aliases {
for n in names {
als.push((n, true));
}
} else {
self.s.aliases = Some(names.iter().map(|n| (*n, true)).collect::<Vec<_>>());
self.aliases = Some(names.iter().map(|n| (*n, true)).collect::<Vec<_>>());
}
self
}
@ -543,7 +570,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg::long_help`]: ./struct.Arg.html#method.long_help
pub fn help(mut self, h: &'b str) -> Self {
self.b.help = Some(h);
self.help = Some(h);
self
}
@ -614,7 +641,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg::help`]: ./struct.Arg.html#method.help
pub fn long_help(mut self, h: &'b str) -> Self {
self.b.long_help = Some(h);
self.long_help = Some(h);
self
}
@ -940,10 +967,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::required`]: ./struct.Arg.html#method.required
/// [`Arg::required_unless(name)`]: ./struct.Arg.html#method.required_unless
pub fn required_unless(mut self, name: &'a str) -> Self {
if let Some(ref mut vec) = self.b.r_unless {
if let Some(ref mut vec) = self.r_unless {
vec.push(name);
} else {
self.b.r_unless = Some(vec![name]);
self.r_unless = Some(vec![name]);
}
self.required(true)
}
@ -1012,12 +1039,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::required_unless_one`]: ./struct.Arg.html#method.required_unless_one
/// [`Arg::required_unless_all(names)`]: ./struct.Arg.html#method.required_unless_all
pub fn required_unless_all(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.b.r_unless {
if let Some(ref mut vec) = self.r_unless {
for s in names {
vec.push(s);
}
} else {
self.b.r_unless = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
self.r_unless = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
}
self.setb(ArgSettings::RequiredUnlessAll);
self.required(true)
@ -1088,12 +1115,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::required_unless_one(names)`]: ./struct.Arg.html#method.required_unless_one
/// [`Arg::required_unless_all`]: ./struct.Arg.html#method.required_unless_all
pub fn required_unless_one(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.b.r_unless {
if let Some(ref mut vec) = self.r_unless {
for s in names {
vec.push(s);
}
} else {
self.b.r_unless = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
self.r_unless = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
}
self.required(true)
}
@ -1136,10 +1163,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert_eq!(res.unwrap_err().kind, ErrorKind::ArgumentConflict);
/// ```
pub fn conflicts_with(mut self, name: &'a str) -> Self {
if let Some(ref mut vec) = self.b.blacklist {
if let Some(ref mut vec) = self.blacklist {
vec.push(name);
} else {
self.b.blacklist = Some(vec![name]);
self.blacklist = Some(vec![name]);
}
self
}
@ -1186,12 +1213,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with
pub fn conflicts_with_all(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.b.blacklist {
if let Some(ref mut vec) = self.blacklist {
for s in names {
vec.push(s);
}
} else {
self.b.blacklist = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
self.blacklist = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
}
self
}
@ -1223,10 +1250,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert!(!m.is_present("flag"));
/// ```
pub fn overrides_with(mut self, name: &'a str) -> Self {
if let Some(ref mut vec) = self.b.overrides {
if let Some(ref mut vec) = self.overrides {
vec.push(name.as_ref());
} else {
self.b.overrides = Some(vec![name.as_ref()]);
self.overrides = Some(vec![name.as_ref()]);
}
self
}
@ -1259,12 +1286,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert!(!m.is_present("flag"));
/// ```
pub fn overrides_with_all(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.b.overrides {
if let Some(ref mut vec) = self.overrides {
for s in names {
vec.push(s);
}
} else {
self.b.overrides = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
self.overrides = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
}
self
}
@ -1325,12 +1352,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires(mut self, name: &'a str) -> Self {
if let Some(ref mut vec) = self.b.requires {
if let Some(ref mut vec) = self.requires {
vec.push((None, name));
} else {
let mut vec = vec![];
vec.push((None, name));
self.b.requires = Some(vec);
self.requires = Some(vec);
}
self
}
@ -1395,10 +1422,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires_if(mut self, val: &'b str, arg: &'a str) -> Self {
if let Some(ref mut vec) = self.b.requires {
if let Some(ref mut vec) = self.requires {
vec.push((Some(val), arg));
} else {
self.b.requires = Some(vec![(Some(val), arg)]);
self.requires = Some(vec![(Some(val), arg)]);
}
self
}
@ -1455,7 +1482,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [Conflicting]: ./struct.Arg.html#method.conflicts_with
/// [override]: ./struct.Arg.html#method.overrides_with
pub fn requires_ifs(mut self, ifs: &[(&'b str, &'a str)]) -> Self {
if let Some(ref mut vec) = self.b.requires {
if let Some(ref mut vec) = self.requires {
for &(val, arg) in ifs {
vec.push((Some(val), arg));
}
@ -1464,7 +1491,7 @@ impl<'a, 'b> Arg<'a, 'b> {
for &(val, arg) in ifs {
vec.push((Some(val), arg));
}
self.b.requires = Some(vec);
self.requires = Some(vec);
}
self
}
@ -1699,7 +1726,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [override]: ./struct.Arg.html#method.overrides_with
/// [`Arg::requires_all(&[arg, arg2])`]: ./struct.Arg.html#method.requires_all
pub fn requires_all(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.b.requires {
if let Some(ref mut vec) = self.requires {
for s in names {
vec.push((None, s));
}
@ -1708,7 +1735,7 @@ impl<'a, 'b> Arg<'a, 'b> {
for s in names {
vec.push((None, *s));
}
self.b.requires = Some(vec);
self.requires = Some(vec);
}
self
}
@ -2127,7 +2154,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`max_values`]: ./struct.Arg.html#method.max_values
pub fn value_terminator(mut self, term: &'b str) -> Self {
self.setb(ArgSettings::TakesValue);
self.v.terminator = Some(term);
self.terminator = Some(term);
self
}
@ -2319,12 +2346,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [options]: ./struct.Arg.html#method.takes_value
/// [positional arguments]: ./struct.Arg.html#method.index
pub fn possible_values(mut self, names: &[&'b str]) -> Self {
if let Some(ref mut vec) = self.v.possible_vals {
if let Some(ref mut vec) = self.possible_vals {
for s in names {
vec.push(s);
}
} else {
self.v.possible_vals = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
self.possible_vals = Some(names.iter().map(|s| *s).collect::<Vec<_>>());
}
self
}
@ -2383,10 +2410,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [options]: ./struct.Arg.html#method.takes_value
/// [positional arguments]: ./struct.Arg.html#method.index
pub fn possible_value(mut self, name: &'b str) -> Self {
if let Some(ref mut vec) = self.v.possible_vals {
if let Some(ref mut vec) = self.possible_vals {
vec.push(name);
} else {
self.v.possible_vals = Some(vec![name]);
self.possible_vals = Some(vec![name]);
}
self
}
@ -2475,10 +2502,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html
pub fn group(mut self, name: &'a str) -> Self {
if let Some(ref mut vec) = self.b.groups {
if let Some(ref mut vec) = self.groups {
vec.push(name);
} else {
self.b.groups = Some(vec![name]);
self.groups = Some(vec![name]);
}
self
}
@ -2515,12 +2542,12 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html
pub fn groups(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.b.groups {
if let Some(ref mut vec) = self.groups {
for s in names {
vec.push(s);
}
} else {
self.b.groups = Some(names.into_iter().map(|s| *s).collect::<Vec<_>>());
self.groups = Some(names.into_iter().map(|s| *s).collect::<Vec<_>>());
}
self
}
@ -2563,7 +2590,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn number_of_values(mut self, qty: u64) -> Self {
self.setb(ArgSettings::TakesValue);
self.v.num_vals = Some(qty);
self.num_vals = Some(qty);
self
}
@ -2607,7 +2634,7 @@ impl<'a, 'b> Arg<'a, 'b> {
where
F: Fn(String) -> Result<(), String> + 'static,
{
self.v.validator = Some(Rc::new(f));
self.validator = Some(Rc::new(f));
self
}
@ -2645,7 +2672,7 @@ impl<'a, 'b> Arg<'a, 'b> {
where
F: Fn(&OsStr) -> Result<(), OsString> + 'static,
{
self.v.validator_os = Some(Rc::new(f));
self.validator_os = Some(Rc::new(f));
self
}
@ -2707,7 +2734,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn max_values(mut self, qty: u64) -> Self {
self.setb(ArgSettings::TakesValue);
self.v.max_vals = Some(qty);
self.max_vals = Some(qty);
self
}
@ -2769,7 +2796,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
pub fn min_values(mut self, qty: u64) -> Self {
self.v.min_vals = Some(qty);
self.min_vals = Some(qty);
self.set(ArgSettings::TakesValue)
}
@ -2821,14 +2848,14 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::value_delimiter`]: ./struct.Arg.html#method.value_delimiter
pub fn use_delimiter(mut self, d: bool) -> Self {
if d {
if self.v.val_delim.is_none() {
self.v.val_delim = Some(',');
if self.val_delim.is_none() {
self.val_delim = Some(',');
}
self.setb(ArgSettings::TakesValue);
self.setb(ArgSettings::UseValueDelimiter);
self.unset(ArgSettings::ValueDelimiterNotSet)
} else {
self.v.val_delim = None;
self.val_delim = None;
self.unsetb(ArgSettings::UseValueDelimiter);
self.unset(ArgSettings::ValueDelimiterNotSet)
}
@ -2946,7 +2973,7 @@ impl<'a, 'b> Arg<'a, 'b> {
self.unsetb(ArgSettings::ValueDelimiterNotSet);
self.setb(ArgSettings::TakesValue);
self.setb(ArgSettings::UseValueDelimiter);
self.v.val_delim = Some(
self.val_delim = Some(
d.chars()
.nth(0)
.expect("Failed to get value_delimiter from arg"),
@ -3019,7 +3046,7 @@ impl<'a, 'b> Arg<'a, 'b> {
self.unsetb(ArgSettings::ValueDelimiterNotSet);
self.setb(ArgSettings::UseValueDelimiter);
}
if let Some(ref mut vals) = self.v.val_names {
if let Some(ref mut vals) = self.val_names {
let mut l = vals.len();
for s in names {
vals.insert(l, s);
@ -3030,7 +3057,7 @@ impl<'a, 'b> Arg<'a, 'b> {
for (i, n) in names.iter().enumerate() {
vm.insert(i, *n);
}
self.v.val_names = Some(vm);
self.val_names = Some(vm);
}
self
}
@ -3083,13 +3110,13 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
pub fn value_name(mut self, name: &'b str) -> Self {
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vals) = self.v.val_names {
if let Some(ref mut vals) = self.val_names {
let l = vals.len();
vals.insert(l, name);
} else {
let mut vm = VecMap::new();
vm.insert(0, name);
self.v.val_names = Some(vm);
self.val_names = Some(vm);
}
self
}
@ -3167,7 +3194,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html
pub fn default_value_os(mut self, val: &'a OsStr) -> Self {
self.setb(ArgSettings::TakesValue);
self.v.default_val = Some(val);
self.default_val = Some(val);
self
}
@ -3286,13 +3313,13 @@ impl<'a, 'b> Arg<'a, 'b> {
default: &'b OsStr,
) -> Self {
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vm) = self.v.default_vals_ifs {
if let Some(ref mut vm) = self.default_vals_ifs {
let l = vm.len();
vm.insert(l, (arg, val, default));
} else {
let mut vm = VecMap::new();
vm.insert(0, (arg, val, default));
self.v.default_vals_ifs = Some(vm);
self.default_vals_ifs = Some(vm);
}
self
}
@ -3511,12 +3538,12 @@ impl<'a, 'b> Arg<'a, 'b> {
pub fn env_os(mut self, name: &'a OsStr) -> Self {
self.setb(ArgSettings::TakesValue);
self.v.env = Some((name, env::var_os(name)));
self.env = Some((name, env::var_os(name)));
self
}
/// @TODO @p2 @docs @release: write docs
pub fn hide_env_values(self, hide: bool) -> Self {
pub fn hide_env_values(self, hide: bool) -> Self {
if hide {
self.set(ArgSettings::HideEnvValues)
} else {
@ -3634,13 +3661,13 @@ impl<'a, 'b> Arg<'a, 'b> {
/// [positional arguments]: ./struct.Arg.html#method.index
/// [index]: ./struct.Arg.html#method.index
pub fn display_order(mut self, ord: usize) -> Self {
self.s.disp_ord = ord;
self.disp_ord = ord;
self
}
/// Checks if one of the [`ArgSettings`] settings is set for the argument
/// [`ArgSettings`]: ./enum.ArgSettings.html
pub fn is_set(&self, s: ArgSettings) -> bool { self.b.is_set(s) }
pub fn is_set(&self, s: ArgSettings) -> bool { self.is_set(s) }
/// Sets one of the [`ArgSettings`] settings for the argument
/// [`ArgSettings`]: ./enum.ArgSettings.html
@ -3657,24 +3684,378 @@ impl<'a, 'b> Arg<'a, 'b> {
}
#[doc(hidden)]
pub fn setb(&mut self, s: ArgSettings) { self.b.set(s); }
pub fn _build(&mut self) {
if self.index.is_some() || (self.short.is_none() && self.long.is_none()) {
if self.max_vals.is_some() || self.min_vals.is_some()
|| (self.num_vals.is_some() && self.num_vals.unwrap() > 1)
{
self.setb(ArgSettings::Multiple);
}
} else if self.is_set(ArgSettings::TakesValue) {
if let Some(ref vec) = self.val_names {
if vec.len() > 1 {
self.num_vals = Some(vec.len() as u64);
}
}
}
}
#[doc(hidden)]
pub fn unsetb(&mut self, s: ArgSettings) { self.b.unset(s); }
}
pub fn setb(&mut self, s: ArgSettings) { self.set(s); }
impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for Arg<'a, 'b> {
fn from(a: &'z Arg<'a, 'b>) -> Self {
Arg {
b: a.b.clone(),
v: a.v.clone(),
s: a.s.clone(),
index: a.index,
r_ifs: a.r_ifs.clone(),
#[doc(hidden)]
pub fn unsetb(&mut self, s: ArgSettings) { self.unset(s); }
#[doc(hidden)]
pub fn has_switch(&self) -> bool { self.short.is_some() || self.long.is_some() }
#[doc(hidden)]
pub fn longest_filter(&self) -> bool {
self.is_set(ArgSettings::TakesValue) || self.index.is_some() || self.long.is_some()
}
// Used for positionals when printing
#[doc(hidden)]
pub fn multiple_str(&self) -> &str {
let mult_vals = self.val_names
.as_ref()
.map_or(true, |names| names.len() < 2);
if self.is_set(ArgSettings::Multiple) && mult_vals {
"..."
} else {
""
}
}
// Used for positionals when printing
#[doc(hidden)]
pub fn name_no_brackets(&self) -> Cow<str> {
debugln!("PosBuilder::name_no_brackets;");
let mut delim = String::new();
delim.push(if self.is_set(ArgSettings::RequireDelimiter) {
self.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
});
if let Some(ref names) = self.val_names {
debugln!("PosBuilder:name_no_brackets: val_names={:#?}", names);
if names.len() > 1 {
Cow::Owned(
names
.values()
.map(|n| format!("<{}>", n))
.collect::<Vec<_>>()
.join(&*delim),
)
} else {
Cow::Borrowed(names.values().next().expect(INTERNAL_ERROR_MSG))
}
} else {
debugln!("PosBuilder:name_no_brackets: just name");
Cow::Borrowed(self.name)
}
}
}
impl<'n, 'e> PartialEq for Arg<'n, 'e> {
fn eq(&self, other: &Arg<'n, 'e>) -> bool { self.b == other.b }
impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for Arg<'a, 'b> {
fn from(a: &'z Arg<'a, 'b>) -> Self {
a.clone()
}
}
impl<'n, 'e> PartialEq for Arg<'n, 'e> {
fn eq(&self, other: &Arg<'n, 'e>) -> bool { self.name == other.name }
}
impl<'n, 'e> Display for Arg<'n, 'e> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.short.is_none() && self.long.is_none() {
// Positional
let mut delim = String::new();
delim.push(if self.is_set(ArgSettings::RequireDelimiter) {
self.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
});
if let Some(ref names) = self.val_names {
write!(
f,
"{}",
names
.values()
.map(|n| format!("<{}>", n))
.collect::<Vec<_>>()
.join(&*delim)
)?;
} else {
write!(f, "<{}>", self.name)?;
}
if self.settings.is_set(ArgSettings::Multiple)
&& (self.val_names.is_none() || self.val_names.as_ref().unwrap().len() == 1)
{
write!(f, "...")?;
}
return Ok(());
}
let sep = if self.is_set(ArgSettings::RequireEquals) {
"="
} else {
" "
};
// Write the name such --long or -l
if let Some(l) = self.long {
write!(f, "--{}{}", l, sep)?;
} else {
write!(f, "-{}{}", self.short.unwrap(), sep)?;
}
let delim = if self.is_set(ArgSettings::RequireDelimiter) {
self.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
};
// Write the values such as <name1> <name2>
if let Some(ref vec) = self.val_names {
let mut it = vec.iter().peekable();
while let Some((_, val)) = it.next() {
write!(f, "<{}>", val)?;
if it.peek().is_some() {
write!(f, "{}", delim)?;
}
}
let num = vec.len();
if self.is_set(ArgSettings::Multiple) && num == 1 {
write!(f, "...")?;
}
} else if let Some(num) = self.num_vals {
let mut it = (0..num).peekable();
while let Some(_) = it.next() {
write!(f, "<{}>", self.name)?;
if it.peek().is_some() {
write!(f, "{}", delim)?;
}
}
if self.is_set(ArgSettings::Multiple) && num == 1 {
write!(f, "...")?;
}
} else {
write!(
f,
"<{}>{}",
self.name,
if self.is_set(ArgSettings::Multiple) {
"..."
} else {
""
}
)?;
}
Ok(())
}
}
impl<'n, 'e> PartialOrd for Arg<'n , 'e> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'n, 'e> Ord for Arg<'n, 'e> {
fn cmp(&self, other: &Arg) -> Ordering {
self.name.cmp(&other.name)
}
}
impl<'n, 'e> Eq for Arg<'n, 'e> { }
impl<'n, 'e> fmt::Debug for Arg<'n, 'e> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "Arg {{ name: {:?}, help: {:?}, long_help: {:?}, conflicts_with: {:?}, \
settings: {:?}, required_unless: {:?}, overrides_with: {:?}, groups: {:?}, \
requires: {:?}, requires_ifs: {:?}, short: {:?}, index: {:?}, long: {:?}, \
aliases: {:?}, possible_values: {:?}, value_names: {:?}, number_of_values: {:?}, \
max_values: {:?}, min_values: {:?}, value_delimiter: {:?}, default_value_ifs: {:?}, \
value_terminator: {:?}, display_order: {:?}, env: {:?}, unified_ord: {:?}, \
default_value: {:?}, validator: {}, validator_os: {} \
}}",
self.name,
self.help,
self.long_help,
self.blacklist,
self.settings,
self.r_unless,
self.overrides,
self.groups,
self.requires,
self.r_ifs,
self.short,
self.index,
self.long,
self.aliases,
self.possible_vals,
self.val_names,
self.num_vals,
self.max_vals,
self.min_vals,
self.val_delim,
self.default_vals_ifs,
self.terminator,
self.disp_ord,
self.env,
self.unified_ord,
self.default_val,
self.validator.as_ref().map_or("None", |_| "Some(Fn)"),
self.validator_os.as_ref().map_or("None", |_| "Some(Fn)")
)
}
}
impl<'n, 'e> DispOrder for Arg<'n, 'e> {
fn disp_ord(&self) -> usize { self.disp_ord }
}
// Flags
#[cfg(test)]
mod test {
use map::VecMap;
use args::settings::ArgSettings;
use super::Arg;
#[test]
fn flag_display() {
let mut f = Arg::with_name("flg");
f.settings.set(ArgSettings::Multiple);
f.long = Some("flag");
assert_eq!(&*format!("{}", f), "--flag");
let mut f2 = Arg::new("flg");
f2.short = Some('f');
assert_eq!(&*format!("{}", f2), "-f");
}
#[test]
fn flag_display_single_alias() {
let mut f = Arg::with_name("flg");
f.long = Some("flag");
f.aliases = Some(vec![("als", true)]);
assert_eq!(&*format!("{}", f), "--flag");
}
#[test]
fn flag_display_multiple_aliases() {
let mut f = Arg::with_name("flg");
f.short = Some('f');
f.aliases = Some(vec![
("alias_not_visible", false),
("f2", true),
("f3", true),
("f4", true),
]);
assert_eq!(&*format!("{}", f), "-f");
}
// Options
#[test]
fn option_display1() {
let mut o = Arg::with_name("opt");
o.long = Some("option");
o.settings.set(ArgSettings::Multiple);
assert_eq!(&*format!("{}", o), "--option <opt>...");
}
#[test]
fn option_display2() {
let mut v_names = VecMap::new();
v_names.insert(0, "file");
v_names.insert(1, "name");
let mut o2 = Arg::new("opt");
o2.short = Some('o');
o2.val_names = Some(v_names);
assert_eq!(&*format!("{}", o2), "-o <file> <name>");
}
#[test]
fn option_display3() {
let mut v_names = VecMap::new();
v_names.insert(0, "file");
v_names.insert(1, "name");
let mut o2 = Arg::new("opt");
o2.short = Some('o');
o2.val_names = Some(v_names);
o2.settings.set(ArgSettings::Multiple);
assert_eq!(&*format!("{}", o2), "-o <file> <name>");
}
#[test]
fn option_display_single_alias() {
let mut o = Arg::with_name("opt");
o.long = Some("option");
o.aliases = Some(vec![("als", true)]);
assert_eq!(&*format!("{}", o), "--option <opt>");
}
#[test]
fn option_display_multiple_aliases() {
let mut o = Arg::with_name("opt");
o.long = Some("option");
o.aliases = Some(vec![
("als_not_visible", false),
("als2", true),
("als3", true),
("als4", true),
]);
assert_eq!(&*format!("{}", o), "--option <opt>");
}
// Positionals
#[test]
fn positiona_display_mult() {
let mut p = Arg::with_name("pos", 1);
p.settings.set(ArgSettings::Multiple);
assert_eq!(&*format!("{}", p), "<pos>...");
}
#[test]
fn positional_display_required() {
let mut p2 = Arg::with_name("pos", 1);
p2.settings.set(ArgSettings::Required);
assert_eq!(&*format!("{}", p2), "<pos>");
}
#[test]
fn positional_display_val_names() {
let mut p2 = Arg::with_name("pos", 1);
let mut vm = VecMap::new();
vm.insert(0, "file1");
vm.insert(1, "file2");
p2.val_names = Some(vm);
assert_eq!(&*format!("{}", p2), "<file1> <file2>");
}
#[test]
fn positional_display_val_names_req() {
let mut p2 = Arg::with_name("pos", 1);
p2.settings.set(ArgSettings::Required);
let mut vm = VecMap::new();
vm.insert(0, "file1");
vm.insert(1, "file2");
p2.val_names = Some(vm);
assert_eq!(&*format!("{}", p2), "<file1> <file2>");
}
}

View file

@ -1,38 +0,0 @@
use args::{Arg, ArgFlags, ArgSettings};
#[derive(Debug, Clone, Default)]
pub struct Base<'a, 'b>
where
'a: 'b,
{
pub name: &'a str,
pub help: Option<&'b str>,
pub long_help: Option<&'b str>,
pub blacklist: Option<Vec<&'a str>>,
pub settings: ArgFlags,
pub r_unless: Option<Vec<&'a str>>,
pub overrides: Option<Vec<&'a str>>,
pub groups: Option<Vec<&'a str>>,
pub requires: Option<Vec<(Option<&'b str>, &'a str)>>,
}
impl<'n, 'e> Base<'n, 'e> {
pub fn new(name: &'n str) -> Self {
Base {
name: name,
..Default::default()
}
}
pub fn set(&mut self, s: ArgSettings) { self.settings.set(s); }
pub fn unset(&mut self, s: ArgSettings) { self.settings.unset(s); }
pub fn is_set(&self, s: ArgSettings) -> bool { self.settings.is_set(s) }
}
impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Base<'n, 'e> {
fn from(a: &'z Arg<'n, 'e>) -> Self { a.b.clone() }
}
impl<'n, 'e> PartialEq for Base<'n, 'e> {
fn eq(&self, other: &Base<'n, 'e>) -> bool { self.name == other.name }
}

View file

@ -1,159 +0,0 @@
// Std
use std::convert::From;
use std::fmt::{Display, Formatter, Result};
use std::rc::Rc;
use std::result::Result as StdResult;
use std::ffi::{OsStr, OsString};
use std::mem;
// Internal
use Arg;
use args::{AnyArg, ArgSettings, Base, DispOrder, Switched};
use map::{self, VecMap};
#[derive(Default, Clone, Debug)]
#[doc(hidden)]
pub struct FlagBuilder<'n, 'e>
where
'n: 'e,
{
pub b: Base<'n, 'e>,
pub s: Switched<'e>,
}
impl<'n, 'e> FlagBuilder<'n, 'e> {
pub fn new(name: &'n str) -> Self {
FlagBuilder {
b: Base::new(name),
..Default::default()
}
}
}
impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> {
fn from(a: &'z Arg<'a, 'b>) -> Self {
FlagBuilder {
b: Base::from(a),
s: Switched::from(a),
}
}
}
impl<'a, 'b> From<Arg<'a, 'b>> for FlagBuilder<'a, 'b> {
fn from(mut a: Arg<'a, 'b>) -> Self {
FlagBuilder {
b: mem::replace(&mut a.b, Base::default()),
s: mem::replace(&mut a.s, Switched::default()),
}
}
}
impl<'n, 'e> Display for FlagBuilder<'n, 'e> {
fn fmt(&self, f: &mut Formatter) -> Result {
if let Some(l) = self.s.long {
write!(f, "--{}", l)?;
} else {
write!(f, "-{}", self.s.short.unwrap())?;
}
Ok(())
}
}
impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> {
fn name(&self) -> &'n str { self.b.name }
fn overrides(&self) -> Option<&[&'e str]> { self.b.overrides.as_ref().map(|o| &o[..]) }
fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> {
self.b.requires.as_ref().map(|o| &o[..])
}
fn blacklist(&self) -> Option<&[&'e str]> { self.b.blacklist.as_ref().map(|o| &o[..]) }
fn required_unless(&self) -> Option<&[&'e str]> { self.b.r_unless.as_ref().map(|o| &o[..]) }
fn is_set(&self, s: ArgSettings) -> bool { self.b.settings.is_set(s) }
fn has_switch(&self) -> bool { true }
fn takes_value(&self) -> bool { false }
fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) }
fn max_vals(&self) -> Option<u64> { None }
fn val_names(&self) -> Option<&VecMap<&'e str>> { None }
fn num_vals(&self) -> Option<u64> { None }
fn possible_vals(&self) -> Option<&[&'e str]> { None }
fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> { None }
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> { None }
fn min_vals(&self) -> Option<u64> { None }
fn short(&self) -> Option<char> { self.s.short }
fn long(&self) -> Option<&'e str> { self.s.long }
fn val_delim(&self) -> Option<char> { None }
fn help(&self) -> Option<&'e str> { self.b.help }
fn long_help(&self) -> Option<&'e str> { self.b.long_help }
fn val_terminator(&self) -> Option<&'e str> { None }
fn default_val(&self) -> Option<&'e OsStr> { None }
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
None
}
fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { None }
fn longest_filter(&self) -> bool { self.s.long.is_some() }
fn aliases(&self) -> Option<Vec<&'e str>> {
if let Some(ref aliases) = self.s.aliases {
let vis_aliases: Vec<_> = aliases
.iter()
.filter_map(|&(n, v)| if v { Some(n) } else { None })
.collect();
if vis_aliases.is_empty() {
None
} else {
Some(vis_aliases)
}
} else {
None
}
}
}
impl<'n, 'e> DispOrder for FlagBuilder<'n, 'e> {
fn disp_ord(&self) -> usize { self.s.disp_ord }
}
impl<'n, 'e> PartialEq for FlagBuilder<'n, 'e> {
fn eq(&self, other: &FlagBuilder<'n, 'e>) -> bool { self.b == other.b }
}
#[cfg(test)]
mod test {
use args::settings::ArgSettings;
use super::FlagBuilder;
#[test]
fn flagbuilder_display() {
let mut f = FlagBuilder::new("flg");
f.b.settings.set(ArgSettings::Multiple);
f.s.long = Some("flag");
assert_eq!(&*format!("{}", f), "--flag");
let mut f2 = FlagBuilder::new("flg");
f2.s.short = Some('f');
assert_eq!(&*format!("{}", f2), "-f");
}
#[test]
fn flagbuilder_display_single_alias() {
let mut f = FlagBuilder::new("flg");
f.s.long = Some("flag");
f.s.aliases = Some(vec![("als", true)]);
assert_eq!(&*format!("{}", f), "--flag");
}
#[test]
fn flagbuilder_display_multiple_aliases() {
let mut f = FlagBuilder::new("flg");
f.s.short = Some('f');
f.s.aliases = Some(vec![
("alias_not_visible", false),
("f2", true),
("f3", true),
("f4", true),
]);
assert_eq!(&*format!("{}", f), "-f");
}
}

View file

@ -1,13 +0,0 @@
pub use self::flag::FlagBuilder;
pub use self::option::OptBuilder;
pub use self::positional::PosBuilder;
pub use self::base::Base;
pub use self::switched::Switched;
pub use self::valued::Valued;
mod flag;
mod positional;
mod option;
mod base;
mod valued;
mod switched;

View file

@ -1,244 +0,0 @@
// Std
use std::fmt::{Display, Formatter, Result};
use std::rc::Rc;
use std::result::Result as StdResult;
use std::ffi::{OsStr, OsString};
use std::mem;
// Internal
use args::{AnyArg, Arg, ArgSettings, Base, DispOrder, Switched, Valued};
use map::{self, VecMap};
use INTERNAL_ERROR_MSG;
#[allow(missing_debug_implementations)]
#[doc(hidden)]
#[derive(Default, Clone)]
pub struct OptBuilder<'n, 'e>
where
'n: 'e,
{
pub b: Base<'n, 'e>,
pub s: Switched<'e>,
pub v: Valued<'n, 'e>,
}
impl<'n, 'e> OptBuilder<'n, 'e> {
pub fn new(name: &'n str) -> Self {
OptBuilder {
b: Base::new(name),
..Default::default()
}
}
}
impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for OptBuilder<'n, 'e> {
fn from(a: &'z Arg<'n, 'e>) -> Self {
OptBuilder {
b: Base::from(a),
s: Switched::from(a),
v: Valued::from(a),
}
}
}
impl<'n, 'e> From<Arg<'n, 'e>> for OptBuilder<'n, 'e> {
fn from(mut a: Arg<'n, 'e>) -> Self {
a.v.fill_in();
OptBuilder {
b: mem::replace(&mut a.b, Base::default()),
s: mem::replace(&mut a.s, Switched::default()),
v: mem::replace(&mut a.v, Valued::default()),
}
}
}
impl<'n, 'e> Display for OptBuilder<'n, 'e> {
fn fmt(&self, f: &mut Formatter) -> Result {
debugln!("OptBuilder::fmt:{}", self.b.name);
let sep = if self.b.is_set(ArgSettings::RequireEquals) {
"="
} else {
" "
};
// Write the name such --long or -l
if let Some(l) = self.s.long {
write!(f, "--{}{}", l, sep)?;
} else {
write!(f, "-{}{}", self.s.short.unwrap(), sep)?;
}
let delim = if self.is_set(ArgSettings::RequireDelimiter) {
self.v.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
};
// Write the values such as <name1> <name2>
if let Some(ref vec) = self.v.val_names {
let mut it = vec.iter().peekable();
while let Some((_, val)) = it.next() {
write!(f, "<{}>", val)?;
if it.peek().is_some() {
write!(f, "{}", delim)?;
}
}
let num = vec.len();
if self.is_set(ArgSettings::Multiple) && num == 1 {
write!(f, "...")?;
}
} else if let Some(num) = self.v.num_vals {
let mut it = (0..num).peekable();
while let Some(_) = it.next() {
write!(f, "<{}>", self.b.name)?;
if it.peek().is_some() {
write!(f, "{}", delim)?;
}
}
if self.is_set(ArgSettings::Multiple) && num == 1 {
write!(f, "...")?;
}
} else {
write!(
f,
"<{}>{}",
self.b.name,
if self.is_set(ArgSettings::Multiple) {
"..."
} else {
""
}
)?;
}
Ok(())
}
}
impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> {
fn name(&self) -> &'n str { self.b.name }
fn overrides(&self) -> Option<&[&'e str]> { self.b.overrides.as_ref().map(|o| &o[..]) }
fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> {
self.b.requires.as_ref().map(|o| &o[..])
}
fn blacklist(&self) -> Option<&[&'e str]> { self.b.blacklist.as_ref().map(|o| &o[..]) }
fn required_unless(&self) -> Option<&[&'e str]> { self.b.r_unless.as_ref().map(|o| &o[..]) }
fn val_names(&self) -> Option<&VecMap<&'e str>> { self.v.val_names.as_ref() }
fn is_set(&self, s: ArgSettings) -> bool { self.b.settings.is_set(s) }
fn has_switch(&self) -> bool { true }
fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) }
fn max_vals(&self) -> Option<u64> { self.v.max_vals }
fn val_terminator(&self) -> Option<&'e str> { self.v.terminator }
fn num_vals(&self) -> Option<u64> { self.v.num_vals }
fn possible_vals(&self) -> Option<&[&'e str]> { self.v.possible_vals.as_ref().map(|o| &o[..]) }
fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> {
self.v.validator.as_ref()
}
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> {
self.v.validator_os.as_ref()
}
fn min_vals(&self) -> Option<u64> { self.v.min_vals }
fn short(&self) -> Option<char> { self.s.short }
fn long(&self) -> Option<&'e str> { self.s.long }
fn val_delim(&self) -> Option<char> { self.v.val_delim }
fn takes_value(&self) -> bool { true }
fn help(&self) -> Option<&'e str> { self.b.help }
fn long_help(&self) -> Option<&'e str> { self.b.long_help }
fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val }
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
}
fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> {
self.v
.env
.as_ref()
.map(|&(key, ref value)| (key, value.as_ref()))
}
fn longest_filter(&self) -> bool { true }
fn aliases(&self) -> Option<Vec<&'e str>> {
if let Some(ref aliases) = self.s.aliases {
let vis_aliases: Vec<_> = aliases
.iter()
.filter_map(|&(n, v)| if v { Some(n) } else { None })
.collect();
if vis_aliases.is_empty() {
None
} else {
Some(vis_aliases)
}
} else {
None
}
}
}
impl<'n, 'e> DispOrder for OptBuilder<'n, 'e> {
fn disp_ord(&self) -> usize { self.s.disp_ord }
}
impl<'n, 'e> PartialEq for OptBuilder<'n, 'e> {
fn eq(&self, other: &OptBuilder<'n, 'e>) -> bool { self.b == other.b }
}
#[cfg(test)]
mod test {
use args::settings::ArgSettings;
use super::OptBuilder;
use map::VecMap;
#[test]
fn optbuilder_display1() {
let mut o = OptBuilder::new("opt");
o.s.long = Some("option");
o.b.settings.set(ArgSettings::Multiple);
assert_eq!(&*format!("{}", o), "--option <opt>...");
}
#[test]
fn optbuilder_display2() {
let mut v_names = VecMap::new();
v_names.insert(0, "file");
v_names.insert(1, "name");
let mut o2 = OptBuilder::new("opt");
o2.s.short = Some('o');
o2.v.val_names = Some(v_names);
assert_eq!(&*format!("{}", o2), "-o <file> <name>");
}
#[test]
fn optbuilder_display3() {
let mut v_names = VecMap::new();
v_names.insert(0, "file");
v_names.insert(1, "name");
let mut o2 = OptBuilder::new("opt");
o2.s.short = Some('o');
o2.v.val_names = Some(v_names);
o2.b.settings.set(ArgSettings::Multiple);
assert_eq!(&*format!("{}", o2), "-o <file> <name>");
}
#[test]
fn optbuilder_display_single_alias() {
let mut o = OptBuilder::new("opt");
o.s.long = Some("option");
o.s.aliases = Some(vec![("als", true)]);
assert_eq!(&*format!("{}", o), "--option <opt>");
}
#[test]
fn optbuilder_display_multiple_aliases() {
let mut o = OptBuilder::new("opt");
o.s.long = Some("option");
o.s.aliases = Some(vec![
("als_not_visible", false),
("als2", true),
("als3", true),
("als4", true),
]);
assert_eq!(&*format!("{}", o), "--option <opt>");
}
}

View file

@ -1,229 +0,0 @@
// Std
use std::borrow::Cow;
use std::fmt::{Display, Formatter, Result};
use std::rc::Rc;
use std::result::Result as StdResult;
use std::ffi::{OsStr, OsString};
use std::mem;
// Internal
use Arg;
use args::{AnyArg, ArgSettings, Base, DispOrder, Valued};
use INTERNAL_ERROR_MSG;
use map::{self, VecMap};
#[allow(missing_debug_implementations)]
#[doc(hidden)]
#[derive(Clone, Default)]
pub struct PosBuilder<'n, 'e>
where
'n: 'e,
{
pub b: Base<'n, 'e>,
pub v: Valued<'n, 'e>,
pub index: u64,
}
impl<'n, 'e> PosBuilder<'n, 'e> {
pub fn new(name: &'n str, idx: u64) -> Self {
PosBuilder {
b: Base::new(name),
index: idx,
..Default::default()
}
}
pub fn from_arg_ref(a: &Arg<'n, 'e>, idx: u64) -> Self {
let mut pb = PosBuilder {
b: Base::from(a),
v: Valued::from(a),
index: idx,
};
if a.v.max_vals.is_some() || a.v.min_vals.is_some()
|| (a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1)
{
pb.b.settings.set(ArgSettings::Multiple);
}
pb
}
pub fn from_arg(mut a: Arg<'n, 'e>, idx: u64) -> Self {
if a.v.max_vals.is_some() || a.v.min_vals.is_some()
|| (a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1)
{
a.b.settings.set(ArgSettings::Multiple);
}
PosBuilder {
b: mem::replace(&mut a.b, Base::default()),
v: mem::replace(&mut a.v, Valued::default()),
index: idx,
}
}
pub fn multiple_str(&self) -> &str {
let mult_vals = self.v
.val_names
.as_ref()
.map_or(true, |names| names.len() < 2);
if self.is_set(ArgSettings::Multiple) && mult_vals {
"..."
} else {
""
}
}
pub fn name_no_brackets(&self) -> Cow<str> {
debugln!("PosBuilder::name_no_brackets;");
let mut delim = String::new();
delim.push(if self.is_set(ArgSettings::RequireDelimiter) {
self.v.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
});
if let Some(ref names) = self.v.val_names {
debugln!("PosBuilder:name_no_brackets: val_names={:#?}", names);
if names.len() > 1 {
Cow::Owned(
names
.values()
.map(|n| format!("<{}>", n))
.collect::<Vec<_>>()
.join(&*delim),
)
} else {
Cow::Borrowed(names.values().next().expect(INTERNAL_ERROR_MSG))
}
} else {
debugln!("PosBuilder:name_no_brackets: just name");
Cow::Borrowed(self.b.name)
}
}
}
impl<'n, 'e> Display for PosBuilder<'n, 'e> {
fn fmt(&self, f: &mut Formatter) -> Result {
let mut delim = String::new();
delim.push(if self.is_set(ArgSettings::RequireDelimiter) {
self.v.val_delim.expect(INTERNAL_ERROR_MSG)
} else {
' '
});
if let Some(ref names) = self.v.val_names {
write!(
f,
"{}",
names
.values()
.map(|n| format!("<{}>", n))
.collect::<Vec<_>>()
.join(&*delim)
)?;
} else {
write!(f, "<{}>", self.b.name)?;
}
if self.b.settings.is_set(ArgSettings::Multiple)
&& (self.v.val_names.is_none() || self.v.val_names.as_ref().unwrap().len() == 1)
{
write!(f, "...")?;
}
Ok(())
}
}
impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> {
fn name(&self) -> &'n str { self.b.name }
fn overrides(&self) -> Option<&[&'e str]> { self.b.overrides.as_ref().map(|o| &o[..]) }
fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> {
self.b.requires.as_ref().map(|o| &o[..])
}
fn blacklist(&self) -> Option<&[&'e str]> { self.b.blacklist.as_ref().map(|o| &o[..]) }
fn required_unless(&self) -> Option<&[&'e str]> { self.b.r_unless.as_ref().map(|o| &o[..]) }
fn val_names(&self) -> Option<&VecMap<&'e str>> { self.v.val_names.as_ref() }
fn is_set(&self, s: ArgSettings) -> bool { self.b.settings.is_set(s) }
fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) }
fn has_switch(&self) -> bool { false }
fn max_vals(&self) -> Option<u64> { self.v.max_vals }
fn val_terminator(&self) -> Option<&'e str> { self.v.terminator }
fn num_vals(&self) -> Option<u64> { self.v.num_vals }
fn possible_vals(&self) -> Option<&[&'e str]> { self.v.possible_vals.as_ref().map(|o| &o[..]) }
fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> {
self.v.validator.as_ref()
}
fn validator_os(&self) -> Option<&Rc<Fn(&OsStr) -> StdResult<(), OsString>>> {
self.v.validator_os.as_ref()
}
fn min_vals(&self) -> Option<u64> { self.v.min_vals }
fn short(&self) -> Option<char> { None }
fn long(&self) -> Option<&'e str> { None }
fn val_delim(&self) -> Option<char> { self.v.val_delim }
fn takes_value(&self) -> bool { true }
fn help(&self) -> Option<&'e str> { self.b.help }
fn long_help(&self) -> Option<&'e str> { self.b.long_help }
fn default_vals_ifs(&self) -> Option<map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
}
fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val }
fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> {
self.v
.env
.as_ref()
.map(|&(key, ref value)| (key, value.as_ref()))
}
fn longest_filter(&self) -> bool { true }
fn aliases(&self) -> Option<Vec<&'e str>> { None }
}
impl<'n, 'e> DispOrder for PosBuilder<'n, 'e> {
fn disp_ord(&self) -> usize { self.index as usize }
}
impl<'n, 'e> PartialEq for PosBuilder<'n, 'e> {
fn eq(&self, other: &PosBuilder<'n, 'e>) -> bool { self.b == other.b }
}
#[cfg(test)]
mod test {
use args::settings::ArgSettings;
use super::PosBuilder;
use map::VecMap;
#[test]
fn display_mult() {
let mut p = PosBuilder::new("pos", 1);
p.b.settings.set(ArgSettings::Multiple);
assert_eq!(&*format!("{}", p), "<pos>...");
}
#[test]
fn display_required() {
let mut p2 = PosBuilder::new("pos", 1);
p2.b.settings.set(ArgSettings::Required);
assert_eq!(&*format!("{}", p2), "<pos>");
}
#[test]
fn display_val_names() {
let mut p2 = PosBuilder::new("pos", 1);
let mut vm = VecMap::new();
vm.insert(0, "file1");
vm.insert(1, "file2");
p2.v.val_names = Some(vm);
assert_eq!(&*format!("{}", p2), "<file1> <file2>");
}
#[test]
fn display_val_names_req() {
let mut p2 = PosBuilder::new("pos", 1);
p2.b.settings.set(ArgSettings::Required);
let mut vm = VecMap::new();
vm.insert(0, "file1");
vm.insert(1, "file2");
p2.v.val_names = Some(vm);
assert_eq!(&*format!("{}", p2), "<file1> <file2>");
}
}

View file

@ -1,38 +0,0 @@
use Arg;
#[derive(Debug)]
pub struct Switched<'b> {
pub short: Option<char>,
pub long: Option<&'b str>,
pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
pub disp_ord: usize,
pub unified_ord: usize,
}
impl<'e> Default for Switched<'e> {
fn default() -> Self {
Switched {
short: None,
long: None,
aliases: None,
disp_ord: 999,
unified_ord: 999,
}
}
}
impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Switched<'e> {
fn from(a: &'z Arg<'n, 'e>) -> Self { a.s.clone() }
}
impl<'e> Clone for Switched<'e> {
fn clone(&self) -> Self {
Switched {
short: self.short,
long: self.long,
aliases: self.aliases.clone(),
disp_ord: self.disp_ord,
unified_ord: self.unified_ord,
}
}
}

View file

@ -1,67 +0,0 @@
use std::rc::Rc;
use std::ffi::{OsStr, OsString};
use map::VecMap;
use Arg;
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct Valued<'a, 'b>
where
'a: 'b,
{
pub possible_vals: Option<Vec<&'b str>>,
pub val_names: Option<VecMap<&'b str>>,
pub num_vals: Option<u64>,
pub max_vals: Option<u64>,
pub min_vals: Option<u64>,
pub validator: Option<Rc<Fn(String) -> Result<(), String>>>,
pub validator_os: Option<Rc<Fn(&OsStr) -> Result<(), OsString>>>,
pub val_delim: Option<char>,
pub default_val: Option<&'b OsStr>,
pub default_vals_ifs: Option<VecMap<(&'a str, Option<&'b OsStr>, &'b OsStr)>>,
pub env: Option<(&'a OsStr, Option<OsString>)>,
pub terminator: Option<&'b str>,
}
impl<'n, 'e> Default for Valued<'n, 'e> {
fn default() -> Self {
Valued {
possible_vals: None,
num_vals: None,
min_vals: None,
max_vals: None,
val_names: None,
validator: None,
validator_os: None,
val_delim: None,
default_val: None,
default_vals_ifs: None,
env: None,
terminator: None,
}
}
}
impl<'n, 'e> Valued<'n, 'e> {
pub fn fill_in(&mut self) {
if let Some(ref vec) = self.val_names {
if vec.len() > 1 {
self.num_vals = Some(vec.len() as u64);
}
}
}
}
impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Valued<'n, 'e> {
fn from(a: &'z Arg<'n, 'e>) -> Self {
let mut v = a.v.clone();
if let Some(ref vec) = a.v.val_names {
if vec.len() > 1 {
v.num_vals = Some(vec.len() as u64);
}
}
v
}
}

View file

@ -6,8 +6,7 @@ use std::ops::Deref;
use std::mem;
// Internal
use args::{ArgMatches, MatchedArg, SubCommand};
use args::AnyArg;
use args::{Arg, ArgMatches, MatchedArg, SubCommand};
use args::settings::ArgSettings;
#[doc(hidden)]
@ -21,10 +20,10 @@ impl<'a> Default for ArgMatcher<'a> {
impl<'a> ArgMatcher<'a> {
pub fn new() -> Self { ArgMatcher::default() }
pub fn process_arg_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>, overrides: &mut Vec<(&'b str, &'a str)>, required: &mut Vec<&'a str>) {
debugln!("ArgMatcher::process_arg_overrides:{:?};", a.map_or(None, |a| Some(a.name())));
pub fn process_arg_overrides<'b>(&mut self, a: Option<&Arg<'a, 'b>>, overrides: &mut Vec<(&'b str, &'a str)>, required: &mut Vec<&'a str>) {
debugln!("ArgMatcher::process_arg_overrides:{:?};", a.map_or(None, |a| Some(a.name)));
if let Some(aa) = a {
if let Some(a_overrides) = aa.overrides() {
if let Some(ref a_overrides) = aa.overrides {
for overr in a_overrides {
debugln!("ArgMatcher::process_arg_overrides:iter:{};", overr);
if self.is_present(overr) {
@ -38,7 +37,7 @@ impl<'a> ArgMatcher<'a> {
}
}
} else {
overrides.push((overr, aa.name()));
overrides.push((overr, aa.name));
}
}
}
@ -147,23 +146,21 @@ impl<'a> ArgMatcher<'a> {
ma.vals.push(val.to_owned());
}
pub fn needs_more_vals<'b, A>(&self, o: &A) -> bool
where
A: AnyArg<'a, 'b>,
pub fn needs_more_vals<'b>(&self, o: &Arg) -> bool
{
debugln!("ArgMatcher::needs_more_vals: o={}", o.name());
if let Some(ma) = self.get(o.name()) {
if let Some(num) = o.num_vals() {
debugln!("ArgMatcher::needs_more_vals: o={}", o.name);
if let Some(ma) = self.get(o.name) {
if let Some(num) = o.num_vals {
debugln!("ArgMatcher::needs_more_vals: num_vals...{}", num);
return if o.is_set(ArgSettings::Multiple) {
((ma.vals.len() as u64) % num) != 0
} else {
num != (ma.vals.len() as u64)
};
} else if let Some(num) = o.max_vals() {
} else if let Some(num) = o.max_vals {
debugln!("ArgMatcher::needs_more_vals: max_vals...{}", num);
return !((ma.vals.len() as u64) > num);
} else if o.min_vals().is_some() {
} else if o.min_vals.is_some() {
debugln!("ArgMatcher::needs_more_vals: min_vals...true");
return true;
}

View file

@ -1,6 +1,4 @@
pub use self::any_arg::{AnyArg, DispOrder};
pub use self::arg::Arg;
pub use self::arg_builder::{Base, FlagBuilder, OptBuilder, PosBuilder, Switched, Valued};
pub use self::arg_matcher::ArgMatcher;
pub use self::arg_matches::{ArgMatches, OsValues, Values};
pub use self::group::ArgGroup;
@ -11,11 +9,13 @@ pub use self::subcommand::SubCommand;
#[macro_use]
mod macros;
mod arg;
pub mod any_arg;
mod arg_matches;
mod arg_matcher;
mod subcommand;
mod arg_builder;
mod matched_arg;
mod group;
pub mod settings;
pub trait DispOrder {
fn disp_ord(&self) -> usize;
}

View file

@ -2,19 +2,14 @@
use std::io::Write;
// Internal
use app::parser::Parser;
use args::{ArgSettings, OptBuilder};
use app::App;
use args::{ArgSettings, Arg};
use completions;
pub struct BashGen<'a, 'b>
where
'a: 'b,
{
p: &'b Parser<'a, 'b>,
}
pub struct BashGen<'a, 'b> (&'b App<'a, 'b> ) where 'a: 'b;
impl<'a, 'b> BashGen<'a, 'b> {
pub fn new(p: &'b Parser<'a, 'b>) -> Self { BashGen { p: p } }
pub fn new(app: &'b App<'a, 'b>) -> Self { BashGen ( app ) }
pub fn generate_to<W: Write>(&self, buf: &mut W) {
w!(
@ -62,10 +57,10 @@ impl<'a, 'b> BashGen<'a, 'b> {
complete -F _{name} -o bashdefault -o default {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 = self.0.bin_name.as_ref().unwrap(),
name_opts = self.all_options_for_path(self.0.bin_name.as_ref().unwrap()),
name_opts_details =
self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
self.option_details_for_path(self.0.bin_name.as_ref().unwrap()),
subcmds = self.all_subcommands(),
subcmd_details = self.subcommand_details()
).as_bytes()
@ -75,7 +70,7 @@ complete -F _{name} -o bashdefault -o default {name}
fn all_subcommands(&self) -> String {
debugln!("BashGen::all_subcommands;");
let mut subcmds = String::new();
let scs = completions::all_subcommand_names(self.p);
let scs = completions::all_subcommand_names(self.0);
for sc in &scs {
subcmds = format!(
@ -95,7 +90,7 @@ complete -F _{name} -o bashdefault -o default {name}
fn subcommand_details(&self) -> String {
debugln!("BashGen::subcommand_details;");
let mut subcmd_dets = String::new();
let mut scs = completions::get_all_subcommand_paths(self.p, true);
let mut scs = completions::get_all_subcommand_paths(self.0, true);
scs.sort();
scs.dedup();
@ -130,14 +125,14 @@ complete -F _{name} -o bashdefault -o default {name}
fn option_details_for_path(&self, path: &str) -> String {
debugln!("BashGen::option_details_for_path: path={}", path);
let mut p = self.p;
let mut p = self.0;
for sc in path.split("__").skip(1) {
debugln!("BashGen::option_details_for_path:iter: sc={}", sc);
p = &find_subcmd!(p, sc).unwrap().p;
p = &find_subcmd!(p, sc).unwrap();
}
let mut opts = String::new();
for o in p.opts() {
if let Some(l) = o.s.long {
for o in opts!(p) {
if let Some(l) = o.long {
opts = format!(
"{}
--{})
@ -149,7 +144,7 @@ complete -F _{name} -o bashdefault -o default {name}
self.vals_for(o)
);
}
if let Some(s) = o.s.short {
if let Some(s) = o.short {
opts = format!(
"{}
-{})
@ -165,15 +160,14 @@ complete -F _{name} -o bashdefault -o default {name}
opts
}
fn vals_for(&self, o: &OptBuilder) -> String {
debugln!("BashGen::vals_for: o={}", o.b.name);
use args::AnyArg;
fn vals_for(&self, o: &Arg) -> String {
debugln!("BashGen::vals_for: o={}", o.name);
let mut ret = String::new();
let mut needs_quotes = true;
if let Some(vals) = o.possible_vals() {
if let Some(ref vals) = o.possible_vals {
needs_quotes = false;
ret = format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" "));
} else if let Some(vec) = o.val_names() {
} else if let Some(ref vec) = o.val_names {
let mut it = vec.iter().peekable();
while let Some((_, val)) = it.next() {
ret = format!(
@ -187,13 +181,13 @@ complete -F _{name} -o bashdefault -o default {name}
if o.is_set(ArgSettings::Multiple) && num == 1 {
ret = format!("{}...", ret);
}
} else if let Some(num) = o.num_vals() {
} else if let Some(num) = o.num_vals {
let mut it = (0..num).peekable();
while let Some(_) = it.next() {
ret = format!(
"{}<{}>{}",
ret,
o.name(),
o.name,
if it.peek().is_some() { " " } else { "" }
);
}
@ -201,7 +195,7 @@ complete -F _{name} -o bashdefault -o default {name}
ret = format!("{}...", ret);
}
} else {
ret = format!("<{}>", o.name());
ret = format!("<{}>", o.name);
if o.is_set(ArgSettings::Multiple) {
ret = format!("{}...", ret);
}
@ -213,10 +207,10 @@ complete -F _{name} -o bashdefault -o default {name}
}
fn all_options_for_path(&self, path: &str) -> String {
debugln!("BashGen::all_options_for_path: path={}", path);
let mut p = self.p;
let mut p = self.0;
for sc in path.split("__").skip(1) {
debugln!("BashGen::all_options_for_path:iter: sc={}", sc);
p = &find_subcmd!(p, sc).unwrap().p;
p = &find_subcmd!(p, sc).unwrap();
}
let mut opts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s));
opts = format!(
@ -227,19 +221,17 @@ complete -F _{name} -o bashdefault -o default {name}
opts = format!(
"{} {}",
opts,
p.positionals
.values()
positionals!(p)
.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))
subcommands!(p)
.fold(String::new(), |acc, s| format!("{} {}", acc, s.name))
);
for sc in &p.subcommands {
if let Some(ref aliases) = sc.p.meta.aliases {
for sc in subcommands!(p) {
if let Some(ref aliases) = sc.aliases {
opts = format!(
"{} {}",
opts,

View file

@ -2,20 +2,15 @@
use std::io::Write;
// Internal
use app::parser::Parser;
use app::App;
pub struct FishGen<'a, 'b>
where
'a: 'b,
{
p: &'b Parser<'a, 'b>,
}
pub struct FishGen<'a, 'b> (&'b App<'a, 'b> ) where 'a: 'b;
impl<'a, 'b> FishGen<'a, 'b> {
pub fn new(p: &'b Parser<'a, 'b>) -> Self { FishGen { p: p } }
pub fn new(app: &'b App<'a, 'b>) -> Self { FishGen ( app ) }
pub fn generate_to<W: Write>(&self, buf: &mut W) {
let command = self.p.meta.bin_name.as_ref().unwrap();
let command = self.0.bin_name.as_ref().unwrap();
// function to detect subcommand
let detect_subcommand_function = r#"function __fish_using_command
@ -62,44 +57,44 @@ fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, parent_cmds: &str, buf
parent_cmds
);
for option in comp_gen.p.opts() {
for option in opts!(comp_gen.0) {
let mut template = basic_template.clone();
if let Some(data) = option.s.short {
if let Some(data) = option.short {
template.push_str(format!(" -s {}", data).as_str());
}
if let Some(data) = option.s.long {
if let Some(data) = option.long {
template.push_str(format!(" -l {}", data).as_str());
}
if let Some(data) = option.b.help {
if let Some(data) = option.help {
template.push_str(format!(" -d '{}'", escape_string(data)).as_str());
}
if let Some(ref data) = option.v.possible_vals {
if let Some(ref data) = option.possible_vals {
template.push_str(format!(" -r -f -a \"{}\"", data.join(" ")).as_str());
}
buffer.push_str(template.as_str());
buffer.push_str("\n");
}
for flag in comp_gen.p.flags() {
for flag in flags!(comp_gen.0) {
let mut template = basic_template.clone();
if let Some(data) = flag.s.short {
if let Some(data) = flag.short {
template.push_str(format!(" -s {}", data).as_str());
}
if let Some(data) = flag.s.long {
if let Some(data) = flag.long {
template.push_str(format!(" -l {}", data).as_str());
}
if let Some(data) = flag.b.help {
if let Some(data) = flag.help {
template.push_str(format!(" -d '{}'", escape_string(data)).as_str());
}
buffer.push_str(template.as_str());
buffer.push_str("\n");
}
for subcommand in &comp_gen.p.subcommands {
for subcommand in subcommands!(comp_gen.0) {
let mut template = basic_template.clone();
template.push_str(" -f");
template.push_str(format!(" -a \"{}\"", &subcommand.p.meta.name).as_str());
if let Some(data) = subcommand.p.meta.about {
template.push_str(format!(" -a \"{}\"", &subcommand.name).as_str());
if let Some(data) = subcommand.about {
template.push_str(format!(" -d '{}'", escape_string(data)).as_str())
}
buffer.push_str(template.as_str());
@ -107,14 +102,14 @@ fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, parent_cmds: &str, buf
}
// generate options of subcommands
for subcommand in &comp_gen.p.subcommands {
let sub_comp_gen = FishGen::new(&subcommand.p);
for subcommand in subcommands!(comp_gen.0) {
let sub_comp_gen = FishGen::new(&subcommand);
// make new "parent_cmds" for different subcommands
let mut sub_parent_cmds = parent_cmds.to_string();
if !sub_parent_cmds.is_empty() {
sub_parent_cmds.push_str(" ");
}
sub_parent_cmds.push_str(&subcommand.p.meta.name);
sub_parent_cmds.push_str(&subcommand.name);
gen_fish_inner(root_command, &sub_comp_gen, &sub_parent_cmds, buffer);
}
}

View file

@ -8,15 +8,15 @@ macro_rules! w {
}
macro_rules! get_zsh_arg_conflicts {
($p:ident, $arg:ident, $msg:ident) => {
if let Some(conf_vec) = $arg.blacklist() {
($app:expr, $arg:ident, $msg:ident) => {
if let Some(conf_vec) = $arg.blacklist {
let mut v = vec![];
for arg_name in conf_vec {
let arg = $p.find_any_arg(arg_name).expect($msg);
if let Some(s) = arg.short() {
let arg = find!($app, arg_name).expect($msg);
if let Some(s) = arg.short {
v.push(format!("-{}", s));
}
if let Some(l) = arg.long() {
if let Some(l) = arg.long {
v.push(format!("--{}", l));
}
}

View file

@ -10,29 +10,24 @@ mod shell;
use std::io::Write;
// Internal
use app::parser::Parser;
use app::App;
use self::bash::BashGen;
use self::fish::FishGen;
use self::zsh::ZshGen;
use self::powershell::PowerShellGen;
pub use self::shell::Shell;
pub struct ComplGen<'a, 'b>
where
'a: 'b,
{
p: &'b Parser<'a, 'b>,
}
pub struct ComplGen<'a, 'b> (&'b App<'a, 'b>, ) where 'a: 'b;
impl<'a, 'b> ComplGen<'a, 'b> {
pub fn new(p: &'b Parser<'a, 'b>) -> Self { ComplGen { p: p } }
pub fn new(app: &'b App<'a, 'b>) -> Self { ComplGen ( app ) }
pub fn generate<W: Write>(&self, for_shell: Shell, buf: &mut W) {
match for_shell {
Shell::Bash => BashGen::new(self.p).generate_to(buf),
Shell::Fish => FishGen::new(self.p).generate_to(buf),
Shell::Zsh => ZshGen::new(self.p).generate_to(buf),
Shell::PowerShell => PowerShellGen::new(self.p).generate_to(buf),
Shell::Bash => BashGen::new(self.0).generate_to(buf),
Shell::Fish => FishGen::new(self.0).generate_to(buf),
Shell::Zsh => ZshGen::new(self.0).generate_to(buf),
Shell::PowerShell => PowerShellGen::new(self.0).generate_to(buf),
}
}
}
@ -43,13 +38,13 @@ impl<'a, 'b> ComplGen<'a, 'b> {
//
// Also note, aliases are treated as their own subcommands but duplicates of whatever they're
// aliasing.
pub fn all_subcommand_names(p: &Parser) -> Vec<String> {
pub fn all_subcommand_names(p: &App) -> Vec<String> {
debugln!("all_subcommand_names;");
let mut subcmds: Vec<_> = subcommands_of(p)
.iter()
.map(|&(ref n, _)| n.clone())
.collect();
for sc_v in p.subcommands.iter().map(|s| all_subcommand_names(&s.p)) {
for sc_v in subcommands!(p).map(|s| all_subcommand_names(&s)) {
subcmds.extend(sc_v);
}
subcmds.sort();
@ -63,10 +58,10 @@ pub fn all_subcommand_names(p: &Parser) -> Vec<String> {
//
// Also note, aliases are treated as their own subcommands but duplicates of whatever they're
// aliasing.
pub fn all_subcommands(p: &Parser) -> Vec<(String, String)> {
pub fn all_subcommands(p: &App) -> Vec<(String, String)> {
debugln!("all_subcommands;");
let mut subcmds: Vec<_> = subcommands_of(p);
for sc_v in p.subcommands.iter().map(|s| all_subcommands(&s.p)) {
for sc_v in subcommands!(p).map(|s| all_subcommands(&s)) {
subcmds.extend(sc_v);
}
subcmds
@ -78,11 +73,11 @@ pub fn all_subcommands(p: &Parser) -> Vec<(String, String)> {
//
// Also note, aliases are treated as their own subcommands but duplicates of whatever they're
// aliasing.
pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> {
pub fn subcommands_of(p: &App) -> Vec<(String, String)> {
debugln!(
"subcommands_of: name={}, bin_name={}",
p.meta.name,
p.meta.bin_name.as_ref().unwrap()
p.name,
p.bin_name.as_ref().unwrap()
);
let mut subcmds = vec![];
@ -93,11 +88,11 @@ pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> {
if !p.has_subcommands() {
let mut ret = vec![];
debugln!("subcommands_of: Looking for aliases...");
if let Some(ref aliases) = p.meta.aliases {
if let Some(ref aliases) = p.aliases {
for &(n, _) in aliases {
debugln!("subcommands_of:iter:iter: Found alias...{}", n);
let mut als_bin_name: Vec<_> =
p.meta.bin_name.as_ref().unwrap().split(' ').collect();
p.bin_name.as_ref().unwrap().split(' ').collect();
als_bin_name.push(n);
let old = als_bin_name.len() - 2;
als_bin_name.swap_remove(old);
@ -106,19 +101,19 @@ pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> {
}
return ret;
}
for sc in &p.subcommands {
for sc in subcommands!(p) {
debugln!(
"subcommands_of:iter: name={}, bin_name={}",
sc.p.meta.name,
sc.p.meta.bin_name.as_ref().unwrap()
sc.name,
sc.bin_name.as_ref().unwrap()
);
debugln!("subcommands_of:iter: Looking for aliases...");
if let Some(ref aliases) = sc.p.meta.aliases {
if let Some(ref aliases) = sc.aliases {
for &(n, _) in aliases {
debugln!("subcommands_of:iter:iter: Found alias...{}", n);
let mut als_bin_name: Vec<_> =
p.meta.bin_name.as_ref().unwrap().split(' ').collect();
p.bin_name.as_ref().unwrap().split(' ').collect();
als_bin_name.push(n);
let old = als_bin_name.len() - 2;
als_bin_name.swap_remove(old);
@ -126,22 +121,22 @@ pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> {
}
}
subcmds.push((
sc.p.meta.name.clone(),
sc.p.meta.bin_name.as_ref().unwrap().clone(),
sc.name.clone(),
sc.bin_name.as_ref().unwrap().clone(),
));
}
subcmds
}
pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
pub fn get_all_subcommand_paths(p: &App, first: bool) -> Vec<String> {
debugln!("get_all_subcommand_paths;");
let mut subcmds = vec![];
if !p.has_subcommands() {
if !first {
let name = &*p.meta.name;
let path = p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "__");
let name = &*p.name;
let path = p.bin_name.as_ref().unwrap().clone().replace(" ", "__");
let mut ret = vec![path.clone()];
if let Some(ref aliases) = p.meta.aliases {
if let Some(ref aliases) = p.aliases {
for &(n, _) in aliases {
ret.push(path.replace(name, n));
}
@ -150,25 +145,22 @@ pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
}
return vec![];
}
for sc in &p.subcommands {
let name = &*sc.p.meta.name;
let path = sc.p
.meta
.bin_name
for sc in subcommands!(p) {
let name = &*sc.name;
let path = sc.bin_name
.as_ref()
.unwrap()
.clone()
.replace(" ", "__");
subcmds.push(path.clone());
if let Some(ref aliases) = sc.p.meta.aliases {
if let Some(ref aliases) = sc.aliases {
for &(n, _) in aliases {
subcmds.push(path.replace(name, n));
}
}
}
for sc_v in p.subcommands
.iter()
.map(|s| get_all_subcommand_paths(&s.p, false))
for sc_v in subcommands!(p)
.map(|s| get_all_subcommand_paths(&s, false))
{
subcmds.extend(sc_v);
}

View file

@ -2,25 +2,20 @@
use std::io::Write;
// Internal
use app::parser::Parser;
use app::App;
use INTERNAL_ERROR_MSG;
pub struct PowerShellGen<'a, 'b>
where
'a: 'b,
{
p: &'b Parser<'a, 'b>,
}
pub struct PowerShellGen<'a, 'b> (&'b App<'a, 'b>) where 'a: 'b;
impl<'a, 'b> PowerShellGen<'a, 'b> {
pub fn new(p: &'b Parser<'a, 'b>) -> Self { PowerShellGen { p: p } }
pub fn new(app: &'b App<'a, 'b>) -> Self { PowerShellGen ( app ) }
pub fn generate_to<W: Write>(&self, buf: &mut W) {
let bin_name = self.p.meta.bin_name.as_ref().unwrap();
let bin_name = self.0.bin_name.as_ref().unwrap();
let mut names = vec![];
let (subcommands_detection_cases, subcommands_cases) =
generate_inner(self.p, "", &mut names);
generate_inner(self.0, "", &mut names);
let mut bin_names = vec![bin_name.to_string(), format!("./{0}", bin_name)];
if cfg!(windows) {
@ -46,7 +41,7 @@ impl<'a, 'b> PowerShellGen<'a, 'b> {
%{{
switch ($_.ToString()) {{
{subcommands_detection_cases}
default {{
default {{
break
}}
}}
@ -76,7 +71,7 @@ impl<'a, 'b> PowerShellGen<'a, 'b> {
}
fn generate_inner<'a, 'b, 'p>(
p: &'p Parser<'a, 'b>,
p: &'p App<'a, 'b>,
previous_command_name: &str,
names: &mut Vec<&'p str>,
) -> (String, String) {
@ -85,14 +80,14 @@ fn generate_inner<'a, 'b, 'p>(
format!(
"{}_{}",
previous_command_name,
&p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG)
&p.bin_name.as_ref().expect(INTERNAL_ERROR_MSG)
)
} else {
format!("{}_{}", previous_command_name, &p.meta.name)
format!("{}_{}", previous_command_name, &p.name)
};
let mut subcommands_detection_cases = if !names.contains(&&*p.meta.name) {
names.push(&*p.meta.name);
let mut subcommands_detection_cases = if !names.contains(&&*p.name) {
names.push(&*p.name);
format!(
r"
'{0}' {{
@ -100,7 +95,7 @@ fn generate_inner<'a, 'b, 'p>(
break
}}
",
&p.meta.name
&p.name
)
} else {
String::new()
@ -108,7 +103,7 @@ fn generate_inner<'a, 'b, 'p>(
let mut completions = String::new();
for subcommand in &p.subcommands {
completions.push_str(&format!("'{}', ", &subcommand.p.meta.name));
completions.push_str(&format!("'{}', ", &subcommand.name));
}
for short in shorts!(p) {
completions.push_str(&format!("'-{}', ", short));
@ -127,9 +122,9 @@ fn generate_inner<'a, 'b, 'p>(
completions.trim_right_matches(", ")
);
for subcommand in &p.subcommands {
for subcommand in subcommands!(p) {
let (subcommand_subcommands_detection_cases, subcommand_subcommands_cases) =
generate_inner(&subcommand.p, &command_name, names);
generate_inner(&subcommand, &command_name, names);
subcommands_detection_cases.push_str(&subcommand_subcommands_detection_cases);
subcommands_cases.push_str(&subcommand_subcommands_cases);
}

View file

@ -5,22 +5,16 @@ use std::ascii::AsciiExt;
// Internal
use app::App;
use app::parser::Parser;
use args::{AnyArg, ArgSettings};
use args::ArgSettings;
use completions;
use INTERNAL_ERROR_MSG;
pub struct ZshGen<'a, 'b>
where
'a: 'b,
{
p: &'b Parser<'a, 'b>,
}
pub struct ZshGen<'a, 'b> (&'b App<'a, 'b>) where 'a: 'b;
impl<'a, 'b> ZshGen<'a, 'b> {
pub fn new(p: &'b Parser<'a, 'b>) -> Self {
pub fn new(app: &'b App<'a, 'b>) -> Self {
debugln!("ZshGen::new;");
ZshGen { p: p }
ZshGen ( app )
}
pub fn generate_to<W: Write>(&self, buf: &mut W) {
@ -52,10 +46,10 @@ _{name}() {{
{subcommand_details}
_{name} \"$@\"",
name = self.p.meta.bin_name.as_ref().unwrap(),
initial_args = get_args_of(self.p),
subcommands = get_subcommands_of(self.p),
subcommand_details = subcommand_details(self.p)
name = self.0.bin_name.as_ref().unwrap(),
initial_args = get_args_of(self.0),
subcommands = get_subcommands_of(self.0),
subcommand_details = subcommand_details(self.0)
).as_bytes()
);
}
@ -88,7 +82,7 @@ _{name} \"$@\"",
// )
// _describe -t commands 'rustup commands' commands "$@"
//
fn subcommand_details(p: &Parser) -> String {
fn subcommand_details(p: &App) -> String {
debugln!("ZshGen::subcommand_details;");
// First we do ourself
let mut ret = vec![
@ -101,8 +95,8 @@ _{bin_name_underscore}_commands() {{
)
_describe -t commands '{bin_name} commands' commands \"$@\"
}}",
bin_name_underscore = p.meta.bin_name.as_ref().unwrap().replace(" ", "__"),
bin_name = p.meta.bin_name.as_ref().unwrap(),
bin_name_underscore = p.bin_name.as_ref().unwrap().replace(" ", "__"),
bin_name = p.bin_name.as_ref().unwrap(),
subcommands_and_args = subcommands_of(p)
),
];
@ -142,7 +136,7 @@ _{bin_name_underscore}_commands() {{
// A snippet from rustup:
// 'show:Show the active and installed toolchains'
// 'update:Update Rust toolchains'
fn subcommands_of(p: &Parser) -> String {
fn subcommands_of(p: &App) -> String {
debugln!("ZshGen::subcommands_of;");
let mut ret = vec![];
fn add_sc(sc: &App, n: &str, ret: &mut Vec<String>) {
@ -150,8 +144,7 @@ fn subcommands_of(p: &Parser) -> String {
let s = format!(
"\"{name}:{help}\" \\",
name = n,
help = sc.p
.meta
help = sc
.about
.unwrap_or("")
.replace("[", "\\[")
@ -163,13 +156,13 @@ fn subcommands_of(p: &Parser) -> String {
}
// The subcommands
for sc in p.subcommands() {
for sc in subcommands!(p) {
debugln!(
"ZshGen::subcommands_of:iter: subcommand={}",
sc.p.meta.name
sc.name
);
add_sc(sc, &sc.p.meta.name, &mut ret);
if let Some(ref v) = sc.p.meta.aliases {
add_sc(sc, &sc.name, &mut ret);
if let Some(ref v) = sc.aliases {
for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) {
add_sc(sc, alias, &mut ret);
}
@ -208,7 +201,7 @@ fn subcommands_of(p: &Parser) -> String {
// [name_hyphen] = The full space deliniated bin_name, but replace spaces with hyphens
// [repeat] = From the same recursive calls, but for all subcommands
// [subcommand_args] = The same as zsh::get_args_of
fn get_subcommands_of(p: &Parser) -> String {
fn get_subcommands_of(p: &App) -> String {
debugln!("get_subcommands_of;");
debugln!(
@ -247,19 +240,19 @@ fn get_subcommands_of(p: &Parser) -> String {
esac
;;
esac",
name = p.meta.name,
name_hyphen = p.meta.bin_name.as_ref().unwrap().replace(" ", "-"),
name = p.name,
name_hyphen = p.bin_name.as_ref().unwrap().replace(" ", "-"),
subcommands = subcmds.join("\n"),
pos = p.positionals().len() + 1
pos = positionals!(p).count() + 1
)
}
fn parser_of<'a, 'b>(p: &'b Parser<'a, 'b>, sc: &str) -> &'b Parser<'a, 'b> {
fn parser_of<'a, 'b>(p: &'b App<'a, 'b>, sc: &str) -> &'b App<'a, 'b> {
debugln!("parser_of: sc={}", sc);
if sc == p.meta.bin_name.as_ref().unwrap_or(&String::new()) {
if sc == p.bin_name.as_ref().unwrap_or(&String::new()) {
return p;
}
&p.find_subcommand(sc).expect(INTERNAL_ERROR_MSG).p
find_subcmd!(p, sc).expect(INTERNAL_ERROR_MSG)
}
// Writes out the args section, which ends up being the flags, opts and postionals, and a jump to
@ -282,7 +275,7 @@ fn parser_of<'a, 'b>(p: &'b Parser<'a, 'b>, sc: &str) -> &'b Parser<'a, 'b> {
// -C: modify the $context internal variable
// -s: Allow stacking of short args (i.e. -a -b -c => -abc)
// -S: Do not complete anything after '--' and treat those as argument values
fn get_args_of(p: &Parser) -> String {
fn get_args_of(p: &App) -> String {
debugln!("get_args_of;");
let mut ret = vec![String::from("_arguments \"${_arguments_options[@]}\" \\")];
let opts = write_opts_of(p);
@ -291,13 +284,13 @@ fn get_args_of(p: &Parser) -> String {
let sc_or_a = if p.has_subcommands() {
format!(
"\":: :_{name}_commands\" \\",
name = p.meta.bin_name.as_ref().unwrap().replace(" ", "__")
name = p.bin_name.as_ref().unwrap().replace(" ", "__")
)
} else {
String::new()
};
let sc = if p.has_subcommands() {
format!("\"*::: :->{name}\" \\", name = p.meta.name)
format!("\"*::: :->{name}\" \\", name = p.name)
} else {
String::new()
};
@ -341,12 +334,12 @@ fn escape_value(string: &str) -> String {
.replace(" ", "\\ ")
}
fn write_opts_of(p: &Parser) -> String {
fn write_opts_of(p: &App) -> String {
debugln!("write_opts_of;");
let mut ret = vec![];
for o in p.opts() {
debugln!("write_opts_of:iter: o={}", o.name());
let help = o.help().map_or(String::new(), escape_help);
for o in opts!(p) {
debugln!("write_opts_of:iter: o={}", o.name);
let help = o.help.map_or(String::new(), escape_help);
let mut conflicts = get_zsh_arg_conflicts!(p, o, INTERNAL_ERROR_MSG);
conflicts = if conflicts.is_empty() {
String::new()
@ -359,13 +352,13 @@ fn write_opts_of(p: &Parser) -> String {
} else {
""
};
let pv = if let Some(pv_vec) = o.possible_vals() {
let pv = if let Some(ref pv_vec) = o.possible_vals {
format!(": :({})", pv_vec.iter().map(
|v| escape_value(*v)).collect::<Vec<String>>().join(" "))
} else {
String::new()
};
if let Some(short) = o.short() {
if let Some(short) = o.short {
let s = format!(
"'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\",
conflicts = conflicts,
@ -378,7 +371,7 @@ fn write_opts_of(p: &Parser) -> String {
debugln!("write_opts_of:iter: Wrote...{}", &*s);
ret.push(s);
}
if let Some(long) = o.long() {
if let Some(long) = o.long {
let l = format!(
"'{conflicts}{multiple}--{arg}=[{help}]{possible_values}' \\",
conflicts = conflicts,
@ -396,12 +389,12 @@ fn write_opts_of(p: &Parser) -> String {
ret.join("\n")
}
fn write_flags_of(p: &Parser) -> String {
fn write_flags_of(p: &App) -> String {
debugln!("write_flags_of;");
let mut ret = vec![];
for f in p.flags() {
debugln!("write_flags_of:iter: f={}", f.name());
let help = f.help().map_or(String::new(), escape_help);
for f in flags!(p) {
debugln!("write_flags_of:iter: f={}", f.name);
let help = f.help.map_or(String::new(), escape_help);
let mut conflicts = get_zsh_arg_conflicts!(p, f, INTERNAL_ERROR_MSG);
conflicts = if conflicts.is_empty() {
String::new()
@ -414,7 +407,7 @@ fn write_flags_of(p: &Parser) -> String {
} else {
""
};
if let Some(short) = f.short() {
if let Some(short) = f.short {
let s = format!(
"'{conflicts}{multiple}-{arg}[{help}]' \\",
multiple = multiple,
@ -427,7 +420,7 @@ fn write_flags_of(p: &Parser) -> String {
ret.push(s);
}
if let Some(long) = f.long() {
if let Some(long) = f.long {
let l = format!(
"'{conflicts}{multiple}--{arg}[{help}]' \\",
conflicts = conflicts,
@ -444,21 +437,20 @@ fn write_flags_of(p: &Parser) -> String {
ret.join("\n")
}
fn write_positionals_of(p: &Parser) -> String {
fn write_positionals_of(p: &App) -> String {
debugln!("write_positionals_of;");
let mut ret = vec![];
for arg in p.positionals() {
for arg in positionals!(p) {
debugln!("write_positionals_of:iter: arg={}", arg.b.name);
let a = format!(
"'{optional}:{name}{help}:{action}' \\",
optional = if !arg.b.is_set(ArgSettings::Required) { ":" } else { "" },
name = arg.b.name,
help = arg.b
.help
optional = if !arg.is_set(ArgSettings::Required) { ":" } else { "" },
name = arg.name,
help = arg.help
.map_or("".to_owned(), |v| " -- ".to_owned() + v)
.replace("[", "\\[")
.replace("]", "\\]"),
action = arg.possible_vals().map_or("_files".to_owned(), |values| {
action = arg.possible_vals.map_or("_files".to_owned(), |values| {
format!("({})",
values.iter().map(|v| escape_value(*v)).collect::<Vec<String>>().join(" "))
})

View file

@ -8,7 +8,7 @@ use std::process;
use std::result::Result as StdResult;
// Internal
use args::AnyArg;
use args::Arg;
use fmt::{ColorWhen, Colorizer, ColorizerOption};
use suggestions;
@ -405,7 +405,7 @@ impl Error {
#[doc(hidden)]
pub fn argument_conflict<'a, 'b, O, U>(
arg: &AnyArg,
arg: &Arg,
other: Option<O>,
usage: U,
color: ColorWhen,
@ -414,7 +414,7 @@ impl Error {
O: Into<String>,
U: Display,
{
let mut v = vec![arg.name().to_owned()];
let mut v = vec![arg.name.to_owned()];
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
when: color,
@ -443,7 +443,7 @@ impl Error {
}
#[doc(hidden)]
pub fn empty_value<'a, 'b, U>(arg: &AnyArg, usage: U, color: ColorWhen) -> Self
pub fn empty_value<'a, 'b, U>(arg: &Arg, usage: U, color: ColorWhen) -> Self
where
U: Display,
{
@ -463,7 +463,7 @@ impl Error {
c.good("--help")
),
kind: ErrorKind::EmptyValue,
info: Some(vec![arg.name().to_owned()]),
info: Some(vec![arg.name.to_owned()]),
}
}
@ -471,7 +471,7 @@ impl Error {
pub fn invalid_value<'a, 'b, B, G, U>(
bad_val: B,
good_vals: &[G],
arg: &AnyArg,
arg: &Arg,
usage: U,
color: ColorWhen,
) -> Self
@ -509,7 +509,7 @@ impl Error {
c.good("--help")
),
kind: ErrorKind::InvalidValue,
info: Some(vec![arg.name().to_owned(), bad_val.as_ref().to_owned()]),
info: Some(vec![arg.name.to_owned(), bad_val.as_ref().to_owned()]),
}
}
@ -657,7 +657,7 @@ impl Error {
}
#[doc(hidden)]
pub fn too_many_values<'a, 'b, V, U>(val: V, arg: &AnyArg, usage: U, color: ColorWhen) -> Self
pub fn too_many_values<'a, 'b, V, U>(val: V, arg: &Arg, usage: U, color: ColorWhen) -> Self
where
V: AsRef<str> + Display + ToOwned,
U: Display,
@ -680,13 +680,13 @@ impl Error {
c.good("--help")
),
kind: ErrorKind::TooManyValues,
info: Some(vec![arg.name().to_owned(), v.to_owned()]),
info: Some(vec![arg.name.to_owned(), v.to_owned()]),
}
}
#[doc(hidden)]
pub fn too_few_values<'a, 'b, U>(
arg: &AnyArg,
arg: &Arg,
min_vals: u64,
curr_vals: usize,
usage: U,
@ -714,12 +714,12 @@ impl Error {
c.good("--help")
),
kind: ErrorKind::TooFewValues,
info: Some(vec![arg.name().to_owned()]),
info: Some(vec![arg.name.to_owned()]),
}
}
#[doc(hidden)]
pub fn value_validation<'a, 'b>(arg: Option<&AnyArg>, err: String, color: ColorWhen) -> Self
pub fn value_validation<'a, 'b>(arg: Option<&Arg>, err: String, color: ColorWhen) -> Self
{
let c = Colorizer::new(ColorizerOption {
use_stderr: true,
@ -743,13 +743,13 @@ impl Error {
#[doc(hidden)]
pub fn value_validation_auto(err: String) -> Self {
let n: Option<&AnyArg> = None;
let n: Option<&Arg> = None;
Error::value_validation(n, err, ColorWhen::Auto)
}
#[doc(hidden)]
pub fn wrong_number_of_values<'a, 'b, S, U>(
arg: &AnyArg,
arg: &Arg,
num_vals: u64,
curr_vals: usize,
suffix: S,
@ -779,12 +779,12 @@ impl Error {
c.good("--help")
),
kind: ErrorKind::WrongNumberOfValues,
info: Some(vec![arg.name().to_owned()]),
info: Some(vec![arg.name.to_owned()]),
}
}
#[doc(hidden)]
pub fn unexpected_multiple_usage<'a, 'b, U>(arg: &AnyArg, usage: U, color: ColorWhen) -> Self
pub fn unexpected_multiple_usage<'a, 'b, U>(arg: &Arg, usage: U, color: ColorWhen) -> Self
where
U: Display,
{
@ -804,7 +804,7 @@ impl Error {
c.good("--help")
),
kind: ErrorKind::UnexpectedMultipleUsage,
info: Some(vec![arg.name().to_owned()]),
info: Some(vec![arg.name.to_owned()]),
}
}

View file

@ -852,38 +852,91 @@ macro_rules! write_nspaces {
})
}
// convenience macro for remove an item from a vec
//macro_rules! vec_remove_all {
// ($vec:expr, $to_rem:expr) => {
// debugln!("vec_remove_all! to_rem={:?}", $to_rem);
// for i in (0 .. $vec.len()).rev() {
// let should_remove = $to_rem.any(|name| name == &$vec[i]);
// if should_remove { $vec.swap_remove(i); }
// }
// };
//}
macro_rules! flags {
($app:expr, $how:ident) => {
$app.args.$how().filter(|a| !a.settings.is_set(::args::settings::ArgSettings::TakesValue) && (a.short.is_some() || a.long.is_some()))
};
($app:expr) => {
flags!($app, iter)
}
}
macro_rules! flags_mut {
($app:expr) => {
flags!($app, iter_mut)
}
}
macro_rules! opts {
($app:expr, $how:ident) => {
$app.args.$how().filter(|a| a.settings.is_set(::args::settings::ArgSettings::TakesValue) && (a.short.is_some() || a.long.is_some()))
};
($app:expr) => {
opts!($app, iter)
}
}
#[allow(unused_macros)]
macro_rules! opts_mut {
($app:expr) => {
opts!($app, iter)
}
}
macro_rules! positionals {
($app:expr, $how:ident) => {
$app.args.$how().filter(|a| !(a.short.is_some() || a.long.is_some()))
};
($app:expr) => {
positionals!($app, iter)
}
}
#[allow(unused_macros)]
macro_rules! positionals_mut {
($app:expr) => {
positionals!($app, iter_mut)
}
}
macro_rules! subcommands {
($app:expr, $how:ident) => {
$app.subcommands.$how()
};
($app:expr) => {
subcommands!($app, iter)
}
}
macro_rules! subcommands_mut {
($app:expr) => {
subcommands!($app, iter_mut)
}
}
macro_rules! groups {
($app:expr, $how:ident) => {
$app.groups.$how()
};
($app:expr) => {
groups!($app, iter)
}
}
macro_rules! groups_mut {
($app:expr) => {
groups!($app, iter_mut)
}
}
macro_rules! find_from {
($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
($app:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
let mut ret = None;
for k in $matcher.arg_names() {
if let Some(f) = find_by_name!($_self, k, flags, iter) {
if let Some(ref v) = f.$from() {
if let Some(a) = find!($app, k) {
if let Some(ref v) = a.$from {
if v.contains($arg_name) {
ret = Some(f.to_string());
}
}
}
if let Some(o) = find_by_name!($_self, k, opts, iter) {
if let Some(ref v) = o.$from() {
if v.contains(&$arg_name) {
ret = Some(o.to_string());
}
}
}
if let Some(pos) = find_by_name!($_self, k, positionals, values) {
if let Some(ref v) = pos.$from() {
if v.contains($arg_name) {
ret = Some(pos.b.name.to_owned());
ret = Some(a.to_string());
}
}
}
@ -892,83 +945,23 @@ macro_rules! find_from {
}};
}
//macro_rules! find_name_from {
// ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{
// let mut ret = None;
// for k in $matcher.arg_names() {
// if let Some(f) = find_by_name!($_self, k, flags, iter) {
// if let Some(ref v) = f.$from() {
// if v.contains($arg_name) {
// ret = Some(f.b.name);
// }
// }
// }
// if let Some(o) = find_by_name!($_self, k, opts, iter) {
// if let Some(ref v) = o.$from() {
// if v.contains(&$arg_name) {
// ret = Some(o.b.name);
// }
// }
// }
// if let Some(pos) = find_by_name!($_self, k, positionals, values) {
// if let Some(ref v) = pos.$from() {
// if v.contains($arg_name) {
// ret = Some(pos.b.name);
// }
// }
// }
// }
// ret
// }};
//}
macro_rules! find_any_by_name {
($p:expr, $name:expr) => {
{
fn as_trait_obj<'a, 'b, T: AnyArg<'a, 'b>>(x: &T) -> &AnyArg<'a, 'b> { x }
find_by_name!($p, $name, flags, iter).map(as_trait_obj).or(
find_by_name!($p, $name, opts, iter).map(as_trait_obj).or(
find_by_name!($p, $name, positionals, values).map(as_trait_obj)
)
)
}
}
}
// Finds an arg by name
macro_rules! find_by_name {
($p:expr, $name:expr, $what:ident, $how:ident) => {
$p.$what.$how().find(|o| o.b.name == $name)
macro_rules! find {
($app:expr, $name:expr, $what:ident) => {
$what!($app).find(|a| a.name == $name)
};
($app:expr, $name:expr) => {
$app.args.iter().find(|a| a.name == $name)
}
}
// Finds an option including if it's aliasesed
macro_rules! find_opt_by_long {
(@os $_self:ident, $long:expr) => {{
_find_by_long!($_self, $long, opts)
}};
($_self:ident, $long:expr) => {{
_find_by_long!($_self, $long, opts)
}};
}
macro_rules! find_flag_by_long {
(@os $_self:ident, $long:expr) => {{
_find_by_long!($_self, $long, flags)
}};
($_self:ident, $long:expr) => {{
_find_by_long!($_self, $long, flags)
}};
}
macro_rules! _find_by_long {
($_self:ident, $long:expr, $what:ident) => {{
$_self.$what
.iter()
.filter(|a| a.s.long.is_some())
macro_rules! find_by_long {
($app:expr, $long:expr, $what:ident) => {{
$what!($app)
.filter(|a| a.long.is_some())
.find(|a| {
a.s.long.unwrap() == $long ||
(a.s.aliases.is_some() &&
a.long.unwrap() == $long ||
(a.aliases.is_some() &&
a.s
.aliases
.as_ref()
@ -976,104 +969,93 @@ macro_rules! _find_by_long {
.iter()
.any(|&(alias, _)| alias == $long))
})
}}
}};
($app:expr, $long:expr) => {{
$app.args.iter()
.filter(|a| a.long.is_some())
.find(|a| {
a.long.unwrap() == $long ||
(a.aliases.is_some() &&
a.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(alias, _)| alias == $long))
})
}};
}
// Finds an option
macro_rules! find_opt_by_short {
($_self:ident, $short:expr) => {{
_find_by_short!($_self, $short, opts)
}}
}
macro_rules! find_flag_by_short {
($_self:ident, $short:expr) => {{
_find_by_short!($_self, $short, flags)
}}
}
macro_rules! _find_by_short {
($_self:ident, $short:expr, $what:ident) => {{
$_self.$what
.iter()
.filter(|a| a.s.short.is_some())
.find(|a| a.s.short.unwrap() == $short)
macro_rules! find_by_short {
($app:expr, $short:expr, $what:ident) => {{
$what!($app)
.filter(|a| a.short.is_some())
.find(|a| a.short.unwrap() == $short)
}};
($app:expr, $short:expr) => {{
$app.args.iter()
.filter(|a| a.short.is_some())
.find(|a| a.short.unwrap() == $short)
}}
}
macro_rules! find_subcmd {
($_self:expr, $sc:expr) => {{
$_self.subcommands
.iter()
subcommands!($_self)
.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))
&*s.name == $sc ||
(s.aliases.is_some() &&
s.aliases
.as_ref()
.unwrap()
.iter()
.any(|&(n, _)| n == $sc))
})
}};
}
macro_rules! shorts {
($_self:ident) => {{
_shorts_longs!($_self, short)
($app:expr) => {{
_shorts_longs!($app, short)
}};
}
macro_rules! longs {
($_self:ident) => {{
_shorts_longs!($_self, long)
($app:expr) => {{
_shorts_longs!($app, long)
}};
}
macro_rules! _shorts_longs {
($_self:ident, $what:ident) => {{
$_self.flags
.iter()
.filter(|f| f.s.$what.is_some())
.map(|f| f.s.$what.as_ref().unwrap())
.chain($_self.opts.iter()
.filter(|o| o.s.$what.is_some())
.map(|o| o.s.$what.as_ref().unwrap()))
}};
}
macro_rules! arg_names {
($_self:ident) => {{
_names!(@args $_self)
}};
}
macro_rules! sc_names {
($_self:ident) => {{
_names!(@sc $_self)
($app:expr, $what:ident) => {{
$app.args.iter().filter_map(|a| a.$what)
}};
}
macro_rules! _names {
(@args $_self:ident) => {{
$_self.flags
.iter()
.map(|f| &*f.b.name)
.chain($_self.opts.iter()
.map(|o| &*o.b.name)
.chain($_self.positionals.values()
.map(|p| &*p.b.name)))
(@args $app:expr) => {{
$app.args.iter().map(|a| &*a.name)
}};
(@sc $_self:ident) => {{
$_self.subcommands
(@sc $app:expr) => {{
$app.subcommands
.iter()
.map(|s| &*s.p.meta.name)
.chain($_self.subcommands
.map(|s| &*s.name)
.chain($app.subcommands
.iter()
.filter(|s| s.p.meta.aliases.is_some())
.flat_map(|s| s.p.meta.aliases.as_ref().unwrap().iter().map(|&(n, _)| n)))
.filter(|s| s.aliases.is_some())
.flat_map(|s| s.aliases.as_ref().unwrap().iter().map(|&(n, _)| n)))
}}
}
macro_rules! arg_names {
($app:expr) => {{
_names!(@args $app)
}};
}
macro_rules! sc_names {
($app:expr) => {{
_names!(@sc $app)
}};
}

View file

@ -1,10 +1,10 @@
use app::App;
// Third Party
#[cfg(feature = "suggestions")]
use strsim;
// Internal
use fmt::Format;
use app::App;
/// Produces a string from a given list of possible values which is similar to
/// the passed in value `v` with a certain confidence.
@ -42,14 +42,13 @@ where
/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
#[cfg_attr(feature = "lints", allow(needless_lifetimes))]
pub fn did_you_mean_flag_suffix<'z, T, I>(
pub fn did_you_mean_flag_suffix<'z, I>(
arg: &str,
longs: I,
subcommands: &'z [App],
) -> (String, Option<&'z str>)
where
T: AsRef<str> + 'z,
I: IntoIterator<Item = &'z T>,
I: IntoIterator<Item = &'z str>,
{
match did_you_mean(arg, longs) {
Some(candidate) => {
@ -61,14 +60,9 @@ where
return (suffix, Some(candidate));
}
None => for subcommand in subcommands {
let opts = subcommand
.p
.flags
.iter()
.filter_map(|f| f.s.long)
.chain(subcommand.p.opts.iter().filter_map(|o| o.s.long));
let longs = longs!(subcommand);
if let Some(candidate) = did_you_mean(arg, opts) {
if let Some(candidate) = did_you_mean(arg, longs) {
let suffix = format!(
"\n\tDid you mean to put '{}{}' after the subcommand '{}'?",
Format::Good("--"),

File diff suppressed because it is too large Load diff