Skip to content

Commit

Permalink
Allow replacing input on the fly
Browse files Browse the repository at this point in the history
  • Loading branch information
pksunkara committed Feb 21, 2020
1 parent 1e7c9ef commit b8851a7
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 136 deletions.
52 changes: 36 additions & 16 deletions src/build/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ mod settings;
pub use self::settings::{AppFlags, AppSettings};

// Std
use std::collections::HashMap;
use std::env;
use std::ffi::OsString;
use std::fmt;
use std::io::{self, BufRead, BufWriter, Write};
use std::iter::Peekable;
use std::path::Path;
use std::process;

Expand All @@ -20,7 +20,7 @@ use crate::mkeymap::MKeyMap;
use crate::output::fmt::ColorWhen;
use crate::output::{Help, Usage};
use crate::parse::errors::Result as ClapResult;
use crate::parse::{ArgMatcher, ArgMatches, Parser};
use crate::parse::{ArgMatcher, ArgMatches, Input, Parser};
use crate::util::{Key, HELP_HASH, VERSION_HASH};
use crate::INTERNAL_ERROR_MSG;

Expand Down Expand Up @@ -110,6 +110,8 @@ pub struct App<'b> {
#[doc(hidden)]
pub subcommands: Vec<App<'b>>,
#[doc(hidden)]
pub replacers: HashMap<&'b str, &'b [&'b str]>,
#[doc(hidden)]
pub groups: Vec<ArgGroup<'b>>,
#[doc(hidden)]
pub help_headings: Vec<Option<&'b str>>,
Expand Down Expand Up @@ -784,6 +786,28 @@ impl<'b> App<'b> {
self
}

/// Replaces an argument to this application with other arguments.
///
/// Below, when the given args are `app install`, they will be changed to `app module install`.
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, };
/// let m = App::new("app")
/// .replace("install", &["module", "install"])
/// .subcommand(App::new("module")
/// .subcommand(App::new("install")))
/// .get_matches_from(vec!["app", "install"]);
///
/// assert!(m.subcommand_matches("module").is_some());
/// assert!(m.subcommand_matches("module").unwrap().subcommand_matches("install").is_some());
/// ```
pub fn replace(mut self, name: &'b str, target: &'b [&'b str]) -> Self {
self.replacers.insert(name, target);
self
}

/// Adds an [`ArgGroup`] to the application. [`ArgGroup`]s are a family of related arguments.
/// By placing them in a logical group, you can build easier requirement and exclusion rules.
/// For instance, you can make an entire [`ArgGroup`] required, meaning that one (and *only*
Expand Down Expand Up @@ -1344,7 +1368,7 @@ impl<'b> App<'b> {
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
let mut it = itr.into_iter();
let mut it = Input::from(itr.into_iter());
// Get the name of the program (argument 1 of env::args()) and determine the
// actual file
// that was used to execute the program. This is because a program called
Expand All @@ -1353,9 +1377,9 @@ impl<'b> App<'b> {
// to display
// the full path when displaying help messages and such
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((name, _)) = it.next(None) {
let p = Path::new(name);

if let Some(f) = p.file_name() {
if let Some(s) = f.to_os_string().to_str() {
if self.bin_name.is_none() {
Expand All @@ -1366,19 +1390,15 @@ impl<'b> App<'b> {
}
}

self._do_parse(&mut it.peekable())
self._do_parse(&mut it)
}
}

// Internally used only
#[doc(hidden)]
impl<'b> App<'b> {
#[doc(hidden)]
fn _do_parse<I, T>(&mut self, it: &mut Peekable<I>) -> ClapResult<ArgMatches>
where
I: Iterator<Item = T>,
T: Into<OsString> + Clone,
{
fn _do_parse(&mut self, it: &mut Input) -> ClapResult<ArgMatches> {
debugln!("App::_do_parse;");
let mut matcher = ArgMatcher::default();

Expand Down Expand Up @@ -1518,7 +1538,7 @@ impl<'b> App<'b> {

pub fn _propagate(&mut self, prop: Propagation) {
macro_rules! propagate_subcmd {
($_self:ident, $sc:expr) => {{
($_self:expr, $sc:expr) => {{
// We have to create a new scope in order to tell rustc the borrow of `sc` is
// done and to recursively call this method
{
Expand Down Expand Up @@ -1627,14 +1647,14 @@ impl<'b> App<'b> {
{
a.disp_ord = i;
}
for (i, mut sc) in &mut subcommands_mut!(self)
for (i, mut sc) in &mut subcommands!(self, iter_mut)
.enumerate()
.filter(|&(_, ref sc)| sc.disp_ord == 999)
{
sc.disp_ord = i;
}
}
for sc in subcommands_mut!(self) {
for sc in subcommands!(self, iter_mut) {
sc._derive_display_order();
}
}
Expand Down Expand Up @@ -1703,7 +1723,7 @@ impl<'b> App<'b> {
#[doc(hidden)]
pub fn _build_bin_names(&mut self) {
debugln!("App::_build_bin_names;");
for mut sc in subcommands_mut!(self) {
for mut sc in subcommands!(self, iter_mut) {
debug!("Parser::build_bin_names:iter: bin_name set...");
if sc.bin_name.is_none() {
sdebugln!("No");
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ pub use crate::derive::{Clap, FromArgMatches, IntoApp, Subcommand};
pub use crate::output::fmt::Format;
pub use crate::parse::errors::{Error, ErrorKind, Result};
pub use crate::parse::{ArgMatches, OsValues, SubCommand, Values};

#[cfg(feature = "yaml")]
pub use yaml_rust::YamlLoader;

Expand Down
68 changes: 17 additions & 51 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -934,13 +934,6 @@ macro_rules! flags {
};
}

#[allow(unused_macros)]
macro_rules! flags_mut {
($app:expr) => {
$crate::flags!($app, iter_mut)
};
}

#[macro_export]
#[doc(hidden)]
macro_rules! opts {
Expand All @@ -956,46 +949,17 @@ macro_rules! opts {
};
}

#[allow(unused_macros)]
macro_rules! opts_mut {
($app:expr) => {
opts!($app, iter_mut)
};
}

#[macro_export]
#[doc(hidden)]
macro_rules! positionals {
($app:expr) => {
($app:expr, $how:ident) => {{
$app.args
.args
.iter()
.filter(|a| !(a.short.is_some() || a.long.is_some()))
};
}

#[allow(unused_macros)]
macro_rules! positionals_mut {
($app:expr) => {
$app.args
.values_mut()
.$how()
.filter(|a| !(a.short.is_some() || a.long.is_some()))
};
}

#[allow(unused_macros)]
macro_rules! custom_headings_mut {
($app:expr) => {
custom_headings!($app, values_mut)
};
}

macro_rules! subcommands_cloned {
($app:expr, $how:ident) => {
$app.subcommands.$how().cloned()
};
}};
($app:expr) => {
subcommands_cloned!($app, iter)
positionals!($app, iter)
};
}

Expand All @@ -1010,12 +974,6 @@ macro_rules! subcommands {
};
}

macro_rules! subcommands_mut {
($app:expr) => {
subcommands!($app, iter_mut)
};
}

macro_rules! groups_for_arg {
($app:expr, $grp:expr) => {{
debugln!("Parser::groups_for_arg: name={}", $grp);
Expand All @@ -1027,21 +985,26 @@ macro_rules! groups_for_arg {
}

macro_rules! find_subcmd_cloned {
($_self:expr, $sc:expr) => {{
subcommands_cloned!($_self).find(|a| match_alias!(a, $sc, &*a.name))
($app:expr, $sc:expr) => {{
subcommands!($app)
.cloned()
.find(|a| match_alias!(a, $sc, &*a.name))
}};
}

#[macro_export]
#[doc(hidden)]
macro_rules! find_subcmd {
($app:expr, $sc:expr) => {{
subcommands!($app).find(|a| match_alias!(a, $sc, &*a.name))
($app:expr, $sc:expr, $how:ident) => {{
subcommands!($app, $how).find(|a| match_alias!(a, $sc, &*a.name))
}};
($app:expr, $sc:expr) => {
find_subcmd!($app, $sc, iter)
};
}

macro_rules! longs {
($app:expr) => {{
($app:expr, $how:ident) => {{
use crate::mkeymap::KeyType;
$app.args.keys.iter().map(|x| &x.key).filter_map(|a| {
if let KeyType::Long(v) = a {
Expand All @@ -1051,6 +1014,9 @@ macro_rules! longs {
}
})
}};
($app:expr) => {
longs!($app, iter)
};
}

#[macro_export]
Expand Down
2 changes: 1 addition & 1 deletion src/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ mod validator;
pub use self::arg_matcher::ArgMatcher;
pub use self::matches::ArgMatches;
pub use self::matches::{MatchedArg, OsValues, SubCommand, Values};
pub use self::parser::{ParseResult, Parser};
pub use self::parser::{Input, ParseResult, Parser};
pub use self::validator::Validator;
Loading

0 comments on commit b8851a7

Please sign in to comment.