Skip to content

Commit f9e6925

Browse files
committed
imp(Value Delimiters): changes the default value delimiter rules
Prior to this change, values were always delimited by default. This was causing issues with code where the arg had a single value, and contained valid commas and shouldn't be delimited. This commit changes the rules slightly so that values are not delimited by default, *unless* one of the methods which implies multiple values was used (max_values, value_names, etc.). This means single value args should *not* be delimited by default. If one wishes to use the old way, they can add `Arg::use_delimiter(true)` to such code. Closes #655
1 parent 9881a4a commit f9e6925

File tree

3 files changed

+60
-19
lines changed

3 files changed

+60
-19
lines changed

src/args/arg.rs

+36-7
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ impl<'a, 'b> Default for Arg<'a, 'b> {
9696
validator: None,
9797
overrides: None,
9898
settings: ArgFlags::new(),
99-
val_delim: Some(','),
99+
val_delim: None,
100100
default_val: None,
101101
disp_ord: 999,
102102
r_unless: None,
@@ -1277,8 +1277,12 @@ impl<'a, 'b> Arg<'a, 'b> {
12771277
/// [option]: ./struct.Arg.html#method.takes_value
12781278
/// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values
12791279
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
1280-
pub fn multiple(self, multi: bool) -> Self {
1280+
pub fn multiple(mut self, multi: bool) -> Self {
12811281
if multi {
1282+
if self.settings.is_set(ArgSettings::ValueDelimiterNotSet) &&
1283+
self.settings.is_set(ArgSettings::TakesValue) {
1284+
self = self.use_delimiter(true);
1285+
}
12821286
self.set(ArgSettings::Multiple)
12831287
} else {
12841288
self.unset(ArgSettings::Multiple)
@@ -1649,6 +1653,13 @@ impl<'a, 'b> Arg<'a, 'b> {
16491653
/// ```
16501654
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
16511655
pub fn number_of_values(mut self, qty: u64) -> Self {
1656+
if qty > 1 && self.settings.is_set(ArgSettings::ValueDelimiterNotSet) {
1657+
self.unsetb(ArgSettings::ValueDelimiterNotSet);
1658+
self.setb(ArgSettings::UseValueDelimiter);
1659+
} else {
1660+
self = self.use_delimiter(false);
1661+
}
1662+
self.setb(ArgSettings::TakesValue);
16521663
self.num_vals = Some(qty);
16531664
self
16541665
}
@@ -1747,6 +1758,13 @@ impl<'a, 'b> Arg<'a, 'b> {
17471758
/// ```
17481759
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
17491760
pub fn max_values(mut self, qty: u64) -> Self {
1761+
if qty > 1 && self.settings.is_set(ArgSettings::ValueDelimiterNotSet) {
1762+
self.unsetb(ArgSettings::ValueDelimiterNotSet);
1763+
self.setb(ArgSettings::UseValueDelimiter);
1764+
} else {
1765+
self = self.use_delimiter(false);
1766+
}
1767+
self.setb(ArgSettings::TakesValue);
17501768
self.max_vals = Some(qty);
17511769
self
17521770
}
@@ -1857,11 +1875,16 @@ impl<'a, 'b> Arg<'a, 'b> {
18571875
/// [`Arg::value_delimiter`]: ./struct.Arg.html#method.value_delimiter
18581876
pub fn use_delimiter(mut self, d: bool) -> Self {
18591877
if d {
1860-
self.val_delim = Some(',');
1861-
self.set(ArgSettings::UseValueDelimiter)
1878+
if self.val_delim.is_none() {
1879+
self.val_delim = Some(',');
1880+
}
1881+
self.setb(ArgSettings::TakesValue);
1882+
self.setb(ArgSettings::UseValueDelimiter);
1883+
self.unset(ArgSettings::ValueDelimiterNotSet)
18621884
} else {
18631885
self.val_delim = None;
1864-
self.unset(ArgSettings::UseValueDelimiter)
1886+
self.unsetb(ArgSettings::UseValueDelimiter);
1887+
self.unset(ArgSettings::ValueDelimiterNotSet)
18651888
}
18661889
}
18671890

@@ -1939,6 +1962,7 @@ impl<'a, 'b> Arg<'a, 'b> {
19391962
/// ```
19401963
pub fn require_delimiter(mut self, d: bool) -> Self {
19411964
if d {
1965+
self.unsetb(ArgSettings::ValueDelimiterNotSet);
19421966
self.setb(ArgSettings::UseValueDelimiter);
19431967
self.set(ArgSettings::RequireDelimiter)
19441968
} else {
@@ -1972,8 +1996,9 @@ impl<'a, 'b> Arg<'a, 'b> {
19721996
/// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter
19731997
/// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value
19741998
pub fn value_delimiter(mut self, d: &str) -> Self {
1975-
self = self.set(ArgSettings::TakesValue);
1976-
self = self.set(ArgSettings::UseValueDelimiter);
1999+
self.unsetb(ArgSettings::ValueDelimiterNotSet);
2000+
self.setb(ArgSettings::TakesValue);
2001+
self.setb(ArgSettings::UseValueDelimiter);
19772002
self.val_delim = Some(d.chars()
19782003
.nth(0)
19792004
.expect("Failed to get value_delimiter from arg"));
@@ -2041,6 +2066,10 @@ impl<'a, 'b> Arg<'a, 'b> {
20412066
/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple
20422067
pub fn value_names(mut self, names: &[&'b str]) -> Self {
20432068
self.setb(ArgSettings::TakesValue);
2069+
if self.settings.is_set(ArgSettings::ValueDelimiterNotSet) {
2070+
self.unsetb(ArgSettings::ValueDelimiterNotSet);
2071+
self.setb(ArgSettings::UseValueDelimiter);
2072+
}
20442073
if let Some(ref mut vals) = self.val_names {
20452074
let mut l = vals.len();
20462075
for s in names {

src/args/settings.rs

+17-12
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@ use std::str::FromStr;
44

55
bitflags! {
66
flags Flags: u16 {
7-
const REQUIRED = 0b0000000001,
8-
const MULTIPLE = 0b0000000010,
9-
const EMPTY_VALS = 0b0000000100,
10-
const GLOBAL = 0b0000001000,
11-
const HIDDEN = 0b0000010000,
12-
const TAKES_VAL = 0b0000100000,
13-
const USE_DELIM = 0b0001000000,
14-
const NEXT_LINE_HELP = 0b0010000000,
15-
const R_UNLESS_ALL = 0b0100000000,
16-
const REQ_DELIM = 0b1000000000,
7+
const REQUIRED = 0b00000000001,
8+
const MULTIPLE = 0b00000000010,
9+
const EMPTY_VALS = 0b00000000100,
10+
const GLOBAL = 0b00000001000,
11+
const HIDDEN = 0b00000010000,
12+
const TAKES_VAL = 0b00000100000,
13+
const USE_DELIM = 0b00001000000,
14+
const NEXT_LINE_HELP = 0b00010000000,
15+
const R_UNLESS_ALL = 0b00100000000,
16+
const REQ_DELIM = 0b01000000000,
17+
const DELIM_NOT_SET = 0b10000000000,
1718
}
1819
}
1920

@@ -36,13 +37,14 @@ impl ArgFlags {
3637
UseValueDelimiter => USE_DELIM,
3738
NextLineHelp => NEXT_LINE_HELP,
3839
RequiredUnlessAll => R_UNLESS_ALL,
39-
RequireDelimiter => REQ_DELIM
40+
RequireDelimiter => REQ_DELIM,
41+
ValueDelimiterNotSet => DELIM_NOT_SET
4042
}
4143
}
4244

4345
impl Default for ArgFlags {
4446
fn default() -> Self {
45-
ArgFlags(EMPTY_VALS | USE_DELIM)
47+
ArgFlags(EMPTY_VALS | DELIM_NOT_SET)
4648
}
4749
}
4850

@@ -74,6 +76,8 @@ pub enum ArgSettings {
7476
RequireDelimiter,
7577
#[doc(hidden)]
7678
RequiredUnlessAll,
79+
#[doc(hidden)]
80+
ValueDelimiterNotSet,
7781
}
7882

7983
impl FromStr for ArgSettings {
@@ -90,6 +94,7 @@ impl FromStr for ArgSettings {
9094
"nextlinehelp" => Ok(ArgSettings::NextLineHelp),
9195
"requiredunlessall" => Ok(ArgSettings::RequiredUnlessAll),
9296
"requiredelimiter" => Ok(ArgSettings::RequireDelimiter),
97+
"valuedelimiternotset" => Ok(ArgSettings::ValueDelimiterNotSet),
9398
_ => Err("unknown ArgSetting, cannot convert from str".to_owned()),
9499
}
95100
}

src/usage_parser.rs

+7
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,13 @@ impl<'a> UsageParser<'a> {
174174
if dot_counter == 3 {
175175
debugln!("setting multiple");
176176
arg.setb(ArgSettings::Multiple);
177+
if arg.settings.is_set(ArgSettings::TakesValue) {
178+
arg.setb(ArgSettings::UseValueDelimiter);
179+
arg.unsetb(ArgSettings::ValueDelimiterNotSet);
180+
if arg.val_delim.is_none() {
181+
arg.val_delim = Some(',');
182+
}
183+
}
177184
self.prev = UsageToken::Multiple;
178185
self.pos += 1;
179186
break;

0 commit comments

Comments
 (0)