@@ -774,31 +774,41 @@ pub mod shell {
774774
775775 #[ derive( Clone , PartialEq , Debug ) ]
776776 pub enum Substitution < ' a > {
777- Ordinal ( u8 ) ,
778- Name ( & ' a str ) ,
779- Escape ,
777+ Ordinal ( u8 , ( usize , usize ) ) ,
778+ Name ( & ' a str , ( usize , usize ) ) ,
779+ Escape ( ( usize , usize ) ) ,
780780 }
781781
782782 impl < ' a > Substitution < ' a > {
783783 pub fn as_str ( & self ) -> String {
784- match * self {
785- Substitution :: Ordinal ( n) => format ! ( "${}" , n) ,
786- Substitution :: Name ( n) => format ! ( "${}" , n) ,
787- Substitution :: Escape => "$$" . into ( ) ,
784+ match self {
785+ Substitution :: Ordinal ( n, _ ) => format ! ( "${}" , n) ,
786+ Substitution :: Name ( n, _ ) => format ! ( "${}" , n) ,
787+ Substitution :: Escape ( _ ) => "$$" . into ( ) ,
788788 }
789789 }
790790
791791 pub fn position ( & self ) -> Option < ( usize , usize ) > {
792- match * self {
793- _ => None ,
792+ match self {
793+ Substitution :: Ordinal ( _, pos) |
794+ Substitution :: Name ( _, pos) |
795+ Substitution :: Escape ( pos) => Some ( * pos) ,
796+ }
797+ }
798+
799+ pub fn set_position ( & mut self , start : usize , end : usize ) {
800+ match self {
801+ Substitution :: Ordinal ( _, ref mut pos) |
802+ Substitution :: Name ( _, ref mut pos) |
803+ Substitution :: Escape ( ref mut pos) => * pos = ( start, end) ,
794804 }
795805 }
796806
797807 pub fn translate ( & self ) -> Option < String > {
798808 match * self {
799- Substitution :: Ordinal ( n) => Some ( format ! ( "{{{}}}" , n) ) ,
800- Substitution :: Name ( n) => Some ( format ! ( "{{{}}}" , n) ) ,
801- Substitution :: Escape => None ,
809+ Substitution :: Ordinal ( n, _ ) => Some ( format ! ( "{{{}}}" , n) ) ,
810+ Substitution :: Name ( n, _ ) => Some ( format ! ( "{{{}}}" , n) ) ,
811+ Substitution :: Escape ( _ ) => None ,
802812 }
803813 }
804814 }
@@ -807,20 +817,26 @@ pub mod shell {
807817 pub fn iter_subs ( s : & str ) -> Substitutions {
808818 Substitutions {
809819 s,
820+ pos : 0 ,
810821 }
811822 }
812823
813824 /// Iterator over substitutions in a string.
814825 pub struct Substitutions < ' a > {
815826 s : & ' a str ,
827+ pos : usize ,
816828 }
817829
818830 impl < ' a > Iterator for Substitutions < ' a > {
819831 type Item = Substitution < ' a > ;
820832 fn next ( & mut self ) -> Option < Self :: Item > {
821833 match parse_next_substitution ( self . s ) {
822- Some ( ( sub, tail) ) => {
834+ Some ( ( mut sub, tail) ) => {
823835 self . s = tail;
836+ if let Some ( ( start, end) ) = sub. position ( ) {
837+ sub. set_position ( start + self . pos , end + self . pos ) ;
838+ self . pos += end;
839+ }
824840 Some ( sub)
825841 } ,
826842 None => None ,
@@ -837,15 +853,15 @@ pub mod shell {
837853 let at = {
838854 let start = s. find ( '$' ) ?;
839855 match s[ start+1 ..] . chars ( ) . next ( ) ? {
840- '$' => return Some ( ( Substitution :: Escape , & s[ start+2 ..] ) ) ,
856+ '$' => return Some ( ( Substitution :: Escape ( ( start , start+ 2 ) ) , & s[ start+2 ..] ) ) ,
841857 c @ '0' ..= '9' => {
842858 let n = ( c as u8 ) - b'0' ;
843- return Some ( ( Substitution :: Ordinal ( n) , & s[ start+2 ..] ) ) ;
859+ return Some ( ( Substitution :: Ordinal ( n, ( start , start+ 2 ) ) , & s[ start+2 ..] ) ) ;
844860 } ,
845861 _ => { /* fall-through */ } ,
846862 }
847863
848- Cur :: new_at_start ( & s[ start ..] )
864+ Cur :: new_at ( & s[ ..] , start )
849865 } ;
850866
851867 let at = at. at_next_cp ( ) ?;
@@ -855,7 +871,10 @@ pub mod shell {
855871 None
856872 } else {
857873 let end = at_next_cp_while ( inner, is_ident_tail) ;
858- Some ( ( Substitution :: Name ( at. slice_between ( end) . unwrap ( ) ) , end. slice_after ( ) ) )
874+ let slice = at. slice_between ( end) . unwrap ( ) ;
875+ let start = at. at - 1 ;
876+ let end_pos = at. at + slice. len ( ) ;
877+ Some ( ( Substitution :: Name ( slice, ( start, end_pos) ) , end. slice_after ( ) ) )
859878 }
860879 }
861880
@@ -907,24 +926,24 @@ pub mod shell {
907926 fn test_escape ( ) {
908927 assert_eq ! ( pns( "has no escapes" ) , None ) ;
909928 assert_eq ! ( pns( "has no escapes, either $" ) , None ) ;
910- assert_eq ! ( pns( "*so* has a $$ escape" ) , Some ( ( S :: Escape , " escape" ) ) ) ;
911- assert_eq ! ( pns( "$$ leading escape" ) , Some ( ( S :: Escape , " leading escape" ) ) ) ;
912- assert_eq ! ( pns( "trailing escape $$" ) , Some ( ( S :: Escape , "" ) ) ) ;
929+ assert_eq ! ( pns( "*so* has a $$ escape" ) , Some ( ( S :: Escape ( ( 11 , 13 ) ) , " escape" ) ) ) ;
930+ assert_eq ! ( pns( "$$ leading escape" ) , Some ( ( S :: Escape ( ( 0 , 2 ) ) , " leading escape" ) ) ) ;
931+ assert_eq ! ( pns( "trailing escape $$" ) , Some ( ( S :: Escape ( ( 16 , 18 ) ) , "" ) ) ) ;
913932 }
914933
915934 #[ test]
916935 fn test_parse ( ) {
917936 macro_rules! assert_pns_eq_sub {
918- ( $in_: expr, $kind: ident( $arg: expr) ) => {
919- assert_eq!( pns( concat!( $in_, "!" ) ) , Some ( ( S :: $kind( $arg. into( ) ) , "!" ) ) )
937+ ( $in_: expr, $kind: ident( $arg: expr, $pos : expr ) ) => {
938+ assert_eq!( pns( concat!( $in_, "!" ) ) , Some ( ( S :: $kind( $arg. into( ) , $pos ) , "!" ) ) )
920939 } ;
921940 }
922941
923- assert_pns_eq_sub ! ( "$0" , Ordinal ( 0 ) ) ;
924- assert_pns_eq_sub ! ( "$1" , Ordinal ( 1 ) ) ;
925- assert_pns_eq_sub ! ( "$9" , Ordinal ( 9 ) ) ;
926- assert_pns_eq_sub ! ( "$N" , Name ( "N" ) ) ;
927- assert_pns_eq_sub ! ( "$NAME" , Name ( "NAME" ) ) ;
942+ assert_pns_eq_sub ! ( "$0" , Ordinal ( 0 , ( 0 , 2 ) ) ) ;
943+ assert_pns_eq_sub ! ( "$1" , Ordinal ( 1 , ( 0 , 2 ) ) ) ;
944+ assert_pns_eq_sub ! ( "$9" , Ordinal ( 9 , ( 0 , 2 ) ) ) ;
945+ assert_pns_eq_sub ! ( "$N" , Name ( "N" , ( 0 , 2 ) ) ) ;
946+ assert_pns_eq_sub ! ( "$NAME" , Name ( "NAME" , ( 0 , 5 ) ) ) ;
928947 }
929948
930949 #[ test]
@@ -961,13 +980,6 @@ mod strcursor {
961980 }
962981
963982 impl < ' a > StrCursor < ' a > {
964- pub fn new_at_start ( s : & ' a str ) -> StrCursor < ' a > {
965- StrCursor {
966- s,
967- at : 0 ,
968- }
969- }
970-
971983 pub fn new_at ( s : & ' a str , at : usize ) -> StrCursor < ' a > {
972984 StrCursor {
973985 s,
0 commit comments