mirror of
https://github.com/clap-rs/clap
synced 2024-11-15 00:57:15 +00:00
wip: changes to builders in prep for v3
This commit is contained in:
parent
969c3adb41
commit
acdbd47152
27 changed files with 3091 additions and 3772 deletions
337
src/app/help.rs
337
src/app/help.rs
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
614
src/app/mod.rs
614
src/app/mod.rs
|
@ -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 }
|
||||
}
|
||||
|
||||
|
|
1784
src/app/parser.rs
1784
src/app/parser.rs
File diff suppressed because it is too large
Load diff
848
src/app/usage.rs
848
src/app/usage.rs
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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() }
|
||||
}
|
545
src/args/arg.rs
545
src/args/arg.rs
|
@ -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>");
|
||||
}
|
||||
}
|
|
@ -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 }
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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>");
|
||||
}
|
||||
}
|
|
@ -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>");
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(" "))
|
||||
})
|
||||
|
|
|
@ -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()]),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
320
src/macros.rs
320
src/macros.rs
|
@ -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)
|
||||
}};
|
||||
}
|
|
@ -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
Loading…
Reference in a new issue