Skip to content

Commit

Permalink
feat: adds support changing the value delimiter
Browse files Browse the repository at this point in the history
Closes #353
  • Loading branch information
kbknapp committed Jan 26, 2016
1 parent 25b8ece commit b1f906b
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 196 deletions.
2 changes: 1 addition & 1 deletion src/app/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1058,7 +1058,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
where A: AnyArg<'a, 'b> + Display {
debugln!("fn=add_val_to_arg;");
let mut ret = None;
for v in val.split(b',') {
for v in val.split(arg.val_delim().unwrap_or(',') as u32 as u8) {
debugln!("adding val: {:?}", v);
matcher.add_val_to(&*arg.name(), v);

Expand Down
1 change: 1 addition & 0 deletions src/args/any_arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ pub trait AnyArg<'n, 'e>: Display {
fn validator(&self) -> Option<&Rc<Fn(String) -> Result<(), String>>>;
fn short(&self) -> Option<char>;
fn long(&self) -> Option<&'e str>;
fn val_delim(&self) -> Option<char>;
}
85 changes: 59 additions & 26 deletions src/args/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ pub struct Arg<'a, 'b> where 'a: 'b {
pub overrides: Option<Vec<&'a str>>,
#[doc(hidden)]
pub settings: ArgFlags,
// Delimiting character for value separation
#[doc(hidden)]
pub val_delim: Option<char>,
}

impl<'a, 'b> Default for Arg<'a, 'b> {
Expand All @@ -111,6 +114,7 @@ impl<'a, 'b> Default for Arg<'a, 'b> {
validator: None,
overrides: None,
settings: ArgFlags::new(),
val_delim: Some(','),
}
}
}
Expand Down Expand Up @@ -175,6 +179,7 @@ impl<'a, 'b> Arg<'a, 'b> {
"max_values" => a.max_values(v.as_i64().unwrap() as u8),
"min_values" => a.min_values(v.as_i64().unwrap() as u8),
"value_name" => a.value_name(v.as_str().unwrap()),
"value_delimiter" => a.value_delimiter(v.as_str().unwrap()),
"value_names" => {
for ys in v.as_vec().unwrap() {
if let Some(s) = ys.as_str() {
Expand All @@ -199,10 +204,10 @@ impl<'a, 'b> Arg<'a, 'b> {
}
a
}
"mutually_overrides_with" => {
"overrides_with" => {
for ys in v.as_vec().unwrap() {
if let Some(s) = ys.as_str() {
a = a.mutually_overrides_with(s);
a = a.overrides_with(s);
}
}
a
Expand Down Expand Up @@ -430,9 +435,9 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```no_run
/// # use clap::{App, Arg};
/// # let myprog = App::new("myprog").arg(Arg::with_name("config")
/// .mutually_overrides_with("debug")
/// .overrides_with("debug")
/// # ).get_matches();
pub fn mutually_overrides_with(mut self, name: &'a str) -> Self {
pub fn overrides_with(mut self, name: &'a str) -> Self {
if let Some(ref mut vec) = self.overrides {
vec.push(name.as_ref());
} else {
Expand All @@ -450,9 +455,9 @@ impl<'a, 'b> Arg<'a, 'b> {
/// # use clap::{App, Arg};
/// let config_overrides = ["debug", "input"];
/// # let myprog = App::new("myprog").arg(Arg::with_name("config")
/// .mutually_overrides_with_all(&config_overrides)
/// .overrides_with_all(&config_overrides)
/// # ).get_matches();
pub fn mutually_overrides_with_all(mut self, names: &[&'a str]) -> Self {
pub fn overrides_with_all(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.overrides {
for s in names {
vec.push(s);
Expand Down Expand Up @@ -810,31 +815,57 @@ impl<'a, 'b> Arg<'a, 'b> {
self
}

/// Specifies the separator to use when values are clumped together, defaults to `,` (comma).
///
/// **NOTE:** implicitly sets `Arg::takes_value(true)`
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg};
/// let app = App::new("fake")
/// .arg(Arg::with_name("config")
/// .short("c")
/// .long("config")
/// .value_delimiter(";"));
///
/// let m = app.get_matches_from(vec![
/// "fake", "--config=val1;val2;val3"
/// ]);
///
/// assert_eq!(m.values_of("config").unwrap().collect::<Vec<_>>(), ["val1", "val2", "val3"])
/// ```
pub fn value_delimiter(mut self, d: &str) -> Self {
self = self.set(ArgSettings::TakesValue);
self.val_delim = Some(d.chars()
.nth(0)
.expect("Failed to get value_delimiter from arg"));
self
}

/// Specifies names for values of option arguments. These names are cosmetic only, used for
/// help and usage strings only. The names are **not** used to access arguments. The values of
/// the arguments are accessed in numeric order (i.e. if you specify two names `one` and `two`
/// `one` will be the first matched value, `two` will be the second).
///
/// **NOTE:** This implicitly sets `.number_of_values()` so there is no need to set that, but
/// be aware that the number of "names" you set for the values, will be the *exact* number of
/// values required to satisfy this argument
/// **NOTE:** This implicitly sets `.number_of_values()`, but be aware that the number of
/// "names" you set for the values, will be the *exact* number of values required to satisfy
/// this argument
///
/// **NOTE:** Does *not* require `.multiple(true)` to be set. Setting `.multiple(true)` would
/// allow `-f <file> <file> <file> -f <file> <file> <file>` where as *not* setting
/// `.multiple(true)` would only allow one occurrence of this argument.
/// **NOTE:** implicitly sets `Arg::takes_value(true)`
///
/// **NOTE:** Does *not* require or imply `.multiple(true)`.
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg};
/// let val_names = ["one", "two"];
/// # let matches = App::new("myprog")
/// # .arg(
/// # Arg::with_name("debug").index(1)
/// // ...
/// .value_names(&val_names)
/// # ).get_matches();
/// Arg::with_name("speed")
/// .short("s")
/// .value_names(&["fast", "slow"])
/// # ;
pub fn value_names(mut self, names: &[&'b str]) -> Self {
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vals) = self.val_names {
let mut l = vals.len();
for s in names {
Expand Down Expand Up @@ -878,20 +909,21 @@ impl<'a, 'b> Arg<'a, 'b> {
self
}

/// Specifies the name for value of option or positional arguments. This name is cosmetic only,
/// used for help and usage strings. The name is **not** used to access arguments.
/// Specifies the name for value of option or positional arguments inside of help documenation.
/// This name is cosmetic only, the name is **not** used to access arguments.
///
/// **NOTE:** implicitly sets `Arg::takes_value(true)`
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, Arg};
/// # let matches = App::new("myprog")
/// # .arg(
/// Arg::with_name("debug")
/// Arg::with_name("input")
/// .index(1)
/// .value_name("file")
/// # ).get_matches();
/// .value_name("FILE")
/// # ;
pub fn value_name(mut self, name: &'b str) -> Self {
self.setb(ArgSettings::TakesValue);
if let Some(ref mut vals) = self.val_names {
let l = vals.len();
vals.insert(l, name);
Expand Down Expand Up @@ -924,6 +956,7 @@ impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>>
validator: a.validator.clone(),
overrides: a.overrides.clone(),
settings: a.settings.clone(),
val_delim: a.val_delim,
}
}
}
15 changes: 2 additions & 13 deletions src/args/arg_builder/flag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,14 @@ use args::AnyArg;
use args::settings::{ArgFlags, ArgSettings};

#[derive(Debug)]
#[doc(hidden)]
pub struct FlagBuilder<'n, 'e> {
pub name: &'n str,
/// The long version of the flag (i.e. word)
/// without the preceding `--`
pub long: Option<&'e str>,
/// The string of text that will displayed to
/// the user when the application's `help`
/// text is displayed
pub help: Option<&'e str>,
/// A list of names for other arguments that
/// *may not* be used with this flag
pub blacklist: Option<Vec<&'e str>>,
/// A list of names of other arguments that
/// are *required* to be used when this
/// flag is used
pub requires: Option<Vec<&'e str>>,
/// The short version (i.e. single character)
/// of the argument, no preceding `-`
pub short: Option<char>,
/// A list of names for other arguments that *mutually override* this flag
pub overrides: Option<Vec<&'e str>>,
pub settings: ArgFlags,
}
Expand Down Expand Up @@ -192,6 +180,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> {
fn min_vals(&self) -> Option<u8> { None }
fn short(&self) -> Option<char> { self.short }
fn long(&self) -> Option<&'e str> { self.long }
fn val_delim(&self) -> Option<char> { None }
}

#[cfg(test)]
Expand Down
14 changes: 5 additions & 9 deletions src/args/arg_builder/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,23 @@ use args::{AnyArg, Arg};
use args::settings::{ArgFlags, ArgSettings};

#[allow(missing_debug_implementations)]
#[doc(hidden)]
pub struct OptBuilder<'n, 'e> {
pub name: &'n str,
/// The short version (i.e. single character) of the argument, no preceding `-`
pub short: Option<char>,
/// The long version of the flag (i.e. word) without the preceding `--`
pub long: Option<&'e str>,
/// The string of text that will displayed to the user when the application's
/// `help` text is displayed
pub help: Option<&'e str>,
/// A list of names for other arguments that *may not* be used with this flag
pub blacklist: Option<Vec<&'e str>>,
/// A list of possible values for this argument
pub possible_vals: Option<Vec<&'e str>>,
/// A list of names of other arguments that are *required* to be used when
/// this flag is used
pub requires: Option<Vec<&'e str>>,
pub num_vals: Option<u8>,
pub min_vals: Option<u8>,
pub max_vals: Option<u8>,
pub val_names: Option<VecMap<&'e str>>,
pub validator: Option<Rc<Fn(String) -> StdResult<(), String>>>,
/// A list of names for other arguments that *mutually override* this flag
pub overrides: Option<Vec<&'e str>>,
pub settings: ArgFlags,
pub val_delim: Option<char>,
}

impl<'n, 'e> Default for OptBuilder<'n, 'e> {
Expand All @@ -52,6 +45,7 @@ impl<'n, 'e> Default for OptBuilder<'n, 'e> {
validator: None,
overrides: None,
settings: ArgFlags::new(),
val_delim: Some(','),
}
}
}
Expand Down Expand Up @@ -81,6 +75,7 @@ impl<'n, 'e> OptBuilder<'n, 'e> {
min_vals: a.min_vals,
max_vals: a.max_vals,
val_names: a.val_names.clone(),
val_delim: a.val_delim,
..Default::default()
};
if a.is_set(ArgSettings::Multiple) {
Expand Down Expand Up @@ -253,6 +248,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> {
fn min_vals(&self) -> Option<u8> { self.min_vals }
fn short(&self) -> Option<char> { self.short }
fn long(&self) -> Option<&'e str> { self.long }
fn val_delim(&self) -> Option<char> { self.val_delim }
}

#[cfg(test)]
Expand Down
33 changes: 11 additions & 22 deletions src/args/arg_builder/positional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,29 @@ use std::result::Result as StdResult;
use std::rc::Rc;
use std::io;

use vec_map::VecMap;

use Arg;
use args::AnyArg;
use args::settings::{ArgFlags, ArgSettings};

#[allow(missing_debug_implementations)]
#[doc(hidden)]
pub struct PosBuilder<'n, 'e> {
pub name: &'n str,
/// The string of text that will displayed to the user when the application's
/// `help` text is displayed
pub help: Option<&'e str>,
/// A list of names of other arguments that are *required* to be used when
/// this flag is used
pub requires: Option<Vec<&'e str>>,
/// A list of names for other arguments that *may not* be used with this flag
pub blacklist: Option<Vec<&'e str>>,
/// A list of possible values for this argument
pub possible_vals: Option<Vec<&'e str>>,
/// The index of the argument
pub index: u8,
pub num_vals: Option<u8>,
pub max_vals: Option<u8>,
pub min_vals: Option<u8>,
pub val_names: Option<VecMap<&'e str>>,
pub validator: Option<Rc<Fn(String) -> StdResult<(), String>>>,
/// A list of names for other arguments that *mutually override* this flag
pub overrides: Option<Vec<&'e str>>,
pub settings: ArgFlags,
pub val_delim: Option<char>,
}

impl<'n, 'e> Default for PosBuilder<'n, 'e> {
Expand All @@ -41,11 +38,13 @@ impl<'n, 'e> Default for PosBuilder<'n, 'e> {
possible_vals: None,
index: 0,
num_vals: None,
max_vals: None,
min_vals: None,
max_vals: None,
val_names: None,
validator: None,
overrides: None,
settings: ArgFlags::new(),
val_delim: Some(','),
}
}
}
Expand All @@ -66,19 +65,6 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
a.name);
}

if a.is_set(ArgSettings::TakesValue) {
panic!("Argument \"{}\" has conflicting requirements, both index() and \
takes_value(true) were supplied\n\n\tArguments with an index automatically \
take a value, you do not need to specify it manually",
a.name);
}

if a.val_names.is_some() {
panic!("Positional arguments (\"{}\") do not support named values, instead \
consider multiple positional arguments",
a.name);
}

// Create the Positional Argument Builder with each HashSet = None to only
// allocate
// those that require it
Expand All @@ -88,7 +74,9 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
num_vals: a.num_vals,
min_vals: a.min_vals,
max_vals: a.max_vals,
val_names: a.val_names.clone(),
help: a.help,
val_delim: a.val_delim,
..Default::default()
};
if a.is_set(ArgSettings::Multiple) || a.num_vals.is_some() || a.max_vals.is_some() || a.min_vals.is_some() {
Expand Down Expand Up @@ -204,6 +192,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> {
fn min_vals(&self) -> Option<u8> { self.min_vals }
fn short(&self) -> Option<char> { None }
fn long(&self) -> Option<&'e str> { None }
fn val_delim(&self) -> Option<char> { self.val_delim }
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit b1f906b

Please sign in to comment.