Skip to content

Commit f84e912

Browse files
committed
Add Matches::opt_positions
1 parent 87e60a0 commit f84e912

File tree

2 files changed

+41
-12
lines changed

2 files changed

+41
-12
lines changed

src/lib.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ impl Options {
354354

355355
let mut vals = (0..opts.len())
356356
.map(|_| Vec::new())
357-
.collect::<Vec<Vec<Optval>>>();
357+
.collect::<Vec<Vec<(usize, Optval)>>>();
358358
let mut free: Vec<String> = Vec::new();
359359
let args = args
360360
.into_iter()
@@ -365,6 +365,7 @@ impl Options {
365365
.map(|s| s.to_owned())
366366
}).collect::<::std::result::Result<Vec<_>, _>>()?;
367367
let mut args = args.into_iter().peekable();
368+
let mut arg_pos = 0;
368369
while let Some(cur) = args.next() {
369370
if !is_arg(&cur) {
370371
free.push(cur);
@@ -440,7 +441,7 @@ impl Options {
440441
if name_pos == names.len() && i_arg.is_some() {
441442
return Err(UnexpectedArgument(nm.to_string()));
442443
}
443-
vals[optid].push(Given);
444+
vals[optid].push((arg_pos, Given));
444445
}
445446
Maybe => {
446447
// Note that here we do not handle `--arg value`.
@@ -450,28 +451,29 @@ impl Options {
450451
// option at the end of the arguments when
451452
// FloatingFrees is in use.
452453
if let Some(i_arg) = i_arg.take() {
453-
vals[optid].push(Val(i_arg));
454+
vals[optid].push((arg_pos, Val(i_arg)));
454455
} else if was_long
455456
|| name_pos < names.len()
456457
|| args.peek().map_or(true, |n| is_arg(&n))
457458
{
458-
vals[optid].push(Given);
459+
vals[optid].push((arg_pos, Given));
459460
} else {
460-
vals[optid].push(Val(args.next().unwrap()));
461+
vals[optid].push((arg_pos, Val(args.next().unwrap())));
461462
}
462463
}
463464
Yes => {
464465
if let Some(i_arg) = i_arg.take() {
465-
vals[optid].push(Val(i_arg));
466+
vals[optid].push((arg_pos, Val(i_arg)));
466467
} else if let Some(n) = args.next() {
467-
vals[optid].push(Val(n));
468+
vals[optid].push((arg_pos, Val(n)));
468469
} else {
469470
return Err(ArgumentMissing(nm.to_string()));
470471
}
471472
}
472473
}
473474
}
474475
}
476+
arg_pos += 1;
475477
}
476478
debug_assert_eq!(vals.len(), opts.len());
477479
for (vals, opt) in vals.iter().zip(opts.iter()) {
@@ -701,8 +703,8 @@ enum Optval {
701703
pub struct Matches {
702704
/// Options that matched
703705
opts: Vec<Opt>,
704-
/// Values of the Options that matched
705-
vals: Vec<Vec<Optval>>,
706+
/// Values of the Options that matched and their positions
707+
vals: Vec<Vec<(usize, Optval)>>,
706708
/// Free string fragments
707709
pub free: Vec<String>,
708710
}
@@ -799,15 +801,15 @@ impl OptGroup {
799801
}
800802

801803
impl Matches {
802-
fn opt_vals(&self, nm: &str) -> Vec<Optval> {
804+
fn opt_vals(&self, nm: &str) -> Vec<(usize, Optval)> {
803805
match find_opt(&self.opts, &Name::from_str(nm)) {
804806
Some(id) => self.vals[id].clone(),
805807
None => panic!("No option '{}' defined", nm),
806808
}
807809
}
808810

809811
fn opt_val(&self, nm: &str) -> Option<Optval> {
810-
self.opt_vals(nm).into_iter().next()
812+
self.opt_vals(nm).into_iter().map(|(_, o)| o).next()
811813
}
812814
/// Returns true if an option was defined
813815
pub fn opt_defined(&self, nm: &str) -> bool {
@@ -824,6 +826,11 @@ impl Matches {
824826
self.opt_vals(nm).len()
825827
}
826828

829+
/// Returns a vector of all the positions in which an option was matched.
830+
pub fn opt_positions(&self, nm: &str) -> Vec<usize> {
831+
self.opt_vals(nm).into_iter().map(|(pos, _)| pos).collect()
832+
}
833+
827834
/// Returns true if any of several options were matched.
828835
pub fn opts_present(&self, names: &[String]) -> bool {
829836
names
@@ -851,7 +858,7 @@ impl Matches {
851858
pub fn opt_strs(&self, nm: &str) -> Vec<String> {
852859
self.opt_vals(nm)
853860
.into_iter()
854-
.filter_map(|v| match v {
861+
.filter_map(|(_, v)| match v {
855862
Val(s) => Some(s),
856863
_ => None,
857864
}).collect()

src/tests/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,3 +1188,25 @@ fn test_opt_get_default() {
11881188
let p_arg = matches.opt_get_default("p", 10.2);
11891189
assert_eq!(p_arg, Ok(1.1));
11901190
}
1191+
1192+
#[test]
1193+
fn test_opt_positions() {
1194+
let mut opts = Options::new();
1195+
opts.optflagmulti("a", "act", "Description");
1196+
opts.optflagmulti("r", "react", "Description");
1197+
1198+
let args: Vec<String> = ["-a", "-a", "-r", "-a", "-r", "-r"]
1199+
.iter()
1200+
.map(|x| x.to_string())
1201+
.collect();
1202+
1203+
let matches = &match opts.parse(&args) {
1204+
Ok(m) => m,
1205+
Err(e) => panic!("{}", e),
1206+
};
1207+
1208+
let a_pos = matches.opt_positions("a");
1209+
assert_eq!(a_pos, vec![0, 1, 3]);
1210+
let b_pos = matches.opt_positions("r");
1211+
assert_eq!(b_pos, vec![2, 4, 5]);
1212+
}

0 commit comments

Comments
 (0)