From acdbd47152102607b7f4c6702cc076caca771280 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Mon, 22 Jan 2018 18:19:53 -0500 Subject: [PATCH] wip: changes to builders in prep for v3 --- src/app/help.rs | 337 ++++-- src/app/meta.rs | 33 - src/app/mod.rs | 614 +++++++--- src/app/parser.rs | 1784 +++++++++++----------------- src/app/usage.rs | 848 +++++++------ src/app/validator.rs | 219 ++-- src/args/any_arg.rs | 74 -- src/args/arg.rs | 545 +++++++-- src/args/arg_builder/base.rs | 38 - src/args/arg_builder/flag.rs | 159 --- src/args/arg_builder/mod.rs | 13 - src/args/arg_builder/option.rs | 244 ---- src/args/arg_builder/positional.rs | 229 ---- src/args/arg_builder/switched.rs | 38 - src/args/arg_builder/valued.rs | 67 -- src/args/arg_matcher.rs | 25 +- src/args/mod.rs | 8 +- src/completions/bash.rs | 64 +- src/completions/fish.rs | 43 +- src/completions/macros.rs | 10 +- src/completions/mod.rs | 74 +- src/completions/powershell.rs | 35 +- src/completions/zsh.rs | 100 +- src/errors.rs | 34 +- src/macros.rs | 320 +++-- src/suggestions.rs | 16 +- src/usage_parser.rs | 892 +++++++------- 27 files changed, 3091 insertions(+), 3772 deletions(-) delete mode 100644 src/app/meta.rs delete mode 100644 src/args/any_arg.rs delete mode 100644 src/args/arg_builder/base.rs delete mode 100644 src/args/arg_builder/flag.rs delete mode 100644 src/args/arg_builder/mod.rs delete mode 100644 src/args/arg_builder/option.rs delete mode 100644 src/args/arg_builder/positional.rs delete mode 100644 src/args/arg_builder/switched.rs delete mode 100644 src/args/arg_builder/valued.rs diff --git a/src/app/help.rs b/src/app/help.rs index fc118a9e..ea0357a8 100644 --- a/src/app/help.rs +++ b/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>, + 'a: 'b, + I: Iterator>, { 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>, + 'a: 'b, + I: Iterator>, { 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 { + fn val<'b, 'c>(&mut self, arg: &Arg<'b, 'c>) -> Result { 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::>() .join(", ") } else { - aliases.join(", ") + aliases.iter().filter(|&als| als.1).map(|&als| als.0).collect::>().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 { + 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::>() + .join(", ") + } else { + aliases.iter().filter(|&als| als.1).map(|&als| als.0).collect::>().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( // 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. diff --git a/src/app/meta.rs b/src/app/meta.rs deleted file mode 100644 index c7f128fe..00000000 --- a/src/app/meta.rs +++ /dev/null @@ -1,33 +0,0 @@ -#[doc(hidden)] -#[allow(missing_debug_implementations)] -#[derive(Default, Clone)] -pub struct AppMeta<'b> { - pub name: String, - pub bin_name: Option, - 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>, // (name, visible) - pub usage_str: Option<&'b str>, - pub usage: Option, - pub help_str: Option<&'b str>, - pub disp_ord: usize, - pub term_w: Option, - pub max_w: Option, - 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() - } - } -} diff --git a/src/app/mod.rs b/src/app/mod.rs index 0a27cb36..b079c30f 100644 --- a/src/app/mod.rs +++ b/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, + 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>, // (name, visible) + pub usage_str: Option<&'b str>, + pub usage: Option, + pub help_str: Option<&'b str>, + pub disp_ord: usize, + pub term_w: Option, + pub max_w: Option, + pub template: Option<&'b str>, + settings: AppFlags, + pub g_settings: AppFlags, + pub args: Vec>, + pub subcommands: Vec>, + pub groups: Vec>, + help_short: Option, + version_short: Option, + 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>(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>(n: S) -> Self { - let mut a = App { - p: Parser::with_name(n.into()), - }; - a.p.meta.author = Some("Kevin K. "); - a.p.meta.version = Some("2.19.2"); - a + App { + name: n.into(), + author: Some("Kevin K. "), + 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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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>(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 + '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>(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>(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>(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>(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>>(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>(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::>()); + self.aliases = Some(names.iter().map(|n| (*n, false)).collect::>()); } 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>(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::>()); + self.aliases = Some(names.iter().map(|n| (*n, true)).collect::>()); } 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>, { 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(&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(&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(&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, T: Into + 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(&mut self, it: &mut Peekable) -> ClapResult> + where + I: Iterator, + T: Into + 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(&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 { None } - fn num_vals(&self) -> Option { None } - fn possible_vals(&self) -> Option<&[&'e str]> { None } - fn validator(&self) -> Option<&Rc StdResult<(), String>>> { None } - fn validator_os(&self) -> Option<&Rc StdResult<(), OsString>>> { None } - fn min_vals(&self) -> Option { None } - fn short(&self) -> Option { None } - fn long(&self) -> Option<&'e str> { None } - fn val_delim(&self) -> Option { 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, &'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> { - 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 } +} + diff --git a/src/app/parser.rs b/src/app/parser.rs index 01e0e1f3..73366aac 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -1,35 +1,30 @@ // Std use std::ffi::{OsStr, OsString}; -use std::fmt::Display; -use std::fs::File; use std::io::{self, BufWriter, Write}; #[cfg(feature = "debug")] use std::os::unix::ffi::OsStrExt; -use std::path::PathBuf; use std::slice::Iter; use std::iter::Peekable; +// Third party +use vec_map::VecMap; + // Internal use INTERNAL_ERROR_MSG; use INVALID_UTF8; use SubCommand; use app::App; use app::help::Help; -use app::meta::AppMeta; -use app::settings::AppFlags; -use args::{AnyArg, Arg, ArgGroup, ArgMatcher, Base, FlagBuilder, OptBuilder, PosBuilder, Switched}; +use args::{Arg, ArgGroup, ArgMatcher}; use args::settings::ArgSettings; -use completions::ComplGen; -use errors::{Error, ErrorKind}; +use errors::ErrorKind; +use errors::Error as ClapError; use errors::Result as ClapResult; -use fmt::ColorWhen; use osstringext::OsStrExt2; -use completions::Shell; use suggestions; use app::settings::AppSettings as AS; use app::validator::Validator; -use app::usage; -use map::{self, VecMap}; +use app::usage::Usage; #[derive(Debug, PartialEq, Copy, Clone)] #[doc(hidden)] @@ -43,215 +38,134 @@ pub enum ParseResult<'a> { ValuesDone, } -#[allow(missing_debug_implementations)] #[doc(hidden)] -#[derive(Clone, Default)] -pub struct Parser<'a, 'b> +pub struct Parser<'a, 'b, 'c> where 'a: 'b, + 'b: 'c { - pub meta: AppMeta<'b>, - settings: AppFlags, - pub g_settings: AppFlags, - pub flags: Vec>, - pub opts: Vec>, - pub positionals: VecMap>, - pub subcommands: Vec>, - pub groups: Vec>, - pub global_args: Vec>, + pub app: &'c mut App<'a, 'b>, pub required: Vec<&'a str>, pub r_ifs: Vec<(&'a str, &'b str, &'a str)>, pub overrides: Vec<(&'b str, &'a str)>, - help_short: Option, - version_short: Option, cache: Option<&'a str>, - pub help_message: Option<&'a str>, - pub version_message: Option<&'a str>, + num_opts: usize, + num_flags: usize, + pub positionals: VecMap<&'a str>, } -impl<'a, 'b> Parser<'a, 'b> +// Initializing Methods +impl<'a, 'b, 'c> Parser<'a, 'b, 'c> where 'a: 'b, + 'b: 'c, { - pub fn with_name(n: String) -> Self { + pub fn new(app: &'c mut App<'a, 'b>) -> Self { + app._build(); + let reqs = app.args.iter().filter(|a| + a.settings.is_set(ArgSettings::Required)).map(|a| a.name).collect(); + Parser { - meta: AppMeta::with_name(n), - g_settings: AppFlags::zeroed(), - ..Default::default() + app: app, + required: reqs, + r_ifs: Vec::new(), + overrides: Vec::new(), + cache: None, + num_opts: 0, + num_flags: 0, + positionals: VecMap::new(), } - } - - pub fn help_short(&mut self, s: &str) { - let c = s.trim_left_matches(|c| c == '-') - .chars() - .nth(0) - .unwrap_or('h'); - self.help_short = Some(c); - } - - pub fn version_short(&mut self, s: &str) { - let c = s.trim_left_matches(|c| c == '-') - .chars() - .nth(0) - .unwrap_or('V'); - self.version_short = Some(c); - } - - pub fn gen_completions_to(&mut self, for_shell: Shell, buf: &mut W) { - if !self.is_set(AS::Propagated) { - self.propagate_help_version(); - self.build_bin_names(); - self.propagate_globals(); - self.propagate_settings(); - self.set(AS::Propagated); - } - - ComplGen::new(self).generate(for_shell, buf) - } - - pub fn gen_completions(&mut self, for_shell: Shell, od: OsString) { - use std::error::Error; - - let out_dir = PathBuf::from(od); - let name = &*self.meta.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(for_shell, &mut file) - } - - #[inline] +} + // Perform some expensive assertions on the Parser itself fn app_debug_asserts(&mut self) -> bool { assert!(self.verify_positionals()); - let should_err = self.groups.iter().all(|g| { - g.args.iter().all(|arg| { - (self.flags.iter().any(|f| &f.b.name == arg) - || self.opts.iter().any(|o| &o.b.name == arg) - || self.positionals.values().any(|p| &p.b.name == arg) - || self.groups.iter().any(|g| &g.name == arg)) - }) - }); - let g = self.groups.iter().find(|g| { + + // * Args listed inside groups should exist + // * Groups should not have naming conflicts with Args + let g = groups!(self.app).find(|g| { g.args.iter().any(|arg| { - !(self.flags.iter().any(|f| &f.b.name == arg) - || self.opts.iter().any(|o| &o.b.name == arg) - || self.positionals.values().any(|p| &p.b.name == arg) - || self.groups.iter().any(|g| &g.name == arg)) + !(find!(self.app, *arg).is_some() + || groups!(self.app).any(|g| &g.name == arg)) }) }); assert!( - should_err, - "The group '{}' contains the arg '{}' that doesn't actually exist.", - g.unwrap().name, - g.unwrap() - .args - .iter() - .find(|arg| { - !(self.flags.iter().any(|f| &&f.b.name == arg) - || self.opts.iter().any(|o| &&o.b.name == arg) - || self.positionals.values().any(|p| &&p.b.name == arg) - || self.groups.iter().any(|g| &&g.name == arg)) - }) - .unwrap() + g.is_none(), + "The group '{}' contains an arg that doesn't exist or has a naming conflict with a group.", + g.unwrap().name ); true } - #[inline] - fn debug_asserts(&self, a: &Arg) -> bool { + // Perform expensive assertions on the Arg instance + fn arg_debug_asserts(&self, a: &Arg) -> bool { + // No naming conflicts assert!( - !arg_names!(self).any(|name| name == a.b.name), - format!("Non-unique argument name: {} is already in use", a.b.name) + !arg_names!(self.app).any(|name| name == a.name), + format!("Non-unique argument name: {} is already in use", a.name) ); - if let Some(l) = a.s.long { + + // Long conflicts + if let Some(l) = a.long { assert!( !self.contains_long(l), "Argument long must be unique\n\n\t--{} is already in use", l ); } - if let Some(s) = a.s.short { + + // Short conflicts + if let Some(s) = a.short { assert!( !self.contains_short(s), "Argument short must be unique\n\n\t-{} is already in use", s ); } - let i = if a.index.is_none() { - (self.positionals.len() + 1) - } else { - a.index.unwrap() as usize - }; - assert!( - !self.positionals.contains_key(i), - "Argument \"{}\" has the same index as another positional \ - argument\n\n\tPerhaps try .multiple(true) to allow one positional argument \ - to take multiple values", - a.b.name - ); + + if let Some(idx) = a.index { + // No index conflicts + assert!( + positionals!(self.app).find(|p| p.index == Some(idx as u64)).is_none(), + "Argument '{}' has the same index as another positional \ + argument\n\n\tUse Arg::multiple(true) to allow one positional argument \ + to take multiple values", + a.name + ); + } assert!( !(a.is_set(ArgSettings::Required) && a.is_set(ArgSettings::Global)), "Global arguments cannot be required.\n\n\t'{}' is marked as \ global and required", - a.b.name + a.name ); - if a.b.is_set(ArgSettings::Last) { + if a.is_set(ArgSettings::Last) { assert!( - !self.positionals - .values() - .any(|p| p.b.is_set(ArgSettings::Last)), + !positionals!(self.app) + .any(|p| p.is_set(ArgSettings::Last)), "Only one positional argument may have last(true) set. Found two." ); - assert!(a.s.long.is_none(), + assert!(a.long.is_none(), "Flags or Options may not have last(true) set. {} has both a long and last(true) set.", - a.b.name); - assert!(a.s.short.is_none(), + a.name); + assert!(a.short.is_none(), "Flags or Options may not have last(true) set. {} has both a short and last(true) set.", - a.b.name); + a.name); } true } - #[inline] fn add_conditional_reqs(&mut self, a: &Arg<'a, 'b>) { if let Some(ref r_ifs) = a.r_ifs { for &(arg, val) in r_ifs { - self.r_ifs.push((arg, val, a.b.name)); + self.r_ifs.push((arg, val, a.name)); } } } - #[inline] - fn add_arg_groups(&mut self, a: &Arg<'a, 'b>) { - if let Some(ref grps) = a.b.groups { - for g in grps { - let mut found = false; - if let Some(ref mut ag) = self.groups.iter_mut().find(|grp| &grp.name == g) { - ag.args.push(a.b.name); - found = true; - } - if !found { - let mut ag = ArgGroup::with_name(g); - ag.args.push(a.b.name); - self.groups.push(ag); - } - } - } - } - - #[inline] fn add_reqs(&mut self, a: &Arg<'a, 'b>) { if a.is_set(ArgSettings::Required) { // If the arg is required, add all it's requirements to master required list - if let Some(ref areqs) = a.b.requires { + if let Some(ref areqs) = a.requires { for name in areqs .iter() .filter(|&&(val, _)| val.is_none()) @@ -260,253 +174,56 @@ where self.required.push(name); } } - self.required.push(a.b.name); - } - } - - #[inline] - 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(AS::DontCollapseArgsInUsage); - self.set(AS::ContainsLast); - } - if let Some(l) = a.s.long { - if l == "version" { - self.unset(AS::NeedsLongVersion); - } else if l == "help" { - self.unset(AS::NeedsLongHelp); - } + self.required.push(a.name); } } // actually adds the arguments - pub fn add_arg(&mut self, a: Arg<'a, 'b>) { - // if it's global we have to clone anyways - if a.is_set(ArgSettings::Global) { - return self.add_arg_ref(&a); - } - debug_assert!(self.debug_asserts(&a)); + pub fn build_arg(&mut self, a: &mut Arg<'a, 'b>) { + // Run arg specific debug assertions if in debug mode + debug_assert!(self.arg_debug_asserts(a)); + + // Add requirements self.add_conditional_reqs(&a); - self.add_arg_groups(&a); self.add_reqs(&a); - self.implied_settings(&a); - if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) { + + // Count types + if a.index.is_some() || (a.short.is_none() && a.long.is_none()) { let i = if a.index.is_none() { (self.positionals.len() + 1) } else { a.index.unwrap() as usize }; - self.positionals - .insert(i, PosBuilder::from_arg(a, i as u64)); + a.index = Some(i as u64); + self.positionals.insert(i, a.name); } else if a.is_set(ArgSettings::TakesValue) { - let mut ob = OptBuilder::from(a); - ob.s.unified_ord = self.flags.len() + self.opts.len(); - self.opts.push(ob); + self.num_opts += 1; + a.unified_ord = self.num_flags + self.num_opts; } else { - let mut fb = FlagBuilder::from(a); - fb.s.unified_ord = self.flags.len() + self.opts.len(); - self.flags.push(fb); - } - } - // actually adds the arguments but from a borrow (which means we have to do some clonine) - pub fn add_arg_ref(&mut self, a: &Arg<'a, 'b>) { - debug_assert!(self.debug_asserts(a)); - self.add_conditional_reqs(a); - self.add_arg_groups(a); - self.add_reqs(a); - self.implied_settings(a); - if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) { - let i = if a.index.is_none() { - (self.positionals.len() + 1) - } else { - a.index.unwrap() as usize - }; - let pb = PosBuilder::from_arg_ref(a, i as u64); - self.positionals.insert(i, pb); - } else if a.is_set(ArgSettings::TakesValue) { - let mut ob = OptBuilder::from(a); - ob.s.unified_ord = self.flags.len() + self.opts.len(); - self.opts.push(ob); - } else { - let mut fb = FlagBuilder::from(a); - fb.s.unified_ord = self.flags.len() + self.opts.len(); - self.flags.push(fb); - } - if a.is_set(ArgSettings::Global) { - self.global_args.push(a.into()); + self.num_flags += 1; + a.unified_ord = self.num_flags + self.num_opts; } } - pub fn add_group(&mut self, group: ArgGroup<'a>) { + pub fn build_group(&mut self, group: &ArgGroup<'a>) { if group.required { self.required.push(group.name); if let Some(ref reqs) = group.requires { self.required.extend_from_slice(reqs); } -// if let Some(ref bl) = group.conflicts { -// self.blacklist.extend_from_slice(bl); -// } - } - if self.groups.iter().any(|g| g.name == group.name) { - let grp = self.groups - .iter_mut() - .find(|g| g.name == group.name) - .expect(INTERNAL_ERROR_MSG); - grp.args.extend_from_slice(&group.args); - grp.requires = group.requires.clone(); - grp.conflicts = group.conflicts.clone(); - grp.required = group.required; - } else { - self.groups.push(group); } + // @TODO @dead-code: remove if tests pass + // if groups!(self.app).any(|g| g.name == group.name) { + // let grp = groups_mut!(self.app) + // .find(|g| g.name == group.name) + // .expect(INTERNAL_ERROR_MSG); + // grp.args.extend_from_slice(&group.args); + // grp.requires = group.requires.clone(); + // grp.conflicts = group.conflicts.clone(); + // grp.required = group.required; + // } } - pub fn add_subcommand(&mut self, mut subcmd: App<'a, 'b>) { - debugln!( - "Parser::add_subcommand: term_w={:?}, name={}", - self.meta.term_w, - subcmd.p.meta.name - ); - subcmd.p.meta.term_w = self.meta.term_w; - if subcmd.p.meta.name == "help" { - self.unset(AS::NeedsSubcommandHelp); - } - - self.subcommands.push(subcmd); - } - - pub fn propagate_settings(&mut self) { - debugln!( - "Parser::propagate_settings: self={}, g_settings={:#?}", - self.meta.name, - self.g_settings - ); - for sc in &mut self.subcommands { - debugln!( - "Parser::propagate_settings: sc={}, settings={:#?}, g_settings={:#?}", - sc.p.meta.name, - sc.p.settings, - sc.p.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(AS::VersionlessSubcommands); - let gv = self.settings.is_set(AS::GlobalVersion); - - if vsc { - sc.p.set(AS::DisableVersion); - } - if gv && sc.p.meta.version.is_none() && self.meta.version.is_some() { - sc.p.set(AS::GlobalVersion); - sc.p.meta.version = Some(self.meta.version.unwrap()); - } - sc.p.settings = sc.p.settings | self.g_settings; - sc.p.g_settings = sc.p.g_settings | self.g_settings; - sc.p.meta.term_w = self.meta.term_w; - sc.p.meta.max_w = self.meta.max_w; - } - sc.p.propagate_settings(); - } - } - - #[cfg_attr(feature = "lints", allow(needless_borrow))] - pub fn derive_display_order(&mut self) { - if self.is_set(AS::DeriveDisplayOrder) { - let unified = self.is_set(AS::UnifiedHelpMessage); - for (i, o) in self.opts - .iter_mut() - .enumerate() - .filter(|&(_, ref o)| o.s.disp_ord == 999) - { - o.s.disp_ord = if unified { o.s.unified_ord } else { i }; - } - for (i, f) in self.flags - .iter_mut() - .enumerate() - .filter(|&(_, ref f)| f.s.disp_ord == 999) - { - f.s.disp_ord = if unified { f.s.unified_ord } else { i }; - } - for (i, sc) in &mut self.subcommands - .iter_mut() - .enumerate() - .filter(|&(_, ref sc)| sc.p.meta.disp_ord == 999) - { - sc.p.meta.disp_ord = i; - } - } - for sc in &mut self.subcommands { - sc.p.derive_display_order(); - } - } - - pub fn required(&self) -> Iter<&str> { self.required.iter() } - - #[cfg_attr(feature = "lints", allow(needless_borrow))] - #[inline] - pub fn has_args(&self) -> bool { - !(self.flags.is_empty() && self.opts.is_empty() && self.positionals.is_empty()) - } - - #[inline] - pub fn has_opts(&self) -> bool { !self.opts.is_empty() } - - #[inline] - pub fn has_flags(&self) -> bool { !self.flags.is_empty() } - - #[inline] - pub fn has_positionals(&self) -> bool { !self.positionals.is_empty() } - - #[inline] - pub fn has_subcommands(&self) -> bool { !self.subcommands.is_empty() } - - #[inline] - pub fn has_visible_opts(&self) -> bool { - if self.opts.is_empty() { - return false; - } - self.opts.iter().any(|o| !o.is_set(ArgSettings::Hidden)) - } - - #[inline] - pub fn has_visible_flags(&self) -> bool { - if self.flags.is_empty() { - return false; - } - self.flags.iter().any(|f| !f.is_set(ArgSettings::Hidden)) - } - - #[inline] - pub fn has_visible_positionals(&self) -> bool { - if self.positionals.is_empty() { - return false; - } - self.positionals - .values() - .any(|p| !p.is_set(ArgSettings::Hidden)) - } - - #[inline] - pub fn has_visible_subcommands(&self) -> bool { - self.has_subcommands() - && self.subcommands - .iter() - .filter(|sc| sc.p.meta.name != "help") - .any(|sc| !sc.p.is_set(AS::Hidden)) - } - - #[inline] - pub fn is_set(&self, s: AS) -> bool { self.settings.is_set(s) } - - #[inline] - pub fn set(&mut self, s: AS) { self.settings.set(s) } - - #[inline] - pub fn unset(&mut self, s: AS) { self.settings.unset(s) } - #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))] pub fn verify_positionals(&mut self) -> bool { // Because you must wait until all arguments have been supplied, this is the first chance @@ -515,29 +232,33 @@ where // Firt we verify that the index highest supplied index, is equal to the number of // positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3 // but no 2) - if let Some((idx, p)) = self.positionals.iter().rev().next() { - assert!( - !(idx != self.positionals.len()), - "Found positional argument \"{}\" whose index is {} but there \ + let highest_idx = self.positionals.keys().last().unwrap_or(0); + let num_p = self.positionals.len(); + assert!( + highest_idx != num_p, + "Found positional argument whose index is {} but there \ are only {} positional arguments defined", - p.b.name, - idx, - self.positionals.len() - ); - } + highest_idx, + num_p + ); // Next we verify that only the highest index has a .multiple(true) (if any) - if self.positionals.values().any(|a| { - a.b.is_set(ArgSettings::Multiple) && (a.index as usize != self.positionals.len()) + if positionals!(self.app).any(|a| { + a.is_set(ArgSettings::Multiple) && (a.index.unwrap_or(0) != highest_idx as u64) }) { + // First we make sure if there is a positional that allows multiple values + // the one before it (second to last) has one of these: + // * a value terminator + // * ArgSettings::Last + // * The last arg is Required let mut it = self.positionals.values().rev(); - let last = it.next().unwrap(); - let second_to_last = it.next().unwrap(); + let last = find!(self.app, *it.next().expect(INTERNAL_ERROR_MSG)).expect(INTERNAL_ERROR_MSG); + let second_to_last = find!(self.app, *it.next().expect(INTERNAL_ERROR_MSG)).expect(INTERNAL_ERROR_MSG); // Either the final positional is required // Or the second to last has a terminator or .last(true) set let ok = last.is_set(ArgSettings::Required) - || (second_to_last.v.terminator.is_some() - || second_to_last.b.is_set(ArgSettings::Last)) + || (second_to_last.terminator.is_some() + || second_to_last.is_set(ArgSettings::Last)) || last.is_set(ArgSettings::Last); assert!( ok, @@ -545,6 +266,8 @@ where last* positional argument, the last positional argument (i.e the one \ with the highest index) *must* have .required(true) or .last(true) set." ); + + // We make sure if the second to last is Multiple the last is ArgSettings::Last let ok = second_to_last.is_set(ArgSettings::Multiple) || last.is_set(ArgSettings::Last); assert!( ok, @@ -552,10 +275,10 @@ where argument may be set to .multiple(true)" ); - let count = self.positionals - .values() + // Next we check how many have both Multiple and not a specific number of values set + let count = positionals!(self.app) .filter(|p| { - p.b.settings.is_set(ArgSettings::Multiple) && p.v.num_vals.is_none() + p.settings.is_set(ArgSettings::Multiple) && p.num_vals.is_none() }) .count(); let ok = count <= 1 @@ -569,23 +292,22 @@ where ); } - if self.is_set(AS::AllowMissingPositional) { // Check that if a required positional argument is found, all positions with a lower // index are also required. let mut found = false; let mut foundx2 = false; - for p in self.positionals.values().rev() { - if foundx2 && !p.b.settings.is_set(ArgSettings::Required) { + for p in self.positionals.values().rev().map(|p_name| find!(self.app, *p_name).expect(INTERNAL_ERROR_MSG)) { + if foundx2 && !p.is_set(ArgSettings::Required) { assert!( - p.b.is_set(ArgSettings::Required), + p.is_set(ArgSettings::Required), "Found positional argument which is not required with a lower \ index than a required positional argument by two or more: {:?} \ - index {}", - p.b.name, + index {:?}", + p.name, p.index ); - } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) { + } else if p.is_set(ArgSettings::Required) && !p.is_set(ArgSettings::Last) { // Args that .last(true) don't count since they can be required and have // positionals with a lower index that aren't required // Imagine: prog [opt1] -- @@ -606,16 +328,16 @@ where // Check that if a required positional argument is found, all positions with a lower // index are also required let mut found = false; - for p in self.positionals.values().rev() { + for p in self.positionals.values().rev().map(|p_name| find!(self.app, *p_name).expect(INTERNAL_ERROR_MSG)) { if found { assert!( - p.b.is_set(ArgSettings::Required), + p.is_set(ArgSettings::Required), "Found positional argument which is not required with a lower \ - index than a required positional argument: {:?} index {}", - p.b.name, + index than a required positional argument: {:?} index {:?}", + p.name, p.index ); - } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) { + } else if p.is_set(ArgSettings::Required) && !p.is_set(ArgSettings::Last) { // Args that .last(true) don't count since they can be required and have // positionals with a lower index that aren't required // Imagine: prog [opt1] -- @@ -627,8 +349,8 @@ where } } } - if self.positionals.values().any(|p| { - p.b.is_set(ArgSettings::Last) && p.b.is_set(ArgSettings::Required) + if positionals!(self.app).any(|p| { + p.is_set(ArgSettings::Last) && p.is_set(ArgSettings::Required) }) && self.has_subcommands() && !self.is_set(AS::SubcommandsNegateReqs) { panic!( @@ -640,197 +362,39 @@ where true } - pub fn propagate_globals(&mut self) { - 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 - { - for a in &self.global_args { - sc.p.add_arg_ref(a); - } - } - sc.p.propagate_globals(); + // Does all the initializing and prepares the parser + fn build(&mut self) { + // Run debug assertions if in debug mode + debug_assert!(self.app_debug_asserts()); + + // Set the LowIndexMultiple flag if required + if positionals!(self.app).any(|a| { + a.is_set(ArgSettings::Multiple) && (a.index.unwrap_or(0) as usize != self.positionals.len()) + }) + && self.positionals.values() + .last() + .map_or(false, |p_name| + !find!(self.app, *p_name).expect(INTERNAL_ERROR_MSG).is_set(ArgSettings::Last)) + { + self.app.settings.set(AS::LowIndexMultiplePositional); + } + + for a in &mut self.app.args { + self.build_arg(a); + } + + for g in &self.app.groups { + self.build_group(g); } } +} - // Checks if the arg matches a subcommand name, or any of it's aliases (if defined) - fn possible_subcommand(&self, arg_os: &OsStr) -> (bool, Option<&str>) { - debugln!("Parser::possible_subcommand: arg={:?}", arg_os); - fn starts(h: &str, n: &OsStr) -> bool { - #[cfg(not(target_os = "windows"))] - use std::os::unix::ffi::OsStrExt; - #[cfg(target_os = "windows")] - use osstringext::OsStrExt3; - - let n_bytes = n.as_bytes(); - let h_bytes = OsStr::new(h).as_bytes(); - - h_bytes.starts_with(n_bytes) - } - - if self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound) { - return (false, None); - } - if !self.is_set(AS::InferSubcommands) { - if let Some(sc) = find_subcmd!(self, arg_os) { - return (true, Some(&sc.p.meta.name)); - } - } else { - let v = self.subcommands - .iter() - .filter(|s| { - starts(&s.p.meta.name[..], &*arg_os) - || (s.p.meta.aliases.is_some() - && s.p - .meta - .aliases - .as_ref() - .unwrap() - .iter() - .filter(|&&(a, _)| starts(a, &*arg_os)) - .count() == 1) - }) - .map(|sc| &sc.p.meta.name) - .collect::>(); - - if v.len() == 1 { - return (true, Some(v[0])); - } - } - (false, None) - } - - fn parse_help_subcommand(&self, it: &mut I) -> ClapResult> - where - I: Iterator, - T: Into, - { - debugln!("Parser::parse_help_subcommand;"); - let cmds: Vec = it.map(|c| c.into()).collect(); - let mut help_help = false; - let mut bin_name = self.meta - .bin_name - .as_ref() - .unwrap_or(&self.meta.name) - .clone(); - let mut sc = { - let mut sc: &Parser = self; - for (i, cmd) in cmds.iter().enumerate() { - if &*cmd.to_string_lossy() == "help" { - // cmd help help - help_help = true; - } - if let Some(c) = sc.subcommands - .iter() - .find(|s| &*s.p.meta.name == cmd) - .map(|sc| &sc.p) - { - sc = c; - if i == cmds.len() - 1 { - break; - } - } else if let Some(c) = sc.subcommands - .iter() - .find(|s| { - if let Some(ref als) = s.p.meta.aliases { - als.iter().any(|&(a, _)| a == &*cmd.to_string_lossy()) - } else { - false - } - }) - .map(|sc| &sc.p) - { - sc = c; - if i == cmds.len() - 1 { - break; - } - } else { - return Err(Error::unrecognized_subcommand( - cmd.to_string_lossy().into_owned(), - self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), - self.color(), - )); - } - bin_name = format!("{} {}", bin_name, &*sc.meta.name); - } - sc.clone() - }; - if help_help { - let mut pb = PosBuilder::new("subcommand", 1); - pb.b.help = Some("The subcommand whose help message to display"); - pb.set(ArgSettings::Multiple); - sc.positionals.insert(1, pb); - sc.settings = sc.settings | self.g_settings; - } else { - sc.create_help_and_version(); - } - if sc.meta.bin_name != self.meta.bin_name { - sc.meta.bin_name = Some(format!("{} {}", bin_name, sc.meta.name)); - } - Err(sc._help(false)) - } - - // allow wrong self convention due to self.valid_neg_num = true and it's a private method - #[cfg_attr(feature = "lints", allow(wrong_self_convention))] - fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult) -> bool { - debugln!( "Parser::is_new_arg:{:?}:{:?}", arg_os, needs_val_of); - let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) { - true - } else if self.is_set(AS::AllowNegativeNumbers) { - let a = arg_os.to_string_lossy(); - if a.parse::().is_ok() || a.parse::().is_ok() { - self.set(AS::ValidNegNumFound); - true - } else { - false - } - } else { - false - }; - let arg_allows_tac = match needs_val_of { - ParseResult::Opt(name) => { - let o = self.opts - .iter() - .find(|o| o.b.name == name) - .expect(INTERNAL_ERROR_MSG); - (o.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings) - } - ParseResult::Pos(name) => { - let p = self.positionals - .values() - .find(|p| p.b.name == name) - .expect(INTERNAL_ERROR_MSG); - (p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings) - } - ParseResult::ValuesDone => return true, - _ => false, - }; - debugln!( "Parser::is_new_arg: arg_allows_tac={:?}", arg_allows_tac ); - - // Is this a new argument, or values from a previous option? - let mut ret = if arg_os.starts_with(b"--") { - debugln!("Parser::is_new_arg: -- found"); - if arg_os.len_() == 2 && !arg_allows_tac { - return true; // We have to return true so override everything else - } else if arg_allows_tac { - return false; - } - true - } else if arg_os.starts_with(b"-") { - debugln!("Parser::is_new_arg: - found"); - // a singe '-' by itself is a value and typically means "stdin" on unix systems - !(arg_os.len_() == 1) - } else { - debugln!("Parser::is_new_arg: probably value"); - false - }; - - ret = ret && !arg_allows_tac; - - debugln!("Parser::is_new_arg: starts_new_arg={:?}", ret); - ret - } - +// Parsing Methods +impl<'a, 'b, 'c> Parser<'a, 'b, 'c> +where + 'a: 'b, + 'b: 'c, +{ // The actual parsing function #[cfg_attr(feature = "lints", allow(while_let_on_iterator, collapsible_if))] pub fn get_matches_with( @@ -844,22 +408,9 @@ where { debugln!("Parser::get_matches_with;"); // Verify all positional assertions pass - debug_assert!(self.app_debug_asserts()); - if self.positionals.values().any(|a| { - a.b.is_set(ArgSettings::Multiple) && (a.index as usize != self.positionals.len()) - }) - && self.positionals - .values() - .last() - .map_or(false, |p| !p.is_set(ArgSettings::Last)) - { - self.settings.set(AS::LowIndexMultiplePositional); - } - let has_args = self.has_args(); + self.build(); - // Next we create the `--help` and `--version` arguments and add them if - // necessary - self.create_help_and_version(); + let has_args = self.has_args(); let mut subcmd_name: Option = None; let mut needs_val_of: ParseResult<'a> = ParseResult::NotFound; @@ -908,7 +459,7 @@ where if starts_new_arg { { - let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); + let any_arg = find!(self.app, self.cache.unwrap_or("")); matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required); } @@ -936,11 +487,11 @@ where if !(arg_os.to_string_lossy().parse::().is_ok() || arg_os.to_string_lossy().parse::().is_ok()) { - return Err(Error::unknown_argument( + return Err(ClapError::unknown_argument( &*arg_os.to_string_lossy(), "", - &*usage::create_error_usage(self, matcher, None), - self.color(), + &*Usage::new(self).create_error_usage(matcher, None), + self.app.color(), )); } }, @@ -954,11 +505,9 @@ where } else { if let ParseResult::Opt(name) = needs_val_of { // Check to see if parsing a value from a previous arg - let arg = self.opts - .iter() - .find(|o| o.b.name == name) + let arg = find!(self.app, name) .expect(INTERNAL_ERROR_MSG); - // get the OptBuilder so we can check the settings + // get the option so we can check the settings needs_val_of = self.add_val_to_arg(arg, &arg_os, matcher)?; // get the next value from the iterator continue; @@ -969,13 +518,13 @@ where if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound)) && !self.is_set(AS::InferSubcommands) { - if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self)) { - return Err(Error::invalid_subcommand( + if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self.app)) { + return Err(ClapError::invalid_subcommand( arg_os.to_string_lossy().into_owned(), cdate, - self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), - &*usage::create_error_usage(self, matcher, None), - self.color(), + self.app.bin_name.as_ref().unwrap_or(&self.app.name), + &*Usage::new(self).create_error_usage(matcher, None), + self.app.color(), )); } } @@ -996,8 +545,8 @@ where if let Some(na) = it.peek() { let n = (*na).clone().into(); needs_val_of = if needs_val_of != ParseResult::ValuesDone { - if let Some(p) = self.positionals.get(pos_counter) { - ParseResult::Pos(p.b.name) + if let Some(p) = positionals!(self.app).find(|p| p.index == Some(pos_counter as u64)) { + ParseResult::Pos(p.name) } else { ParseResult::ValuesDone } @@ -1006,7 +555,7 @@ where }; let sc_match = { self.possible_subcommand(&n).0 }; if self.is_new_arg(&n, needs_val_of) || sc_match - || suggestions::did_you_mean(&n.to_string_lossy(), sc_names!(self)) + || suggestions::did_you_mean(&n.to_string_lossy(), sc_names!(self.app)) .is_some() { debugln!("Parser::get_matches_with: Bumping the positional counter..."); @@ -1022,48 +571,48 @@ where debugln!("Parser::get_matches_with: .last(true) and --, setting last pos"); pos_counter = self.positionals.len(); } - if let Some(p) = self.positionals.get(pos_counter) { + if let Some(p) = positionals!(self.app).find(|p| p.index == Some(pos_counter as u64)) { if p.is_set(ArgSettings::Last) && !self.is_set(AS::TrailingValues) { - return Err(Error::unknown_argument( + return Err(ClapError::unknown_argument( &*arg_os.to_string_lossy(), "", - &*usage::create_error_usage(self, matcher, None), - self.color(), + &*Usage::new(self).create_error_usage(matcher, None), + self.app.color(), )); } if !self.is_set(AS::TrailingValues) && (self.is_set(AS::TrailingVarArg) && pos_counter == self.positionals.len()) { - self.settings.set(AS::TrailingValues); + self.app.settings.set(AS::TrailingValues); } - if self.cache.map_or(true, |name| name != p.b.name) { + if self.cache.map_or(true, |name| name != p.name) { { - let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); + let any_arg = find!(self.app, self.cache.unwrap_or("")); matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required); } - self.cache = Some(p.b.name); + self.cache = Some(p.name); } let _ = self.add_val_to_arg(p, &arg_os, matcher)?; - matcher.inc_occurrence_of(p.b.name); - let _ = self.groups_for_arg(p.b.name) + matcher.inc_occurrence_of(p.name); + let _ = self.groups_for_arg(p.name) .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); - self.settings.set(AS::ValidArgFound); + self.app.settings.set(AS::ValidArgFound); // Only increment the positional counter if it doesn't allow multiples - if !p.b.settings.is_set(ArgSettings::Multiple) { + if !p.settings.is_set(ArgSettings::Multiple) { pos_counter += 1; } - self.settings.set(AS::ValidArgFound); + self.app.settings.set(AS::ValidArgFound); } else if self.is_set(AS::AllowExternalSubcommands) { // Get external subcommand name let sc_name = match arg_os.to_str() { Some(s) => s.to_string(), None => { if !self.is_set(AS::StrictUtf8) { - return Err(Error::invalid_utf8( - &*usage::create_error_usage(self, matcher, None), - self.color(), + return Err(ClapError::invalid_utf8( + &*Usage::new(self).create_error_usage(matcher, None), + self.app.color(), )); } arg_os.to_string_lossy().into_owned() @@ -1075,9 +624,9 @@ where while let Some(v) = it.next() { let a = v.into(); if a.to_str().is_none() && !self.is_set(AS::StrictUtf8) { - return Err(Error::invalid_utf8( - &*usage::create_error_usage(self, matcher, None), - self.color(), + return Err(ClapError::invalid_utf8( + &*Usage::new(self).create_error_usage(matcher, None), + self.app.color(), )); } sc_m.add_val_to("", &a); @@ -1092,62 +641,60 @@ where && arg_os.starts_with(b"-")) && !self.is_set(AS::InferSubcommands) { - return Err(Error::unknown_argument( + return Err(ClapError::unknown_argument( &*arg_os.to_string_lossy(), "", - &*usage::create_error_usage(self, matcher, None), - self.color(), + &*Usage::new(self).create_error_usage(matcher, None), + self.app.color(), )); } else if !has_args || self.is_set(AS::InferSubcommands) && self.has_subcommands() { if let Some(cdate) = - suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self)) + suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self.app)) { - return Err(Error::invalid_subcommand( + return Err(ClapError::invalid_subcommand( arg_os.to_string_lossy().into_owned(), cdate, - self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), - &*usage::create_error_usage(self, matcher, None), - self.color(), + self.app.bin_name.as_ref().unwrap_or(&self.app.name), + &*Usage::new(self).create_error_usage(matcher, None), + self.app.color(), )); } else { - return Err(Error::unrecognized_subcommand( + return Err(ClapError::unrecognized_subcommand( arg_os.to_string_lossy().into_owned(), - self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), - self.color(), + self.app.bin_name.as_ref().unwrap_or(&self.app.name), + self.app.color(), )); } } else { - return Err(Error::unknown_argument( + return Err(ClapError::unknown_argument( &*arg_os.to_string_lossy(), "", - &*usage::create_error_usage(self, matcher, None), - self.color(), + &*Usage::new(self).create_error_usage(matcher, None), + self.app.color(), )); } } if let Some(ref pos_sc_name) = subcmd_name { let sc_name = { - find_subcmd!(self, pos_sc_name) + find_subcmd!(self.app, pos_sc_name) .expect(INTERNAL_ERROR_MSG) - .p - .meta .name .clone() }; self.parse_subcommand(&*sc_name, matcher, it)?; } else if self.is_set(AS::SubcommandRequired) { - let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name); - return Err(Error::missing_subcommand( + let bn = self.app.bin_name.as_ref().unwrap_or(&self.app.name); + return Err(ClapError::missing_subcommand( bn, - &usage::create_error_usage(self, matcher, None), - self.color(), + &Usage::new(self).create_error_usage(matcher, None), + self.app.color(), )); } else if self.is_set(AS::SubcommandRequiredElseHelp) { debugln!("Parser::get_matches_with: SubcommandRequiredElseHelp=true"); let mut out = vec![]; self.write_help_err(&mut out)?; - return Err(Error { + return Err(ClapError { message: String::from_utf8_lossy(&*out).into_owned(), kind: ErrorKind::MissingArgumentOrSubcommand, info: None, @@ -1156,7 +703,7 @@ where // In case the last arg was new, we need to process it's overrides { - let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); + let any_arg = find!(self.app, self.cache.unwrap_or("")); matcher.process_arg_overrides(any_arg, &mut self.overrides, &mut self.required); } @@ -1165,6 +712,156 @@ where Validator::new(self).validate(needs_val_of, subcmd_name, matcher) } + // Checks if the arg matches a subcommand name, or any of it's aliases (if defined) + fn possible_subcommand(&self, arg_os: &OsStr) -> (bool, Option<&str>) { + debugln!("Parser::possible_subcommand: arg={:?}", arg_os); + fn starts(h: &str, n: &OsStr) -> bool { + #[cfg(not(target_os = "windows"))] + use std::os::unix::ffi::OsStrExt; + #[cfg(target_os = "windows")] + use osstringext::OsStrExt3; + + let n_bytes = n.as_bytes(); + let h_bytes = OsStr::new(h).as_bytes(); + + h_bytes.starts_with(n_bytes) + } + + if self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound) { + return (false, None); + } + if !self.is_set(AS::InferSubcommands) { + if let Some(sc) = find_subcmd!(self.app, arg_os) { + return (true, Some(&sc.name)); + } + } else { + let v = sc_names!(self.app) + .filter(|s| starts(s, &*arg_os)) + .collect::>(); + + if v.len() == 1 { + return (true, Some(v[0])); + } + } + (false, None) + } + + fn parse_help_subcommand(&self, it: &mut I) -> ClapResult> + where + I: Iterator, + T: Into, + { + debugln!("Parser::parse_help_subcommand;"); + let cmds: Vec = it.map(|c| c.into()).collect(); + let mut help_help = false; + let mut bin_name = self.app.bin_name.as_ref().unwrap_or(&self.app.name).clone(); + let mut sc = { + // @TODO @perf: cloning all these Apps ins't great, but since it's just displaying the help + // message there are bigger fish to fry + let mut sc = self.app.clone(); + for (i, cmd) in cmds.iter().enumerate() { + if &*cmd.to_string_lossy() == "help" { + // cmd help help + help_help = true; + break; // Maybe? + } + if let Some(c) = find_subcmd!(sc, cmd) + { + sc = c; + if i == cmds.len() - 1 { + break; + } + } else if let Some(c) = find_subcmd!(sc, &*cmd.to_string_lossy()) { + sc = c; + if i == cmds.len() - 1 { + break; + } + } else { + return Err(ClapError::unrecognized_subcommand( + cmd.to_string_lossy().into_owned(), + self.app.bin_name.as_ref().unwrap_or(&self.app.name), + self.app.color(), + )); + } + bin_name = format!("{} {}", bin_name, &*sc.name); + } + sc + }; + let mut parser = Parser::new(&mut sc); + if help_help { + let mut pb = Arg::with_name("subcommand") + .index(1) + .set(ArgSettings::Multiple) + .help("The subcommand whose help message to display"); + pb._build(); + parser.positionals.insert(1, pb.name); + parser.app.settings = parser.app.settings | self.app.g_settings; + parser.app.g_settings = self.app.g_settings; + } + if parser.app.bin_name != self.app.bin_name { + parser.app.bin_name = Some(format!("{} {}", bin_name, parser.app.name)); + } + Err(parser.help_err(false)) + } + + // allow wrong self convention due to self.valid_neg_num = true and it's a private method + #[cfg_attr(feature = "lints", allow(wrong_self_convention))] + fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult) -> bool { + debugln!( "Parser::is_new_arg:{:?}:{:?}", arg_os, needs_val_of); + let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) { + true + } else if self.is_set(AS::AllowNegativeNumbers) { + let a = arg_os.to_string_lossy(); + if a.parse::().is_ok() || a.parse::().is_ok() { + self.set(AS::ValidNegNumFound); + true + } else { + false + } + } else { + false + }; + let arg_allows_tac = match needs_val_of { + ParseResult::Opt(name) => { + let o = find!(self.app, name) + .expect(INTERNAL_ERROR_MSG); + (o.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings) + } + ParseResult::Pos(name) => { + let p = find!(self.app, name) + .expect(INTERNAL_ERROR_MSG); + (p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings) + } + ParseResult::ValuesDone => return true, + _ => false, + }; + debugln!( "Parser::is_new_arg: arg_allows_tac={:?}", arg_allows_tac ); + + // Is this a new argument, or values from a previous option? + let mut ret = if arg_os.starts_with(b"--") { + debugln!("Parser::is_new_arg: -- found"); + if arg_os.len_() == 2 && !arg_allows_tac { + return true; // We have to return true so override everything else + } else if arg_allows_tac { + return false; + } + true + } else if arg_os.starts_with(b"-") { + debugln!("Parser::is_new_arg: - found"); + // a singe '-' by itself is a value and typically means "stdin" on unix systems + !(arg_os.len_() == 1) + } else { + debugln!("Parser::is_new_arg: probably value"); + false + }; + + ret = ret && !arg_allows_tac; + + debugln!("Parser::is_new_arg: starts_new_arg={:?}", ret); + ret + } + + fn remove_overrides(&mut self, matcher: &mut ArgMatcher) { debugln!("Parser::remove_overrides:{:?};", self.overrides); for &(overr, name) in &self.overrides { @@ -1183,50 +880,6 @@ where } } - fn propagate_help_version(&mut self) { - debugln!("Parser::propagate_help_version;"); - self.create_help_and_version(); - for sc in &mut self.subcommands { - sc.p.propagate_help_version(); - } - } - - fn build_bin_names(&mut self) { - debugln!("Parser::build_bin_names;"); - for sc in &mut self.subcommands { - debug!("Parser::build_bin_names:iter: bin_name set..."); - if sc.p.meta.bin_name.is_none() { - sdebugln!("No"); - let bin_name = format!( - "{}{}{}", - self.meta - .bin_name - .as_ref() - .unwrap_or(&self.meta.name.clone()), - if self.meta.bin_name.is_some() { - " " - } else { - "" - }, - &*sc.p.meta.name - ); - debugln!( - "Parser::build_bin_names:iter: Setting bin_name of {} to {}", - self.meta.name, - bin_name - ); - sc.p.meta.bin_name = Some(bin_name); - } else { - sdebugln!("yes ({:?})", sc.p.meta.bin_name); - } - debugln!( - "Parser::build_bin_names:iter: Calling build_bin_names from...{}", - sc.p.meta.name - ); - sc.p.build_bin_names(); - } - } - fn parse_subcommand( &mut self, sc_name: &str, @@ -1245,180 +898,53 @@ where for k in matcher.arg_names() { hs.push(k); } - let reqs = usage::get_required_usage_from(self, &hs, Some(matcher), None, false); + let reqs = Usage::new(self).get_required_usage_from(&hs, Some(matcher), None, false); for s in &reqs { write!(&mut mid_string, " {}", s).expect(INTERNAL_ERROR_MSG); } } mid_string.push_str(" "); - if let Some(ref mut sc) = self.subcommands - .iter_mut() - .find(|s| s.p.meta.name == sc_name) + if let Some(ref mut sc) = subcommands_mut!(self.app) + .find(|s| s.name == sc_name) { let mut sc_matcher = ArgMatcher::new(); // bin_name should be parent's bin_name + [] + the sc's name separated by // a space - sc.p.meta.usage = Some(format!( + sc.usage = Some(format!( "{}{}{}", - self.meta.bin_name.as_ref().unwrap_or(&String::new()), - if self.meta.bin_name.is_some() { + self.app.bin_name.as_ref().unwrap_or(&String::new()), + if self.app.bin_name.is_some() { &*mid_string } else { "" }, - &*sc.p.meta.name + &*sc.name )); - sc.p.meta.bin_name = Some(format!( + sc.bin_name = Some(format!( "{}{}{}", - self.meta.bin_name.as_ref().unwrap_or(&String::new()), - if self.meta.bin_name.is_some() { + self.app.bin_name.as_ref().unwrap_or(&String::new()), + if self.app.bin_name.is_some() { " " } else { "" }, - &*sc.p.meta.name + &*sc.name )); debugln!( "Parser::parse_subcommand: About to parse sc={}", - sc.p.meta.name + sc.name ); - debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings); - sc.p.get_matches_with(&mut sc_matcher, it)?; + debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.settings); + sc.get_matches_with(&mut sc_matcher, it)?; matcher.subcommand(SubCommand { - name: sc.p.meta.name.clone(), + name: sc.name.clone(), matches: sc_matcher.into(), }); } Ok(()) } - pub fn groups_for_arg(&self, name: &str) -> Option> { - debugln!("Parser::groups_for_arg: name={}", name); - - if self.groups.is_empty() { - debugln!("Parser::groups_for_arg: No groups defined"); - return None; - } - let mut res = vec![]; - debugln!("Parser::groups_for_arg: Searching through groups..."); - for grp in &self.groups { - for a in &grp.args { - if a == &name { - sdebugln!("\tFound '{}'", grp.name); - res.push(&*grp.name); - } - } - } - if res.is_empty() { - return None; - } - - Some(res) - } - - pub fn args_in_group(&self, group: &str) -> Vec { - let mut g_vec = vec![]; - let mut args = vec![]; - - for n in &self.groups - .iter() - .find(|g| g.name == group) - .expect(INTERNAL_ERROR_MSG) - .args - { - if let Some(f) = self.flags.iter().find(|f| &f.b.name == n) { - args.push(f.to_string()); - } else if let Some(f) = self.opts.iter().find(|o| &o.b.name == n) { - args.push(f.to_string()); - } else if let Some(p) = self.positionals.values().find(|p| &p.b.name == n) { - args.push(p.b.name.to_owned()); - } else { - g_vec.push(*n); - } - } - - for av in g_vec.iter().map(|g| self.args_in_group(g)) { - args.extend(av); - } - args.dedup(); - args.iter().map(ToOwned::to_owned).collect() - } - - pub fn arg_names_in_group(&self, group: &str) -> Vec<&'a str> { - let mut g_vec = vec![]; - let mut args = vec![]; - - for n in &self.groups - .iter() - .find(|g| g.name == group) - .expect(INTERNAL_ERROR_MSG) - .args - { - if self.groups.iter().any(|g| g.name == *n) { - args.extend(self.arg_names_in_group(n)); - g_vec.push(*n); - } else if !args.contains(n) { - args.push(*n); - } - } - - args.iter().map(|s| *s).collect() - } - - pub fn create_help_and_version(&mut self) { - debugln!("Parser::create_help_and_version;"); - // name is "hclap_help" because flags are sorted by name - if !self.contains_long("help") { - debugln!("Parser::create_help_and_version: Building --help"); - if self.help_short.is_none() && !self.contains_short('h') { - self.help_short = Some('h'); - } - let arg = FlagBuilder { - b: Base { - name: "hclap_help", - help: self.help_message.or(Some("Prints help information")), - ..Default::default() - }, - s: Switched { - short: self.help_short, - long: Some("help"), - ..Default::default() - }, - }; - self.flags.push(arg); - } - if !self.is_set(AS::DisableVersion) && !self.contains_long("version") { - debugln!("Parser::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 = FlagBuilder { - b: Base { - name: "vclap_version", - help: self.version_message.or(Some("Prints version information")), - ..Default::default() - }, - s: Switched { - short: self.version_short, - long: Some("version"), - ..Default::default() - }, - }; - self.flags.push(arg); - } - if !self.subcommands.is_empty() && !self.is_set(AS::DisableHelpSubcommand) - && self.is_set(AS::NeedsSubcommandHelp) - { - debugln!("Parser::create_help_and_version: Building help"); - self.subcommands.push( - App::new("help") - .about("Prints this message or the help of the given subcommand(s)"), - ); - } - } - // Retrieves the names of all args the user has supplied thus far, except required ones // because those will be listed in self.required fn check_for_help_and_version_str(&self, arg: &OsStr) -> ClapResult<()> { @@ -1429,11 +955,11 @@ where ); if arg == "help" && self.is_set(AS::NeedsLongHelp) { sdebugln!("Help"); - return Err(self._help(true)); + return Err(self.help_err(true)); } if arg == "version" && self.is_set(AS::NeedsLongVersion) { sdebugln!("Version"); - return Err(self._version(true)); + return Err(self.version_err(true)); } sdebugln!("Neither"); @@ -1446,59 +972,22 @@ where "Parser::check_for_help_and_version_char: Checking if -{} is help or version...", arg ); - if let Some(h) = self.help_short { + if let Some(h) = self.app.help_short { if arg == h && self.is_set(AS::NeedsLongHelp) { sdebugln!("Help"); - return Err(self._help(false)); + return Err(self.help_err(false)); } } - if let Some(v) = self.version_short { + if let Some(v) = self.app.version_short { if arg == v && self.is_set(AS::NeedsLongVersion) { sdebugln!("Version"); - return Err(self._version(false)); + return Err(self.version_err(false)); } } sdebugln!("Neither"); Ok(()) } - fn use_long_help(&self) -> bool { - self.meta.long_about.is_some() || self.flags.iter().any(|f| f.b.long_help.is_some()) - || self.opts.iter().any(|o| o.b.long_help.is_some()) - || self.positionals.values().any(|p| p.b.long_help.is_some()) - || self.subcommands - .iter() - .any(|s| s.p.meta.long_about.is_some()) - } - - fn _help(&self, mut use_long: bool) -> Error { - debugln!("Parser::_help: use_long={:?}", use_long); - use_long = use_long && self.use_long_help(); - let mut buf = vec![]; - match Help::write_parser_help(&mut buf, self, use_long) { - Err(e) => e, - _ => Error { - message: String::from_utf8(buf).unwrap_or_default(), - kind: ErrorKind::HelpDisplayed, - info: None, - }, - } - } - - fn _version(&self, use_long: bool) -> Error { - debugln!("Parser::_version: "); - let out = io::stdout(); - let mut buf_w = BufWriter::new(out.lock()); - match self.print_version(&mut buf_w, use_long) { - Err(e) => e, - _ => Error { - message: String::new(), - kind: ErrorKind::VersionDisplayed, - info: None, - }, - } - } - fn parse_long_arg( &mut self, matcher: &mut ArgMatcher<'a>, @@ -1518,24 +1007,24 @@ where full_arg.trim_left_matches(b'-') }; - if let Some(opt) = find_opt_by_long!(@os self, arg) { + if let Some(opt) = find_by_long!(self.app, arg) { debugln!( "Parser::parse_long_arg: Found valid opt '{}'", opt.to_string() ); - self.settings.set(AS::ValidArgFound); + self.app.settings.set(AS::ValidArgFound); let ret = self.parse_opt(val, opt, val.is_some(), matcher)?; - if self.cache.map_or(true, |name| name != opt.b.name) { - self.cache = Some(opt.b.name); + if self.cache.map_or(true, |name| name != opt.name) { + self.cache = Some(opt.name); } return Ok(ret); - } else if let Some(flag) = find_flag_by_long!(@os self, arg) { + } else if let Some(flag) = find_by_long!(self.app, arg) { debugln!( "Parser::parse_long_arg: Found valid flag '{}'", flag.to_string() ); - self.settings.set(AS::ValidArgFound); + self.app.settings.set(AS::ValidArgFound); // Only flags could be help or version, and we need to check the raw long // so this is the first point to check self.check_for_help_and_version_str(arg)?; @@ -1543,8 +1032,8 @@ where self.parse_flag(flag, matcher)?; // Handle conflicts, requirements, etc. - if self.cache.map_or(true, |name| name != flag.b.name) { - self.cache = Some(flag.b.name); + if self.cache.map_or(true, |name| name != flag.name) { + self.cache = Some(flag.name); } return Ok(ParseResult::Flag); @@ -1593,9 +1082,9 @@ where // concatenated value: -oval // Option: -o // Value: val - if let Some(opt) = find_opt_by_short!(self, c) { + if let Some(opt) = find_by_short!(self.app, c) { debugln!("Parser::parse_short_arg:iter:{}: Found valid opt", c); - self.settings.set(AS::ValidArgFound); + self.app.settings.set(AS::ValidArgFound); // Check for trailing concatenated value let p: Vec<_> = arg.splitn(2, c).collect(); debugln!( @@ -1620,30 +1109,30 @@ where // Default to "we're expecting a value later" let ret = self.parse_opt(val, opt, false, matcher)?; - if self.cache.map_or(true, |name| name != opt.b.name) { - self.cache = Some(opt.b.name); + if self.cache.map_or(true, |name| name != opt.name) { + self.cache = Some(opt.name); } return Ok(ret); - } else if let Some(flag) = find_flag_by_short!(self, c) { + } else if let Some(flag) = find_by_short!(self.app, c) { debugln!("Parser::parse_short_arg:iter:{}: Found valid flag", c); - self.settings.set(AS::ValidArgFound); + self.app.settings.set(AS::ValidArgFound); // Only flags can be help or version self.check_for_help_and_version_char(c)?; ret = self.parse_flag(flag, matcher)?; // Handle conflicts, requirements, overrides, etc. // Must be called here due to mutablilty - if self.cache.map_or(true, |name| name != flag.b.name) { - self.cache = Some(flag.b.name); + if self.cache.map_or(true, |name| name != flag.name) { + self.cache = Some(flag.name); } } else { let arg = format!("-{}", c); - return Err(Error::unknown_argument( + return Err(ClapError::unknown_argument( &*arg, "", - &*usage::create_error_usage(self, matcher, None), - self.color(), + &*Usage::new(self).create_error_usage(matcher, None), + self.app.color(), )); } } @@ -1653,16 +1142,16 @@ where fn parse_opt( &self, val: Option<&OsStr>, - opt: &OptBuilder<'a, 'b>, + opt: &Arg<'a, 'b>, had_eq: bool, matcher: &mut ArgMatcher<'a>, ) -> ClapResult> { - debugln!("Parser::parse_opt; opt={}, val={:?}", opt.b.name, val); - debugln!("Parser::parse_opt; opt.settings={:?}", opt.b.settings); + debugln!("Parser::parse_opt; opt={}, val={:?}", opt.name, val); + debugln!("Parser::parse_opt; opt.settings={:?}", opt.settings); let mut has_eq = false; let no_val = val.is_none(); let empty_vals = opt.is_set(ArgSettings::EmptyValues); - let min_vals_zero = opt.v.min_vals.unwrap_or(1) == 0; + let min_vals_zero = opt.min_vals.unwrap_or(1) == 0; let needs_eq = opt.is_set(ArgSettings::RequireEquals); debug!("Parser::parse_opt; Checking for val..."); @@ -1671,10 +1160,10 @@ where let v = fv.trim_left_matches(b'='); if !empty_vals && (v.len_() == 0 || (needs_eq && !has_eq)) { sdebugln!("Found Empty - Error"); - return Err(Error::empty_value( + return Err(ClapError::empty_value( opt, - &*usage::create_error_usage(self, matcher, None), - self.color(), + &*Usage::new(self).create_error_usage(matcher, None), + self.app.color(), )); } sdebugln!("Found - {:?}, len: {}", v, v.len_()); @@ -1686,18 +1175,18 @@ where self.add_val_to_arg(opt, v, matcher)?; } else if needs_eq && !(empty_vals || min_vals_zero) { sdebugln!("None, but requires equals...Error"); - return Err(Error::empty_value( + return Err(ClapError::empty_value( opt, - &*usage::create_error_usage(self, matcher, None), - self.color(), + &*Usage::new(self).create_error_usage(matcher, None), + self.app.color(), )); } else { sdebugln!("None"); } - matcher.inc_occurrence_of(opt.b.name); + matcher.inc_occurrence_of(opt.name); // Increment or create the group "args" - self.groups_for_arg(opt.b.name) + self.groups_for_arg(opt.name) .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); let needs_delim = opt.is_set(ArgSettings::RequireDelimiter); @@ -1707,29 +1196,27 @@ where return Ok(ParseResult::ValuesDone); } else if no_val || (mult && !needs_delim) && !has_eq && matcher.needs_more_vals(opt) { debugln!("Parser::parse_opt: More arg vals required..."); - return Ok(ParseResult::Opt(opt.b.name)); + return Ok(ParseResult::Opt(opt.name)); } debugln!("Parser::parse_opt: More arg vals not required..."); Ok(ParseResult::ValuesDone) } - fn add_val_to_arg( + fn add_val_to_arg( &self, - arg: &A, + arg: &Arg<'a, 'b>, val: &OsStr, matcher: &mut ArgMatcher<'a>, ) -> ClapResult> - where - A: AnyArg<'a, 'b> + Display, { - debugln!("Parser::add_val_to_arg; arg={}, val={:?}", arg.name(), val); + debugln!("Parser::add_val_to_arg; arg={}, val={:?}", arg.name, val); debugln!( "Parser::add_val_to_arg; trailing_vals={:?}, DontDelimTrailingVals={:?}", self.is_set(AS::TrailingValues), self.is_set(AS::DontDelimitTrailingValues) ); if !(self.is_set(AS::TrailingValues) && self.is_set(AS::DontDelimitTrailingValues)) { - if let Some(delim) = arg.val_delim() { + if let Some(delim) = arg.val_delim { if val.is_empty_() { Ok(self.add_single_val_to_arg(arg, val, matcher)?) } else { @@ -1753,158 +1240,83 @@ where } } - fn add_single_val_to_arg( + fn add_single_val_to_arg( &self, - arg: &A, + arg: &Arg<'a, 'b>, v: &OsStr, matcher: &mut ArgMatcher<'a>, ) -> ClapResult> - where - A: AnyArg<'a, 'b> + Display, { debugln!("Parser::add_single_val_to_arg;"); debugln!("Parser::add_single_val_to_arg: adding val...{:?}", v); - if let Some(t) = arg.val_terminator() { + if let Some(t) = arg.terminator { if t == v { return Ok(ParseResult::ValuesDone); } } - matcher.add_val_to(arg.name(), v); + matcher.add_val_to(arg.name, v); // Increment or create the group "args" - if let Some(grps) = self.groups_for_arg(arg.name()) { + if let Some(grps) = self.groups_for_arg(arg.name) { for grp in grps { matcher.add_val_to(&*grp, v); } } if matcher.needs_more_vals(arg) { - return Ok(ParseResult::Opt(arg.name())); + return Ok(ParseResult::Opt(arg.name)); } Ok(ParseResult::ValuesDone) } - fn parse_flag( &self, - flag: &FlagBuilder<'a, 'b>, + flag: &Arg<'a, 'b>, matcher: &mut ArgMatcher<'a>, ) -> ClapResult> { debugln!("Parser::parse_flag;"); - matcher.inc_occurrence_of(flag.b.name); + matcher.inc_occurrence_of(flag.name); // Increment or create the group "args" - self.groups_for_arg(flag.b.name) + self.groups_for_arg(flag.name) .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); Ok(ParseResult::Flag) } - fn did_you_mean_error(&self, arg: &str, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { - // Didn't match a flag or option - let suffix = suggestions::did_you_mean_flag_suffix(arg, longs!(self), &self.subcommands); - - // Add the arg to the matches to build a proper usage string - if let Some(name) = suffix.1 { - if let Some(opt) = find_opt_by_long!(self, name) { - self.groups_for_arg(&*opt.b.name) - .and_then(|grps| Some(matcher.inc_occurrences_of(&*grps))); - matcher.insert(&*opt.b.name); - } else if let Some(flg) = find_flag_by_long!(self, name) { - self.groups_for_arg(&*flg.b.name) - .and_then(|grps| Some(matcher.inc_occurrences_of(&*grps))); - matcher.insert(&*flg.b.name); - } - } - - let used_arg = format!("--{}", arg); - Err(Error::unknown_argument( - &*used_arg, - &*suffix.0, - &*usage::create_error_usage(self, matcher, None), - self.color(), - )) - } - - // Prints the version to the user and exits if quit=true - fn print_version(&self, w: &mut W, use_long: bool) -> ClapResult<()> { - self.write_version(w, use_long)?; - w.flush().map_err(Error::from) - } - - pub fn write_version(&self, w: &mut W, use_long: bool) -> io::Result<()> { - let ver = if use_long { - self.meta - .long_version - .unwrap_or_else(|| self.meta.version.unwrap_or("")) - } else { - self.meta - .version - .unwrap_or_else(|| self.meta.long_version.unwrap_or("")) - }; - if let Some(bn) = self.meta.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.meta.name[..], ver) - } - } else { - write!(w, "{} {}", &self.meta.name[..], ver) - } - } - - pub fn print_help(&self) -> ClapResult<()> { - let out = io::stdout(); - let mut buf_w = BufWriter::new(out.lock()); - self.write_help(&mut buf_w) - } - - pub fn write_help(&self, w: &mut W) -> ClapResult<()> { - Help::write_parser_help(w, self, false) - } - - pub fn write_long_help(&self, w: &mut W) -> ClapResult<()> { - Help::write_parser_help(w, self, true) - } - - pub fn write_help_err(&self, w: &mut W) -> ClapResult<()> { - Help::write_parser_help_to_stderr(w, self) - } - pub fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { debugln!("Parser::add_defaults;"); macro_rules! add_val { (@default $_self:ident, $a:ident, $m:ident) => { - if let Some(ref val) = $a.v.default_val { - debugln!("Parser::add_defaults:iter:{}: has default vals", $a.b.name); - if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) { - debugln!("Parser::add_defaults:iter:{}: has no user defined vals", $a.b.name); + if let Some(ref val) = $a.default_val { + debugln!("Parser::add_defaults:iter:{}: has default vals", $a.name); + if $m.get($a.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) { + debugln!("Parser::add_defaults:iter:{}: has no user defined vals", $a.name); $_self.add_val_to_arg($a, OsStr::new(val), $m)?; - if $_self.cache.map_or(true, |name| name != $a.name()) { - $_self.cache = Some($a.name()); + if $_self.cache.map_or(true, |name| name != $a.name) { + $_self.cache = Some($a.name); } - } else if $m.get($a.b.name).is_some() { - debugln!("Parser::add_defaults:iter:{}: has user defined vals", $a.b.name); + } else if $m.get($a.name).is_some() { + debugln!("Parser::add_defaults:iter:{}: has user defined vals", $a.name); } else { - debugln!("Parser::add_defaults:iter:{}: wasn't used", $a.b.name); + debugln!("Parser::add_defaults:iter:{}: wasn't used", $a.name); $_self.add_val_to_arg($a, OsStr::new(val), $m)?; - if $_self.cache.map_or(true, |name| name != $a.name()) { - $_self.cache = Some($a.name()); + if $_self.cache.map_or(true, |name| name != $a.name) { + $_self.cache = Some($a.name); } } } else { - debugln!("Parser::add_defaults:iter:{}: doesn't have default vals", $a.b.name); + debugln!("Parser::add_defaults:iter:{}: doesn't have default vals", $a.name); } }; ($_self:ident, $a:ident, $m:ident) => { - if let Some(ref vm) = $a.v.default_vals_ifs { + if let Some(ref vm) = $a.default_vals_ifs { sdebugln!(" has conditional defaults"); let mut done = false; - if $m.get($a.b.name).is_none() { + if $m.get($a.name).is_none() { for &(arg, val, default) in vm.values() { let add = if let Some(a) = $m.get(arg) { if let Some(v) = val { @@ -1917,8 +1329,8 @@ where }; if add { $_self.add_val_to_arg($a, OsStr::new(default), $m)?; - if $_self.cache.map_or(true, |name| name != $a.name()) { - $_self.cache = Some($a.name()); + if $_self.cache.map_or(true, |name| name != $a.name) { + $_self.cache = Some($a.name); } done = true; break; @@ -1936,92 +1348,201 @@ where }; } - for o in &self.opts { - debug!("Parser::add_defaults:iter:{}:", o.b.name); + for o in opts!(self.app) { + debug!("Parser::add_defaults:iter:{}:", o.name); add_val!(self, o, matcher); } - for p in self.positionals.values() { - debug!("Parser::add_defaults:iter:{}:", p.b.name); + for p in positionals!(self.app) { + debug!("Parser::add_defaults:iter:{}:", p.name); add_val!(self, p, matcher); } Ok(()) } pub fn add_env(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { - macro_rules! add_val { - ($_self:ident, $a:ident, $m:ident) => { - if let Some(ref val) = $a.v.env { - if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) { - if let Some(ref val) = val.1 { - $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + for a in &self.app.args { + if let Some(ref val) = a.env { + if matcher.get(a.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) { + if let Some(ref val) = val.1 { + self.add_val_to_arg(a, OsStr::new(val), matcher)?; - if $_self.cache.map_or(true, |name| name != $a.name()) { - $_self.cache = Some($a.name()); - } + if self.cache.map_or(true, |name| name != a.name) { + self.cache = Some(a.name); } - } else { - if let Some(ref val) = val.1 { - $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + } + } else { + if let Some(ref val) = val.1 { + self.add_val_to_arg(a, OsStr::new(val), matcher)?; - if $_self.cache.map_or(true, |name| name != $a.name()) { - $_self.cache = Some($a.name()); - } + if self.cache.map_or(true, |name| name != a.name) { + self.cache = Some(a.name); } } } - }; - } - - for o in &self.opts { - add_val!(self, o, matcher); - } - for p in self.positionals.values() { - add_val!(self, p, matcher); + } } Ok(()) } +} - pub fn flags(&self) -> Iter> { self.flags.iter() } +// Error, Help, and Version Methods +impl<'a, 'b, 'c> Parser<'a, 'b, 'c> +where + 'a: 'b, + 'b: 'c, +{ + fn did_you_mean_error(&self, arg: &str, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { + // Didn't match a flag or option + let suffix = suggestions::did_you_mean_flag_suffix(arg, longs!(self.app), &*self.app.subcommands); - pub fn opts(&self) -> Iter> { self.opts.iter() } + // Add the arg to the matches to build a proper usage string + if let Some(name) = suffix.1 { + if let Some(opt) = find_by_long!(self.app, name) { + self.groups_for_arg(&*opt.name) + .and_then(|grps| Some(matcher.inc_occurrences_of(&*grps))); + matcher.insert(&*opt.name); + } else if let Some(flg) = find_by_long!(self.app, name) { + self.groups_for_arg(&*flg.name) + .and_then(|grps| Some(matcher.inc_occurrences_of(&*grps))); + matcher.insert(&*flg.name); + } + } - pub fn positionals(&self) -> map::Values> { self.positionals.values() } + let used_arg = format!("--{}", arg); + Err(ClapError::unknown_argument( + &*used_arg, + &*suffix.0, + &*Usage::new(self).create_error_usage(matcher, None), + self.app.color(), + )) + } - pub fn subcommands(&self) -> Iter { self.subcommands.iter() } + // Prints the version to the user and exits if quit=true + fn print_version(&self, w: &mut W, use_long: bool) -> ClapResult<()> { + self.app._write_version(w, use_long)?; + w.flush().map_err(ClapError::from) + } - // Should we color the output? None=determined by output location, true=yes, false=no - #[doc(hidden)] - pub fn color(&self) -> ColorWhen { - debugln!("Parser::color;"); - debug!("Parser::color: Color setting..."); - if self.is_set(AS::ColorNever) { - sdebugln!("Never"); - ColorWhen::Never - } else if self.is_set(AS::ColorAlways) { - sdebugln!("Always"); - ColorWhen::Always - } else { - sdebugln!("Auto"); - ColorWhen::Auto + pub fn print_help(&self) -> ClapResult<()> { + let out = io::stdout(); + let mut buf_w = BufWriter::new(out.lock()); + self.write_help(&mut buf_w) + } + + pub fn write_help(&self, w: &mut W) -> ClapResult<()> { + Help::write_parser_help(w, &self, false) + } + + pub fn write_long_help(&self, w: &mut W) -> ClapResult<()> { + Help::write_parser_help(w, &self, true) + } + + pub fn write_help_err(&self, w: &mut W) -> ClapResult<()> { + Help::write_parser_help_to_stderr(w, &self) + } + + fn help_err(&self, mut use_long: bool) -> ClapError { + debugln!("Parser::_help: use_long={:?}", use_long); + use_long = use_long && self.app.use_long_help(); + let mut buf = vec![]; + match Help::write_parser_help(&mut buf, self, use_long) { + Err(e) => e, + _ => ClapError { + message: String::from_utf8(buf).unwrap_or_default(), + kind: ErrorKind::HelpDisplayed, + info: None, + }, } } - pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg<'a, 'b>> { - if let Some(f) = find_by_name!(self, name, flags, iter) { - return Some(f); + fn version_err(&self, use_long: bool) -> ClapError { + debugln!("Parser::_version: "); + let out = io::stdout(); + let mut buf_w = BufWriter::new(out.lock()); + match self.print_version(&mut buf_w, use_long) { + Err(e) => e, + _ => ClapError { + message: String::new(), + kind: ErrorKind::VersionDisplayed, + info: None, + }, } - if let Some(o) = find_by_name!(self, name, opts, iter) { - return Some(o); + } + + +} + +// Query Methods +impl<'a, 'b, 'c> Parser<'a, 'b, 'c> +where + 'a: 'b, + 'b: 'c, +{ + pub fn groups_for_arg(&self, name: &str) -> Option> { + debugln!("Parser::groups_for_arg: name={}", name); + + if self.app.groups.is_empty() { + debugln!("Parser::groups_for_arg: No groups defined"); + return None; } - if let Some(p) = find_by_name!(self, name, positionals, values) { - return Some(p); + let mut res = vec![]; + debugln!("Parser::groups_for_arg: Searching through groups..."); + for grp in groups!(self.app) { + for a in &grp.args { + if a == &name { + sdebugln!("\tFound '{}'", grp.name); + res.push(&*grp.name); + } + } } - None + if res.is_empty() { + return None; + } + + Some(res) + } + + pub fn args_in_group(&self, group: &str) -> Vec { + let mut g_vec = vec![]; + let mut args = vec![]; + + for n in find!(self.app, group, groups).expect(INTERNAL_ERROR_MSG).args { + if let Some(f) = find!(self.app, n) { + args.push(f.to_string()); + } else { + g_vec.push(n); + } + } + + for av in g_vec.iter().map(|g| self.args_in_group(g)) { + args.extend(av); + } + args.dedup(); + args.iter().map(ToOwned::to_owned).collect() + } + + pub fn arg_names_in_group(&self, group: &str) -> Vec<&'a str> { + let mut g_vec = vec![]; + let mut args = vec![]; + + for n in find!(self.app, group, groups) + .expect(INTERNAL_ERROR_MSG) + .args + { + if groups!(self.app).any(|g| g.name == n) { + args.extend(self.arg_names_in_group(n)); + g_vec.push(n); + } else if !args.contains(&&n) { + args.push(n); + } + } + + args.iter().map(|s| *s).collect() } /// Check is a given string matches the binary name for this parser fn is_bin_name(&self, value: &str) -> bool { - self.meta + self.app .bin_name .as_ref() .and_then(|name| Some(value == name)) @@ -2030,7 +1551,7 @@ where /// Check is a given string is an alias for this parser fn is_alias(&self, value: &str) -> bool { - self.meta + self.app .aliases .as_ref() .and_then(|aliases| { @@ -2044,35 +1565,56 @@ where .unwrap_or(false) } - // Only used for completion scripts due to bin_name messiness - #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))] - pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> { - debugln!("Parser::find_subcommand: sc={}", sc); - debugln!( - "Parser::find_subcommand: Currently in Parser...{}", - self.meta.bin_name.as_ref().unwrap() - ); - for s in &self.subcommands { - if s.p.is_bin_name(sc) { - return Some(s); - } - // XXX: why do we split here? - // isn't `sc` supposed to be single word already? - let last = sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG); - if s.p.is_alias(last) { - return Some(s); - } + fn contains_long(&self, l: &str) -> bool { self.app.contains_long(l) } - if let Some(app) = s.p.find_subcommand(sc) { - return Some(app); - } - } - None + fn contains_short(&self, s: char) -> bool { self.app.contains_short(s) } + + pub fn required(&self) -> Iter<&str> { self.required.iter() } + + #[cfg_attr(feature = "lints", allow(needless_borrow))] + pub fn has_args(&self) -> bool { + self.app.has_args() + } + + pub fn has_opts(&self) -> bool { + self.app.has_opts() + } + + pub fn has_flags(&self) -> bool { + self.app.has_flags() + } + + pub fn has_positionals(&self) -> bool { + !self.positionals.is_empty() + } + + pub fn has_subcommands(&self) -> bool { + self.app.has_subcommands() + } + + pub fn has_visible_opts(&self) -> bool { + self.app.has_visible_opts() + } + + pub fn has_visible_flags(&self) -> bool { + self.app.has_visible_flags() + } + + pub fn has_visible_positionals(&self) -> bool { + self.app.has_visible_positionals() } #[inline] - fn contains_long(&self, l: &str) -> bool { longs!(self).any(|al| al == &l) } + pub fn has_visible_subcommands(&self) -> bool { + self.app.has_visible_subcommands() + } #[inline] - fn contains_short(&self, s: char) -> bool { shorts!(self).any(|arg_s| arg_s == &s) } + pub fn is_set(&self, s: AS) -> bool { self.app.is_set(s) } + + #[inline] + pub fn set(&mut self, s: AS) { self.app.set(s) } + + #[inline] + pub fn unset(&mut self, s: AS) { self.app.unset(s) } } diff --git a/src/app/usage.rs b/src/app/usage.rs index 60905884..9b165ec1 100644 --- a/src/app/usage.rs +++ b/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(" "); - } else { - usage.push_str("\n "); - usage.push_str(&*name); - usage.push_str(" "); - } - } else if p.is_set(AS::SubcommandRequired) || p.is_set(AS::SubcommandRequiredElseHelp) { - usage.push_str(" "); - } 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(" "); - } - 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 { - 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::>() - .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(" "); } else { - None + usage.push_str("\n "); + usage.push_str(&*name); + usage.push_str(" "); } - }) - .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(" "); + } 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(" "); + } + usage.shrink_to_fit(); + usage + } + + // Gets the `[ARGS]` tag for the usage string + fn get_args_tag(&self, incl_reqs: bool) -> Option { + 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::>() + .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::>() - .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::>() + .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 { - 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 { + 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::>(); + + 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::>() // 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::>() // 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::>(); - - 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::>() // 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 = 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::>() // 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 = 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 + } } diff --git a/src/app/validator.rs b/src/app/validator.rs index 9751321a..3a1503b0 100644 --- a/src/app/validator.rs +++ b/src/app/validator.rs @@ -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( + 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( + 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( + 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( + 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 { - debugln!("Validator::validate_arg_conflicts: a={:?};", a.name()); - a.blacklist().map(|bl| { + fn validate_arg_conflicts(&self, a: &Arg, matcher: &ArgMatcher) -> Option { + 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 { - debugln!("Validator::validate_required_unless: a={:?};", a.name()); + fn validate_required_unless(&self, a: &Arg, matcher: &ArgMatcher) -> Option { + 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::>(); 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) } diff --git a/src/args/any_arg.rs b/src/args/any_arg.rs deleted file mode 100644 index eee52283..00000000 --- a/src/args/any_arg.rs +++ /dev/null @@ -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>; - 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; - fn min_vals(&self) -> Option; - fn num_vals(&self) -> Option; - fn possible_vals(&self) -> Option<&[&'e str]>; - fn validator(&self) -> Option<&Rc Result<(), String>>>; - fn validator_os(&self) -> Option<&Rc Result<(), OsString>>>; - fn short(&self) -> Option; - fn long(&self) -> Option<&'e str>; - fn val_delim(&self) -> Option; - 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, &'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> { (*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 { (*self).max_vals() } - fn min_vals(&self) -> Option { (*self).min_vals() } - fn num_vals(&self) -> Option { (*self).num_vals() } - fn possible_vals(&self) -> Option<&[&'e str]> { (*self).possible_vals() } - fn validator(&self) -> Option<&Rc Result<(), String>>> { (*self).validator() } - fn validator_os(&self) -> Option<&Rc Result<(), OsString>>> { (*self).validator_os() } - fn short(&self) -> Option { (*self).short() } - fn long(&self) -> Option<&'e str> { (*self).long() } - fn val_delim(&self) -> Option { (*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, &'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() } -} diff --git a/src/args/arg.rs b/src/args/arg.rs index bdcd63a5..520875e7 100644 --- a/src/args/arg.rs +++ b/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>, + pub settings: ArgFlags, + pub r_unless: Option>, + pub overrides: Option>, + pub groups: Option>, + pub requires: Option, &'a str)>>, + pub short: Option, + pub long: Option<&'b str>, + pub aliases: Option>, // (name, visible) + pub disp_ord: usize, + pub unified_ord: usize, + pub possible_vals: Option>, + pub val_names: Option>, + pub num_vals: Option, + pub max_vals: Option, + pub min_vals: Option, + pub validator: Option Result<(), String>>>, + pub validator_os: Option Result<(), OsString>>>, + pub val_delim: Option, + pub default_val: Option<&'b OsStr>, + pub default_vals_ifs: Option, &'b OsStr)>>, + pub env: Option<(&'a OsStr, Option)>, + pub terminator: Option<&'b str>, #[doc(hidden)] pub index: Option, #[doc(hidden)] pub r_ifs: Option>, } @@ -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>(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>(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::>()); + self.aliases = Some(names.iter().map(|n| (*n, false)).collect::>()); } 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>(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::>()); + self.aliases = Some(names.iter().map(|n| (*n, true)).collect::>()); } 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::>()); + self.r_unless = Some(names.iter().map(|s| *s).collect::>()); } 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::>()); + self.r_unless = Some(names.iter().map(|s| *s).collect::>()); } 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::>()); + self.blacklist = Some(names.iter().map(|s| *s).collect::>()); } 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::>()); + self.overrides = Some(names.iter().map(|s| *s).collect::>()); } 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::>()); + self.possible_vals = Some(names.iter().map(|s| *s).collect::>()); } 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::>()); + self.groups = Some(names.into_iter().map(|s| *s).collect::>()); } 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 { + 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::>() + .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::>() + .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 + 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 { + 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 ..."); + } + + #[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 "); + } + + #[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 "); + } + + #[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 "); + } + + #[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 "); + } + + // Positionals + + #[test] + fn positiona_display_mult() { + let mut p = Arg::with_name("pos", 1); + p.settings.set(ArgSettings::Multiple); + + assert_eq!(&*format!("{}", p), "..."); + } + + #[test] + fn positional_display_required() { + let mut p2 = Arg::with_name("pos", 1); + p2.settings.set(ArgSettings::Required); + + assert_eq!(&*format!("{}", p2), ""); + } + + #[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), " "); + } + + #[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), " "); + } +} \ No newline at end of file diff --git a/src/args/arg_builder/base.rs b/src/args/arg_builder/base.rs deleted file mode 100644 index fef9d8ab..00000000 --- a/src/args/arg_builder/base.rs +++ /dev/null @@ -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>, - pub settings: ArgFlags, - pub r_unless: Option>, - pub overrides: Option>, - pub groups: Option>, - pub requires: Option, &'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 } -} diff --git a/src/args/arg_builder/flag.rs b/src/args/arg_builder/flag.rs deleted file mode 100644 index 641e7777..00000000 --- a/src/args/arg_builder/flag.rs +++ /dev/null @@ -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> 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 { None } - fn val_names(&self) -> Option<&VecMap<&'e str>> { None } - fn num_vals(&self) -> Option { None } - fn possible_vals(&self) -> Option<&[&'e str]> { None } - fn validator(&self) -> Option<&Rc StdResult<(), String>>> { None } - fn validator_os(&self) -> Option<&Rc StdResult<(), OsString>>> { None } - fn min_vals(&self) -> Option { None } - fn short(&self) -> Option { self.s.short } - fn long(&self) -> Option<&'e str> { self.s.long } - fn val_delim(&self) -> Option { 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, &'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> { - 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"); - } -} diff --git a/src/args/arg_builder/mod.rs b/src/args/arg_builder/mod.rs deleted file mode 100644 index d1a7a660..00000000 --- a/src/args/arg_builder/mod.rs +++ /dev/null @@ -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; diff --git a/src/args/arg_builder/option.rs b/src/args/arg_builder/option.rs deleted file mode 100644 index 4bb147a7..00000000 --- a/src/args/arg_builder/option.rs +++ /dev/null @@ -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> 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 - 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 { self.v.max_vals } - fn val_terminator(&self) -> Option<&'e str> { self.v.terminator } - fn num_vals(&self) -> Option { 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 StdResult<(), String>>> { - self.v.validator.as_ref() - } - fn validator_os(&self) -> Option<&Rc StdResult<(), OsString>>> { - self.v.validator_os.as_ref() - } - fn min_vals(&self) -> Option { self.v.min_vals } - fn short(&self) -> Option { self.s.short } - fn long(&self) -> Option<&'e str> { self.s.long } - fn val_delim(&self) -> Option { 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, &'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> { - 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 ..."); - } - - #[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 "); - } - - #[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 "); - } - - #[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 "); - } - - #[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 "); - } -} diff --git a/src/args/arg_builder/positional.rs b/src/args/arg_builder/positional.rs deleted file mode 100644 index 43fdca4c..00000000 --- a/src/args/arg_builder/positional.rs +++ /dev/null @@ -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 { - 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::>() - .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::>() - .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 { self.v.max_vals } - fn val_terminator(&self) -> Option<&'e str> { self.v.terminator } - fn num_vals(&self) -> Option { 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 StdResult<(), String>>> { - self.v.validator.as_ref() - } - fn validator_os(&self) -> Option<&Rc StdResult<(), OsString>>> { - self.v.validator_os.as_ref() - } - fn min_vals(&self) -> Option { self.v.min_vals } - fn short(&self) -> Option { None } - fn long(&self) -> Option<&'e str> { None } - fn val_delim(&self) -> Option { 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, &'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> { 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), "..."); - } - - #[test] - fn display_required() { - let mut p2 = PosBuilder::new("pos", 1); - p2.b.settings.set(ArgSettings::Required); - - assert_eq!(&*format!("{}", p2), ""); - } - - #[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), " "); - } - - #[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), " "); - } -} diff --git a/src/args/arg_builder/switched.rs b/src/args/arg_builder/switched.rs deleted file mode 100644 index 224b2f2b..00000000 --- a/src/args/arg_builder/switched.rs +++ /dev/null @@ -1,38 +0,0 @@ -use Arg; - -#[derive(Debug)] -pub struct Switched<'b> { - pub short: Option, - pub long: Option<&'b str>, - pub aliases: Option>, // (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, - } - } -} diff --git a/src/args/arg_builder/valued.rs b/src/args/arg_builder/valued.rs deleted file mode 100644 index d70854dc..00000000 --- a/src/args/arg_builder/valued.rs +++ /dev/null @@ -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>, - pub val_names: Option>, - pub num_vals: Option, - pub max_vals: Option, - pub min_vals: Option, - pub validator: Option Result<(), String>>>, - pub validator_os: Option Result<(), OsString>>>, - pub val_delim: Option, - pub default_val: Option<&'b OsStr>, - pub default_vals_ifs: Option, &'b OsStr)>>, - pub env: Option<(&'a OsStr, Option)>, - 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 - } -} diff --git a/src/args/arg_matcher.rs b/src/args/arg_matcher.rs index 25f3fc5d..3c9d5b02 100644 --- a/src/args/arg_matcher.rs +++ b/src/args/arg_matcher.rs @@ -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; } diff --git a/src/args/mod.rs b/src/args/mod.rs index 21f9b850..1ab4b856 100644 --- a/src/args/mod.rs +++ b/src/args/mod.rs @@ -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; +} diff --git a/src/completions/bash.rs b/src/completions/bash.rs index f563922d..178fd316 100644 --- a/src/completions/bash.rs +++ b/src/completions/bash.rs @@ -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(&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, diff --git a/src/completions/fish.rs b/src/completions/fish.rs index 841c39b3..19c5c0f9 100644 --- a/src/completions/fish.rs +++ b/src/completions/fish.rs @@ -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(&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); } } diff --git a/src/completions/macros.rs b/src/completions/macros.rs index 653c72c4..24386178 100644 --- a/src/completions/macros.rs +++ b/src/completions/macros.rs @@ -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)); } } diff --git a/src/completions/mod.rs b/src/completions/mod.rs index 742c6161..986585bd 100644 --- a/src/completions/mod.rs +++ b/src/completions/mod.rs @@ -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(&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 { +pub fn all_subcommand_names(p: &App) -> Vec { 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 { // // 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 { +pub fn get_all_subcommand_paths(p: &App, first: bool) -> Vec { 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 { } 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); } diff --git a/src/completions/powershell.rs b/src/completions/powershell.rs index 19b14969..5f8d726f 100644 --- a/src/completions/powershell.rs +++ b/src/completions/powershell.rs @@ -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(&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); } diff --git a/src/completions/zsh.rs b/src/completions/zsh.rs index 11dd868e..59cd4270 100644 --- a/src/completions/zsh.rs +++ b/src/completions/zsh.rs @@ -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(&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) { @@ -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::>().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::>().join(" ")) }) diff --git a/src/errors.rs b/src/errors.rs index 664819d6..f38073e1 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -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, usage: U, color: ColorWhen, @@ -414,7 +414,7 @@ impl Error { O: Into, 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 + 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()]), } } diff --git a/src/macros.rs b/src/macros.rs index 52fb35a4..b0cf2337 100644 --- a/src/macros.rs +++ b/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) + }}; +} \ No newline at end of file diff --git a/src/suggestions.rs b/src/suggestions.rs index 23832cb3..acca15ab 100644 --- a/src/suggestions.rs +++ b/src/suggestions.rs @@ -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 + 'z, - I: IntoIterator, + I: IntoIterator, { 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("--"), diff --git a/src/usage_parser.rs b/src/usage_parser.rs index f6d5ac60..f3d04dee 100644 --- a/src/usage_parser.rs +++ b/src/usage_parser.rs @@ -60,17 +60,17 @@ impl<'a> UsageParser<'a> { } } debug_assert!( - !arg.b.name.is_empty(), + !arg.name.is_empty(), format!( "No name found for Arg when parsing usage string: {}", self.usage ) ); - arg.v.num_vals = match arg.v.val_names { + arg.num_vals = match arg.val_names { Some(ref v) if v.len() >= 2 => Some(v.len() as u64), _ => None, }; - debugln!("UsageParser::parse: vals...{:?}", arg.v.val_names); + debugln!("UsageParser::parse: vals...{:?}", arg.val_names); arg } @@ -88,21 +88,21 @@ impl<'a> UsageParser<'a> { let name = &self.usage[self.start..self.pos]; if self.prev == UsageToken::Unknown { debugln!("UsageParser::name: setting name...{}", name); - arg.b.name = name; - if arg.s.long.is_none() && arg.s.short.is_none() { + arg.name = name; + if arg.long.is_none() && arg.short.is_none() { debugln!("UsageParser::name: explicit name set..."); self.explicit_name_set = true; self.prev = UsageToken::Name; } } else { debugln!("UsageParser::name: setting val name...{}", name); - if let Some(ref mut v) = arg.v.val_names { + if let Some(ref mut v) = arg.val_names { let len = v.len(); v.insert(len, name); } else { let mut v = VecMap::new(); v.insert(0, name); - arg.v.val_names = Some(v); + arg.val_names = Some(v); arg.setb(ArgSettings::TakesValue); } self.prev = UsageToken::ValName; @@ -142,10 +142,10 @@ impl<'a> UsageParser<'a> { let name = &self.usage[self.start..self.pos]; if !self.explicit_name_set { debugln!("UsageParser::long: setting name...{}", name); - arg.b.name = name; + arg.name = name; } debugln!("UsageParser::long: setting long...{}", name); - arg.s.long = Some(name); + arg.long = Some(name); self.prev = UsageToken::Long; } @@ -154,12 +154,12 @@ impl<'a> UsageParser<'a> { let start = &self.usage[self.pos..]; let short = start.chars().nth(0).expect(INTERNAL_ERROR_MSG); debugln!("UsageParser::short: setting short...{}", short); - arg.s.short = Some(short); - if arg.b.name.is_empty() { + arg.short = Some(short); + if arg.name.is_empty() { // --long takes precedence but doesn't set self.explicit_name_set let name = &start[..short.len_utf8()]; debugln!("UsageParser::short: setting name...{}", name); - arg.b.name = name; + arg.name = name; } self.prev = UsageToken::Short; } @@ -179,8 +179,8 @@ impl<'a> UsageParser<'a> { if arg.is_set(ArgSettings::TakesValue) { arg.setb(ArgSettings::UseValueDelimiter); arg.unsetb(ArgSettings::ValueDelimiterNotSet); - if arg.v.val_delim.is_none() { - arg.v.val_delim = Some(','); + if arg.val_delim.is_none() { + arg.val_delim = Some(','); } } self.prev = UsageToken::Multiple; @@ -199,7 +199,7 @@ impl<'a> UsageParser<'a> { "UsageParser::help: setting help...{}", &self.usage[self.start..self.pos] ); - arg.b.help = Some(&self.usage[self.start..self.pos]); + arg.help = Some(&self.usage[self.start..self.pos]); self.pos += 1; // Move to next byte to keep from thinking ending ' is a start self.prev = UsageToken::Help; } @@ -227,1034 +227,1034 @@ mod test { #[test] fn create_flag_usage() { let a = Arg::from_usage("[flag] -f 'some help info'"); - assert_eq!(a.b.name, "flag"); - assert_eq!(a.s.short.unwrap(), 'f'); - assert!(a.s.long.is_none()); - assert_eq!(a.b.help.unwrap(), "some help info"); + assert_eq!(a.name, "flag"); + assert_eq!(a.short.unwrap(), 'f'); + assert!(a.long.is_none()); + assert_eq!(a.help.unwrap(), "some help info"); assert!(!a.is_set(ArgSettings::Multiple)); - assert!(a.v.val_names.is_none()); - assert!(a.v.num_vals.is_none()); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); let b = Arg::from_usage("[flag] --flag 'some help info'"); - assert_eq!(b.b.name, "flag"); - assert_eq!(b.s.long.unwrap(), "flag"); - assert!(b.s.short.is_none()); - assert_eq!(b.b.help.unwrap(), "some help info"); + assert_eq!(b.name, "flag"); + assert_eq!(b.long.unwrap(), "flag"); + assert!(b.short.is_none()); + assert_eq!(b.help.unwrap(), "some help info"); assert!(!b.is_set(ArgSettings::Multiple)); - assert!(a.v.val_names.is_none()); - assert!(a.v.num_vals.is_none()); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); let b = Arg::from_usage("--flag 'some help info'"); - assert_eq!(b.b.name, "flag"); - assert_eq!(b.s.long.unwrap(), "flag"); - assert!(b.s.short.is_none()); - assert_eq!(b.b.help.unwrap(), "some help info"); + assert_eq!(b.name, "flag"); + assert_eq!(b.long.unwrap(), "flag"); + assert!(b.short.is_none()); + assert_eq!(b.help.unwrap(), "some help info"); assert!(!b.is_set(ArgSettings::Multiple)); - assert!(b.v.val_names.is_none()); - assert!(b.v.num_vals.is_none()); + assert!(b.val_names.is_none()); + assert!(b.num_vals.is_none()); let c = Arg::from_usage("[flag] -f --flag 'some help info'"); - assert_eq!(c.b.name, "flag"); - assert_eq!(c.s.short.unwrap(), 'f'); - assert_eq!(c.s.long.unwrap(), "flag"); - assert_eq!(c.b.help.unwrap(), "some help info"); + assert_eq!(c.name, "flag"); + assert_eq!(c.short.unwrap(), 'f'); + assert_eq!(c.long.unwrap(), "flag"); + assert_eq!(c.help.unwrap(), "some help info"); assert!(!c.is_set(ArgSettings::Multiple)); - assert!(c.v.val_names.is_none()); - assert!(c.v.num_vals.is_none()); + assert!(c.val_names.is_none()); + assert!(c.num_vals.is_none()); let d = Arg::from_usage("[flag] -f... 'some help info'"); - assert_eq!(d.b.name, "flag"); - assert_eq!(d.s.short.unwrap(), 'f'); - assert!(d.s.long.is_none()); - assert_eq!(d.b.help.unwrap(), "some help info"); + assert_eq!(d.name, "flag"); + assert_eq!(d.short.unwrap(), 'f'); + assert!(d.long.is_none()); + assert_eq!(d.help.unwrap(), "some help info"); assert!(d.is_set(ArgSettings::Multiple)); - assert!(d.v.val_names.is_none()); - assert!(d.v.num_vals.is_none()); + assert!(d.val_names.is_none()); + assert!(d.num_vals.is_none()); let e = Arg::from_usage("[flag] -f --flag... 'some help info'"); - assert_eq!(e.b.name, "flag"); - assert_eq!(e.s.long.unwrap(), "flag"); - assert_eq!(e.s.short.unwrap(), 'f'); - assert_eq!(e.b.help.unwrap(), "some help info"); + assert_eq!(e.name, "flag"); + assert_eq!(e.long.unwrap(), "flag"); + assert_eq!(e.short.unwrap(), 'f'); + assert_eq!(e.help.unwrap(), "some help info"); assert!(e.is_set(ArgSettings::Multiple)); - assert!(e.v.val_names.is_none()); - assert!(e.v.num_vals.is_none()); + assert!(e.val_names.is_none()); + assert!(e.num_vals.is_none()); let e = Arg::from_usage("-f --flag... 'some help info'"); - assert_eq!(e.b.name, "flag"); - assert_eq!(e.s.long.unwrap(), "flag"); - assert_eq!(e.s.short.unwrap(), 'f'); - assert_eq!(e.b.help.unwrap(), "some help info"); + assert_eq!(e.name, "flag"); + assert_eq!(e.long.unwrap(), "flag"); + assert_eq!(e.short.unwrap(), 'f'); + assert_eq!(e.help.unwrap(), "some help info"); assert!(e.is_set(ArgSettings::Multiple)); - assert!(e.v.val_names.is_none()); - assert!(e.v.num_vals.is_none()); + assert!(e.val_names.is_none()); + assert!(e.num_vals.is_none()); let e = Arg::from_usage("--flags"); - assert_eq!(e.b.name, "flags"); - assert_eq!(e.s.long.unwrap(), "flags"); - assert!(e.v.val_names.is_none()); - assert!(e.v.num_vals.is_none()); + assert_eq!(e.name, "flags"); + assert_eq!(e.long.unwrap(), "flags"); + assert!(e.val_names.is_none()); + assert!(e.num_vals.is_none()); let e = Arg::from_usage("--flags..."); - assert_eq!(e.b.name, "flags"); - assert_eq!(e.s.long.unwrap(), "flags"); + assert_eq!(e.name, "flags"); + assert_eq!(e.long.unwrap(), "flags"); assert!(e.is_set(ArgSettings::Multiple)); - assert!(e.v.val_names.is_none()); - assert!(e.v.num_vals.is_none()); + assert!(e.val_names.is_none()); + assert!(e.num_vals.is_none()); let e = Arg::from_usage("[flags] -f"); - assert_eq!(e.b.name, "flags"); - assert_eq!(e.s.short.unwrap(), 'f'); - assert!(e.v.val_names.is_none()); - assert!(e.v.num_vals.is_none()); + assert_eq!(e.name, "flags"); + assert_eq!(e.short.unwrap(), 'f'); + assert!(e.val_names.is_none()); + assert!(e.num_vals.is_none()); let e = Arg::from_usage("[flags] -f..."); - assert_eq!(e.b.name, "flags"); - assert_eq!(e.s.short.unwrap(), 'f'); + assert_eq!(e.name, "flags"); + assert_eq!(e.short.unwrap(), 'f'); assert!(e.is_set(ArgSettings::Multiple)); - assert!(e.v.val_names.is_none()); - assert!(e.v.num_vals.is_none()); + assert!(e.val_names.is_none()); + assert!(e.num_vals.is_none()); let a = Arg::from_usage("-f 'some help info'"); - assert_eq!(a.b.name, "f"); - assert_eq!(a.s.short.unwrap(), 'f'); - assert!(a.s.long.is_none()); - assert_eq!(a.b.help.unwrap(), "some help info"); + assert_eq!(a.name, "f"); + assert_eq!(a.short.unwrap(), 'f'); + assert!(a.long.is_none()); + assert_eq!(a.help.unwrap(), "some help info"); assert!(!a.is_set(ArgSettings::Multiple)); - assert!(a.v.val_names.is_none()); - assert!(a.v.num_vals.is_none()); + assert!(a.val_names.is_none()); + assert!(a.num_vals.is_none()); let e = Arg::from_usage("-f"); - assert_eq!(e.b.name, "f"); - assert_eq!(e.s.short.unwrap(), 'f'); - assert!(e.v.val_names.is_none()); - assert!(e.v.num_vals.is_none()); + assert_eq!(e.name, "f"); + assert_eq!(e.short.unwrap(), 'f'); + assert!(e.val_names.is_none()); + assert!(e.num_vals.is_none()); let e = Arg::from_usage("-f..."); - assert_eq!(e.b.name, "f"); - assert_eq!(e.s.short.unwrap(), 'f'); + assert_eq!(e.name, "f"); + assert_eq!(e.short.unwrap(), 'f'); assert!(e.is_set(ArgSettings::Multiple)); - assert!(e.v.val_names.is_none()); - assert!(e.v.num_vals.is_none()); + assert!(e.val_names.is_none()); + assert!(e.num_vals.is_none()); } #[test] fn create_option_usage0() { // Short only let a = Arg::from_usage("[option] -o [opt] 'some help info'"); - assert_eq!(a.b.name, "option"); - assert_eq!(a.s.short.unwrap(), 'o'); - assert!(a.s.long.is_none()); - assert_eq!(a.b.help.unwrap(), "some help info"); + assert_eq!(a.name, "option"); + assert_eq!(a.short.unwrap(), 'o'); + assert!(a.long.is_none()); + assert_eq!(a.help.unwrap(), "some help info"); assert!(!a.is_set(ArgSettings::Multiple)); assert!(a.is_set(ArgSettings::TakesValue)); assert!(!a.is_set(ArgSettings::Required)); assert_eq!( - a.v.val_names.unwrap().values().collect::>(), + a.val_names.unwrap().values().collect::>(), [&"opt"] ); - assert!(a.v.num_vals.is_none()); + assert!(a.num_vals.is_none()); } #[test] fn create_option_usage1() { let b = Arg::from_usage("-o [opt] 'some help info'"); - assert_eq!(b.b.name, "o"); - assert_eq!(b.s.short.unwrap(), 'o'); - assert!(b.s.long.is_none()); - assert_eq!(b.b.help.unwrap(), "some help info"); + assert_eq!(b.name, "o"); + assert_eq!(b.short.unwrap(), 'o'); + assert!(b.long.is_none()); + assert_eq!(b.help.unwrap(), "some help info"); assert!(!b.is_set(ArgSettings::Multiple)); assert!(b.is_set(ArgSettings::TakesValue)); assert!(!b.is_set(ArgSettings::Required)); assert_eq!( - b.v.val_names.unwrap().values().collect::>(), + b.val_names.unwrap().values().collect::>(), [&"opt"] ); - assert!(b.v.num_vals.is_none()); + assert!(b.num_vals.is_none()); } #[test] fn create_option_usage2() { let c = Arg::from_usage("