mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 22:32:33 +00:00
api(Arg::value_terminator): adds the ability to terminate multiple values with a given value
One can now specificy a value termintaor that will stop the parsing of multiple values upon reaching this special value. Closes #782
This commit is contained in:
parent
3ca4a08f0f
commit
be64ce0c37
8 changed files with 67 additions and 0 deletions
|
@ -1517,6 +1517,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for App<'n, 'e> {
|
|||
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!")
|
||||
}
|
||||
|
|
|
@ -1523,6 +1523,11 @@ impl<'a, 'b> Parser<'a, 'b>
|
|||
{
|
||||
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 t == v {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
matcher.add_val_to(arg.name(), v);
|
||||
|
||||
// Increment or create the group "args"
|
||||
|
|
|
@ -38,6 +38,7 @@ pub trait AnyArg<'n, 'e>: std_fmt::Display {
|
|||
fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e str>, &'e str)>>;
|
||||
fn longest_filter(&self) -> bool;
|
||||
fn kind(&self) -> ArgKind;
|
||||
fn val_terminator(&self) -> Option<&'e str>;
|
||||
}
|
||||
|
||||
pub trait DispOrder {
|
||||
|
|
|
@ -84,6 +84,8 @@ pub struct Arg<'a, 'b>
|
|||
pub r_unless: Option<Vec<&'a str>>,
|
||||
#[doc(hidden)]
|
||||
pub r_ifs: Option<Vec<(&'a str, &'b str)>>,
|
||||
#[doc(hidden)]
|
||||
pub val_terminator: Option<&'b str>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Default for Arg<'a, 'b> {
|
||||
|
@ -113,6 +115,7 @@ impl<'a, 'b> Default for Arg<'a, 'b> {
|
|||
disp_ord: 999,
|
||||
r_unless: None,
|
||||
r_ifs: None,
|
||||
val_terminator: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1819,6 +1822,55 @@ impl<'a, 'b> Arg<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Specifies a value that *stops* parsing multiple values of a give argument. By default when
|
||||
/// one sets [`multiple(true)`] on an argument, clap will continue parsing values for that
|
||||
/// argument until it reaches another valid argument, or one of the other more specific settings
|
||||
/// for multiple values is used (such as [`min_values`], [`max_values`] or
|
||||
/// [`number_of_values`]).
|
||||
///
|
||||
/// **NOTE:** This setting only applies to [options] and [positional arguments]
|
||||
///
|
||||
/// **NOTE:** When the terminator is passed in on the command line, it is **not** stored as one
|
||||
/// of the vaues
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap::{App, Arg};
|
||||
/// Arg::with_name("vals")
|
||||
/// .takes_value(true)
|
||||
/// .multiple(true)
|
||||
/// .value_terminator(";")
|
||||
/// # ;
|
||||
/// ```
|
||||
/// The following example uses two arguments, a sequence of commands, and the location in which
|
||||
/// to perform them
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap::{App, Arg};
|
||||
/// let m = App::new("do")
|
||||
/// .arg(Arg::with_name("cmds")
|
||||
/// .multiple(true)
|
||||
/// .allow_hyphen_values(true)
|
||||
/// .value_terminator(";"))
|
||||
/// .arg(Arg::with_name("location"))
|
||||
/// .get_matches_from(vec!["do", "find", "-type", "f", "-name", "special", ";", "/home/clap"]);
|
||||
/// let cmds: Vec<_> = m.values_of("cmds").unwrap().collect();
|
||||
/// assert_eq!(&cmds, &["find", "-type", "f", "-name", "special"]);
|
||||
/// assert_eq!(m.value_of("location"), Some("/home/clap"));
|
||||
/// ```
|
||||
/// [options]: ./struct.Arg.html#method.takes_value
|
||||
/// [positional arguments]: ./struct.Arg.html#method.index
|
||||
/// [`multiple(true)`]: ./struct.Arg.html#method.multiple
|
||||
/// [`min_values`]: ./struct.Arg.html#method.min_values
|
||||
/// [`number_of_values`]: ./struct.Arg.html#method.number_of_values
|
||||
/// [`max_values`]: ./struct.Arg.html#method.max_values
|
||||
pub fn value_terminator(mut self, term: &'b str) -> Self {
|
||||
self.setb(ArgSettings::TakesValue);
|
||||
self.val_terminator = Some(term);
|
||||
self
|
||||
}
|
||||
|
||||
/// Specifies that an argument can be matched to all child [`SubCommand`]s.
|
||||
///
|
||||
/// **NOTE:** Global arguments *only* propagate down, **not** up (to parent commands)
|
||||
|
@ -3153,6 +3205,7 @@ impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for Arg<'a, 'b> {
|
|||
disp_ord: a.disp_ord,
|
||||
r_unless: a.r_unless.clone(),
|
||||
r_ifs: a.r_ifs.clone(),
|
||||
val_terminator: a.val_terminator.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3184,6 +3237,7 @@ impl<'a, 'b> Clone for Arg<'a, 'b> {
|
|||
disp_ord: self.disp_ord,
|
||||
r_unless: self.r_unless.clone(),
|
||||
r_ifs: self.r_ifs.clone(),
|
||||
val_terminator: self.val_terminator.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> {
|
|||
fn long(&self) -> Option<&'e str> { self.s.long }
|
||||
fn val_delim(&self) -> Option<char> { None }
|
||||
fn help(&self) -> Option<&'e str> { self.b.help }
|
||||
fn val_terminator(&self) -> Option<&'e str> {None}
|
||||
fn default_val(&self) -> Option<&'n str> { None }
|
||||
fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e str>, &'e str)>> {None}
|
||||
fn longest_filter(&self) -> bool { self.s.long.is_some() }
|
||||
|
|
|
@ -105,6 +105,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> {
|
|||
fn has_switch(&self) -> bool { true }
|
||||
fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) }
|
||||
fn max_vals(&self) -> Option<u64> { self.v.max_vals }
|
||||
fn val_terminator(&self) -> Option<&'e str> { self.v.terminator }
|
||||
fn num_vals(&self) -> Option<u64> { self.v.num_vals }
|
||||
fn possible_vals(&self) -> Option<&[&'e str]> { self.v.possible_vals.as_ref().map(|o| &o[..]) }
|
||||
fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> {
|
||||
|
|
|
@ -109,6 +109,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> {
|
|||
fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) }
|
||||
fn has_switch(&self) -> bool { false }
|
||||
fn max_vals(&self) -> Option<u64> { self.v.max_vals }
|
||||
fn val_terminator(&self) -> Option<&'e str> { self.v.terminator }
|
||||
fn num_vals(&self) -> Option<u64> { self.v.num_vals }
|
||||
fn possible_vals(&self) -> Option<&[&'e str]> { self.v.possible_vals.as_ref().map(|o| &o[..]) }
|
||||
fn validator(&self) -> Option<&Rc<Fn(String) -> StdResult<(), String>>> {
|
||||
|
|
|
@ -20,6 +20,7 @@ pub struct Valued<'a, 'b>
|
|||
pub val_delim: Option<char>,
|
||||
pub default_val: Option<&'a str>,
|
||||
pub default_vals_ifs: Option<VecMap<(&'a str, Option<&'b str>, &'b str)>>,
|
||||
pub terminator: Option<&'b str>,
|
||||
}
|
||||
|
||||
impl<'n, 'e> Default for Valued<'n, 'e> {
|
||||
|
@ -35,6 +36,7 @@ impl<'n, 'e> Default for Valued<'n, 'e> {
|
|||
val_delim: Some(','),
|
||||
default_val: None,
|
||||
default_vals_ifs: None,
|
||||
terminator: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +54,7 @@ impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Valued<'n, 'e> {
|
|||
val_delim: a.val_delim,
|
||||
default_val: a.default_val,
|
||||
default_vals_ifs: a.default_vals_ifs.clone(),
|
||||
terminator: a.val_terminator.clone(),
|
||||
};
|
||||
if let Some(ref vec) = a.val_names {
|
||||
if vec.len() > 1 {
|
||||
|
|
Loading…
Reference in a new issue