Skip to content

Commit 6b3a5bd

Browse files
committed
fix(parser)!: Split on value delimiter after validating num_args
This will allow `num_args(0..=1).value_delimiter(',')` to work properly. This hacks in support for `require_value_delimiter` until we can remove it. This no longer recognzes value terminators in delimited lists. It looks like there is a bug with recognizing value terminators in positionals arguments. We'll need to dig into that more.
1 parent b731b6a commit 6b3a5bd

File tree

5 files changed

+141
-168
lines changed

5 files changed

+141
-168
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2323
- Replace `Arg::number_of_values` (average across occurrences) with `Arg::num_args` (per occurrence, raw CLI args, not parsed values)
2424
- `num_args(0)` no longer implies `takes_value(true).multiple_values(true)`
2525
- `num_args(1)` no longer implies `multiple_values(true)`
26-
- Does not check default values, only what the user explicitly passes in
26+
- Does not check default or env values, only what the user explicitly passes in
27+
- No longer terminates on delimited values
28+
- `Arg::value_terminator` must stand on its own now rather than being in a delimited list
2729
- Sometimes `Arg::default_missing_value` didn't require `num_args(0..=1)`, now it does
2830
- Replace `Arg::min_values` (across all occurrences) with `Arg::num_args(N..)` (per occurrence)
2931
- Replace `Arg::max_values` (across all occurrences) with `Arg::num_args(1..=M)` (per occurrence)

src/error/kind.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,8 @@ pub enum ErrorKind {
104104
/// # use clap::{Command, Arg, error::ErrorKind};
105105
/// let result = Command::new("prog")
106106
/// .arg(Arg::new("arg")
107-
/// .num_args(1..=2)
108-
/// .require_value_delimiter(true))
109-
/// .try_get_matches_from(vec!["prog", "too,many,values"]);
107+
/// .num_args(1..=2))
108+
/// .try_get_matches_from(vec!["prog", "too", "many", "values"]);
110109
/// assert!(result.is_err());
111110
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooManyValues);
112111
/// ```

src/parser/arg_matcher.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,9 @@ impl ArgMatcher {
202202
"ArgMatcher::needs_more_vals: o={}, pending={}",
203203
o.name, num_pending
204204
);
205-
if let Some(expected) = o.get_num_args() {
205+
if num_pending == 1 && o.is_require_value_delimiter_set() {
206+
false
207+
} else if let Some(expected) = o.get_num_args() {
206208
debug!(
207209
"ArgMatcher::needs_more_vals: expected={}, actual={}",
208210
expected, num_pending
@@ -221,19 +223,35 @@ impl ArgMatcher {
221223
&mut self,
222224
id: &Id,
223225
ident: Option<Identifier>,
226+
trailing_values: bool,
224227
) -> &mut Vec<OsString> {
225228
let pending = self.pending.get_or_insert_with(|| PendingArg {
226229
id: id.clone(),
227230
ident,
228231
raw_vals: Default::default(),
232+
trailing_idx: None,
229233
});
230234
debug_assert_eq!(pending.id, *id, "{}", INTERNAL_ERROR_MSG);
231235
if ident.is_some() {
232236
debug_assert_eq!(pending.ident, ident, "{}", INTERNAL_ERROR_MSG);
233237
}
238+
if trailing_values {
239+
pending
240+
.trailing_idx
241+
.get_or_insert_with(|| pending.raw_vals.len());
242+
}
234243
&mut pending.raw_vals
235244
}
236245

246+
pub(crate) fn start_trailing(&mut self) {
247+
if let Some(pending) = &mut self.pending {
248+
// Allow asserting its started on subsequent calls
249+
pending
250+
.trailing_idx
251+
.get_or_insert_with(|| pending.raw_vals.len());
252+
}
253+
}
254+
237255
pub(crate) fn take_pending(&mut self) -> Option<PendingArg> {
238256
self.pending.take()
239257
}

0 commit comments

Comments
 (0)