@@ -8,6 +8,7 @@ use std::io::{self, BufWriter, Write};
8
8
use std:: os:: unix:: ffi:: OsStrExt ;
9
9
use std:: path:: PathBuf ;
10
10
use std:: slice:: Iter ;
11
+ use std:: iter:: Peekable ;
11
12
12
13
// Third Party
13
14
use vec_map:: { self , VecMap } ;
@@ -118,15 +119,14 @@ impl<'a, 'b> Parser<'a, 'b>
118
119
let out_dir = PathBuf :: from ( od) ;
119
120
let name = & * self . meta . bin_name . as_ref ( ) . unwrap ( ) . clone ( ) ;
120
121
let file_name = match for_shell {
121
-
122
+
122
123
Shell :: Bash => format ! ( "{}.bash-completion" , name) ,
123
124
Shell :: Fish => format ! ( "{}.fish" , name) ,
124
- Shell :: Zsh => format ! ( "_{}" , name)
125
+ Shell :: Zsh => format ! ( "_{}" , name) ,
125
126
} ;
126
127
127
128
let mut file = match File :: create ( out_dir. join ( file_name) ) {
128
- Err ( why) => panic ! ( "couldn't create completion file: {}" ,
129
- why. description( ) ) ,
129
+ Err ( why) => panic ! ( "couldn't create completion file: {}" , why. description( ) ) ,
130
130
Ok ( file) => file,
131
131
} ;
132
132
self . gen_completions_to ( for_shell, & mut file)
@@ -266,10 +266,16 @@ impl<'a, 'b> Parser<'a, 'b>
266
266
for ( i, o) in self . opts . iter_mut ( ) . enumerate ( ) . filter ( |& ( _, ref o) | o. disp_ord == 999 ) {
267
267
o. disp_ord = if unified { o. unified_ord } else { i } ;
268
268
}
269
- for ( i, f) in self . flags . iter_mut ( ) . enumerate ( ) . filter ( |& ( _, ref f) | f. disp_ord == 999 ) {
269
+ for ( i, f) in self . flags
270
+ . iter_mut ( )
271
+ . enumerate ( )
272
+ . filter ( |& ( _, ref f) | f. disp_ord == 999 ) {
270
273
f. disp_ord = if unified { f. unified_ord } else { i } ;
271
274
}
272
- for ( i, sc) in & mut self . subcommands . iter_mut ( ) . enumerate ( ) . filter ( |& ( _, ref sc) | sc. p . meta . disp_ord == 999 ) {
275
+ for ( i, sc) in & mut self . subcommands
276
+ . iter_mut ( )
277
+ . enumerate ( )
278
+ . filter ( |& ( _, ref sc) | sc. p . meta . disp_ord == 999 ) {
273
279
sc. p . meta . disp_ord = i;
274
280
}
275
281
}
@@ -517,12 +523,40 @@ impl<'a, 'b> Parser<'a, 'b>
517
523
}
518
524
519
525
// Next we verify that only the highest index has a .multiple(true) (if any)
520
- debug_assert ! ( !self . positionals
521
- . values( )
522
- . any( |a| a. settings. is_set( ArgSettings :: Multiple ) &&
523
- ( a. index as usize != self . positionals. len( ) )
524
- ) ,
525
- "Only the positional argument with the highest index may accept multiple values" ) ;
526
+ if self . positionals ( )
527
+ . any ( |a| {
528
+ a. settings . is_set ( ArgSettings :: Multiple ) &&
529
+ ( a. index as usize != self . positionals . len ( ) )
530
+ } ) {
531
+ debug_assert ! ( self . positionals( )
532
+ . filter( |p| p. settings. is_set( ArgSettings :: Multiple )
533
+ && p. num_vals. is_none( ) ) . map( |_| 1 ) . sum:: <u64 >( ) <= 1 ,
534
+ "Only one positional argument with .multiple(true) set is allowed per command" ) ;
535
+
536
+ debug_assert ! ( self . positionals( )
537
+ . rev( )
538
+ . next( )
539
+ . unwrap( )
540
+ . is_set( ArgSettings :: Required ) ,
541
+ "When using a positional argument with .multiple(true) that is *not the last* \
542
+ positional argument, the last positional argument (i.e the one with the highest \
543
+ index) *must* have .required(true) set.") ;
544
+
545
+ debug_assert ! ( {
546
+ let num = self . positionals. len( ) - 1 ;
547
+ self . positionals. get( num) . unwrap( ) . is_set( ArgSettings :: Multiple )
548
+ } ,
549
+ "Only the last positional argument, or second to last positional argument may be set to .multiple(true)" ) ;
550
+
551
+ self . set ( AppSettings :: LowIndexMultiplePositional ) ;
552
+ }
553
+
554
+ debug_assert ! ( self . positionals( )
555
+ . filter( |p| p. settings. is_set( ArgSettings :: Multiple )
556
+ && p. num_vals. is_none( ) )
557
+ . map( |_| 1 )
558
+ . sum:: <u64 >( ) <= 1 ,
559
+ "Only one positional argument with .multiple(true) set is allowed per command" ) ;
526
560
527
561
// If it's required we also need to ensure all previous positionals are
528
562
// required too
@@ -666,10 +700,10 @@ impl<'a, 'b> Parser<'a, 'b>
666
700
#[ cfg_attr( feature = "lints" , allow( while_let_on_iterator) ) ]
667
701
pub fn get_matches_with < I , T > ( & mut self ,
668
702
matcher : & mut ArgMatcher < ' a > ,
669
- it : & mut I )
703
+ it : & mut Peekable < I > )
670
704
-> ClapResult < ( ) >
671
705
where I : Iterator < Item = T > ,
672
- T : Into < OsString >
706
+ T : Into < OsString > + Clone
673
707
{
674
708
debugln ! ( "fn=get_matches_with;" ) ;
675
709
// First we create the `--help` and `--version` arguments and add them if
@@ -684,15 +718,7 @@ impl<'a, 'b> Parser<'a, 'b>
684
718
debugln ! ( "Begin parsing '{:?}' ({:?})" , arg_os, & * arg_os. as_bytes( ) ) ;
685
719
686
720
// Is this a new argument, or values from a previous option?
687
- debug ! ( "Starts new arg..." ) ;
688
- let starts_new_arg = if arg_os. starts_with ( b"-" ) {
689
- sdebugln ! ( "Maybe" ) ;
690
- // a singe '-' by itself is a value and typically means "stdin" on unix systems
691
- !( arg_os. len_ ( ) == 1 )
692
- } else {
693
- sdebugln ! ( "No" ) ;
694
- false
695
- } ;
721
+ let starts_new_arg = is_new_arg ( & arg_os) ;
696
722
697
723
// Has the user already passed '--'? Meaning only positional args follow
698
724
if !self . trailing_vals {
@@ -739,15 +765,16 @@ impl<'a, 'b> Parser<'a, 'b>
739
765
arg_os. to_string_lossy( ) . parse:: <f64 >( ) . is_ok( ) ) ) ;
740
766
if needs_val_of. is_none ( ) {
741
767
if self . is_set ( AppSettings :: AllowNegativeNumbers ) {
742
- if !( arg_os. to_string_lossy ( ) . parse :: < i64 > ( ) . is_ok ( ) || arg_os. to_string_lossy ( ) . parse :: < f64 > ( ) . is_ok ( ) ) {
768
+ if !( arg_os. to_string_lossy ( ) . parse :: < i64 > ( ) . is_ok ( ) ||
769
+ arg_os. to_string_lossy ( ) . parse :: < f64 > ( ) . is_ok ( ) ) {
743
770
return Err ( Error :: unknown_argument ( & * arg_os. to_string_lossy ( ) ,
744
771
"" ,
745
772
& * self . create_current_usage ( matcher) ,
746
773
self . color ( ) ) ) ;
747
774
}
748
775
} else if !self . is_set ( AppSettings :: AllowLeadingHyphen ) {
749
776
continue ;
750
- }
777
+ }
751
778
} else {
752
779
continue ;
753
780
}
@@ -775,6 +802,26 @@ impl<'a, 'b> Parser<'a, 'b>
775
802
}
776
803
}
777
804
805
+ debugln ! ( "Positional counter...{}" , pos_counter) ;
806
+ debug ! ( "Checking for low index multiples..." ) ;
807
+ if self . is_set ( AppSettings :: LowIndexMultiplePositional ) && pos_counter == ( self . positionals . len ( ) - 1 ) {
808
+ sdebugln ! ( "Found" ) ;
809
+ if let Some ( na) = it. peek ( ) {
810
+ let n = ( * na) . clone ( ) . into ( ) ;
811
+ if is_new_arg ( & n) || self . possible_subcommand ( & n) || suggestions:: did_you_mean ( & n. to_string_lossy ( ) ,
812
+ self . subcommands
813
+ . iter ( )
814
+ . map ( |s| & s. p . meta . name ) ) . is_some ( ) {
815
+ debugln ! ( "Bumping the positional counter..." ) ;
816
+ pos_counter += 1 ;
817
+ }
818
+ } else {
819
+ debugln ! ( "Bumping the positional counter..." ) ;
820
+ pos_counter += 1 ;
821
+ }
822
+ } else {
823
+ sdebugln ! ( "None" ) ;
824
+ }
778
825
if let Some ( p) = self . positionals . get ( pos_counter) {
779
826
parse_positional ! ( self , p, arg_os, pos_counter, matcher) ;
780
827
} else if self . settings . is_set ( AppSettings :: AllowExternalSubcommands ) {
@@ -953,10 +1000,10 @@ impl<'a, 'b> Parser<'a, 'b>
953
1000
fn parse_subcommand < I , T > ( & mut self ,
954
1001
sc_name : String ,
955
1002
matcher : & mut ArgMatcher < ' a > ,
956
- it : & mut I )
1003
+ it : & mut Peekable < I > )
957
1004
-> ClapResult < ( ) >
958
1005
where I : Iterator < Item = T > ,
959
- T : Into < OsString >
1006
+ T : Into < OsString > + Clone
960
1007
{
961
1008
use std:: fmt:: Write ;
962
1009
debugln ! ( "fn=parse_subcommand;" ) ;
@@ -1949,10 +1996,11 @@ impl<'a, 'b> Parser<'a, 'b>
1949
1996
}
1950
1997
None
1951
1998
}
1952
-
1999
+
1953
2000
fn find_flag ( & self , name : & str ) -> Option < & FlagBuilder < ' a , ' b > > {
1954
2001
for f in self . flags ( ) {
1955
- if f. name == name || f. aliases . as_ref ( ) . unwrap_or ( & vec ! [ ( "" , false ) ] ) . iter ( ) . any ( |& ( n, _) | n == name) {
2002
+ if f. name == name ||
2003
+ f. aliases . as_ref ( ) . unwrap_or ( & vec ! [ ( "" , false ) ] ) . iter ( ) . any ( |& ( n, _) | n == name) {
1956
2004
return Some ( f) ;
1957
2005
}
1958
2006
}
@@ -1961,7 +2009,8 @@ impl<'a, 'b> Parser<'a, 'b>
1961
2009
1962
2010
fn find_option ( & self , name : & str ) -> Option < & OptBuilder < ' a , ' b > > {
1963
2011
for o in self . opts ( ) {
1964
- if o. name == name || o. aliases . as_ref ( ) . unwrap_or ( & vec ! [ ( "" , false ) ] ) . iter ( ) . any ( |& ( n, _) | n == name) {
2012
+ if o. name == name ||
2013
+ o. aliases . as_ref ( ) . unwrap_or ( & vec ! [ ( "" , false ) ] ) . iter ( ) . any ( |& ( n, _) | n == name) {
1965
2014
return Some ( o) ;
1966
2015
}
1967
2016
}
@@ -1983,7 +2032,15 @@ impl<'a, 'b> Parser<'a, 'b>
1983
2032
debugln ! ( "Looking for sc...{}" , sc) ;
1984
2033
debugln ! ( "Currently in Parser...{}" , self . meta. bin_name. as_ref( ) . unwrap( ) ) ;
1985
2034
for s in self . subcommands . iter ( ) {
1986
- if s. p . meta . bin_name . as_ref ( ) . unwrap_or ( & String :: new ( ) ) == sc || ( s. p . meta . aliases . is_some ( ) && s. p . meta . aliases . as_ref ( ) . unwrap ( ) . iter ( ) . any ( |& ( s, _) | s == sc. split ( ' ' ) . rev ( ) . next ( ) . expect ( INTERNAL_ERROR_MSG ) ) ) {
2035
+ if s. p . meta . bin_name . as_ref ( ) . unwrap_or ( & String :: new ( ) ) == sc ||
2036
+ ( s. p . meta . aliases . is_some ( ) &&
2037
+ s. p
2038
+ . meta
2039
+ . aliases
2040
+ . as_ref ( )
2041
+ . unwrap ( )
2042
+ . iter ( )
2043
+ . any ( |& ( s, _) | s == sc. split ( ' ' ) . rev ( ) . next ( ) . expect ( INTERNAL_ERROR_MSG ) ) ) {
1987
2044
return Some ( s) ;
1988
2045
}
1989
2046
if let Some ( app) = s. p . find_subcommand ( sc) {
@@ -2019,3 +2076,17 @@ impl<'a, 'b> Clone for Parser<'a, 'b>
2019
2076
}
2020
2077
}
2021
2078
}
2079
+
2080
+ #[ inline]
2081
+ fn is_new_arg ( arg_os : & OsStr ) -> bool {
2082
+ // Is this a new argument, or values from a previous option?
2083
+ debug ! ( "Starts new arg..." ) ;
2084
+ if arg_os. starts_with ( b"-" ) {
2085
+ sdebugln ! ( "Maybe" ) ;
2086
+ // a singe '-' by itself is a value and typically means "stdin" on unix systems
2087
+ !( arg_os. len_ ( ) == 1 )
2088
+ } else {
2089
+ sdebugln ! ( "No" ) ;
2090
+ false
2091
+ }
2092
+ }
0 commit comments