@@ -533,7 +533,12 @@ impl CodeMap {
533533 Ok ( FileLines { file : lo. file , lines : lines} )
534534 }
535535
536- pub fn span_to_snippet ( & self , sp : Span ) -> Result < String , SpanSnippetError > {
536+ /// Extract the source surrounding the given `Span` using the `extract_source` function. The
537+ /// extract function takes three arguments: a string slice containing the source, an index in
538+ /// the slice for the beginning of the span and an index in the slice for the end of the span.
539+ fn span_to_source < F > ( & self , sp : Span , extract_source : F ) -> Result < String , SpanSnippetError >
540+ where F : Fn ( & str , usize , usize ) -> String
541+ {
537542 if sp. lo ( ) > sp. hi ( ) {
538543 return Err ( SpanSnippetError :: IllFormedSpan ( sp) ) ;
539544 }
@@ -567,9 +572,9 @@ impl CodeMap {
567572 }
568573
569574 if let Some ( ref src) = local_begin. fm . src {
570- return Ok ( ( & src[ start_index.. end_index] ) . to_string ( ) ) ;
575+ return Ok ( extract_source ( src, start_index, end_index) ) ;
571576 } else if let Some ( src) = local_begin. fm . external_src . borrow ( ) . get_source ( ) {
572- return Ok ( ( & src[ start_index.. end_index] ) . to_string ( ) ) ;
577+ return Ok ( extract_source ( src, start_index, end_index) ) ;
573578 } else {
574579 return Err ( SpanSnippetError :: SourceNotAvailable {
575580 filename : local_begin. fm . name . clone ( )
@@ -578,6 +583,17 @@ impl CodeMap {
578583 }
579584 }
580585
586+ /// Return the source snippet as `String` corresponding to the given `Span`
587+ pub fn span_to_snippet ( & self , sp : Span ) -> Result < String , SpanSnippetError > {
588+ self . span_to_source ( sp, |src, start_index, end_index| src[ start_index..end_index]
589+ . to_string ( ) )
590+ }
591+
592+ /// Return the source snippet as `String` before the given `Span`
593+ pub fn span_to_prev_source ( & self , sp : Span ) -> Result < String , SpanSnippetError > {
594+ self . span_to_source ( sp, |src, start_index, _| src[ ..start_index] . to_string ( ) )
595+ }
596+
581597 /// Given a `Span`, try to get a shorter span ending before the first occurrence of `c` `char`
582598 pub fn span_until_char ( & self , sp : Span , c : char ) -> Span {
583599 match self . span_to_snippet ( sp) {
@@ -593,6 +609,32 @@ impl CodeMap {
593609 }
594610 }
595611
612+ /// Extend the given `Span` to just after the previous occurrence of `c`. Return the same span
613+ /// if no character could be found or if an error occurred while retrieving the code snippet.
614+ pub fn span_extend_to_prev_char ( & self , sp : Span , c : char ) -> Span {
615+ if let Ok ( prev_source) = self . span_to_prev_source ( sp) {
616+ let prev_source = prev_source. rsplit ( c) . nth ( 0 ) . unwrap_or ( "" ) . trim_left ( ) ;
617+ if !prev_source. is_empty ( ) && !prev_source. contains ( '\n' ) {
618+ return sp. with_lo ( BytePos ( sp. lo ( ) . 0 - prev_source. len ( ) as u32 ) ) ;
619+ }
620+ }
621+
622+ sp
623+ }
624+
625+ /// Extend the given `Span` to just after the previous occurrence of `pat`. Return the same span
626+ /// if no character could be found or if an error occurred while retrieving the code snippet.
627+ pub fn span_extend_to_prev_str ( & self , sp : Span , pat : & str ) -> Span {
628+ if let Ok ( prev_source) = self . span_to_prev_source ( sp) {
629+ let prev_source = prev_source. rsplit ( pat) . nth ( 0 ) . unwrap_or ( "" ) . trim_left ( ) ;
630+ if !prev_source. is_empty ( ) && !prev_source. contains ( '\n' ) {
631+ return sp. with_lo ( BytePos ( sp. lo ( ) . 0 - prev_source. len ( ) as u32 ) ) ;
632+ }
633+ }
634+
635+ sp
636+ }
637+
596638 /// Given a `Span`, get a new `Span` covering the first token and all its trailing whitespace or
597639 /// the original `Span`.
598640 ///
@@ -615,6 +657,24 @@ impl CodeMap {
615657 sp
616658 }
617659
660+ /// Given a `Span`, get a new `Span` covering the first token without its trailing whitespace or
661+ /// the original `Span` in case of error.
662+ ///
663+ /// If `sp` points to `"let mut x"`, then a span pointing at `"let"` will be returned.
664+ pub fn span_until_whitespace ( & self , sp : Span ) -> Span {
665+ if let Ok ( snippet) = self . span_to_snippet ( sp) {
666+ let mut offset = 0 ;
667+ // Get the bytes width of all the non-whitespace characters
668+ for c in snippet. chars ( ) . take_while ( |c| !c. is_whitespace ( ) ) {
669+ offset += c. len_utf8 ( ) ;
670+ }
671+ if offset > 1 {
672+ return sp. with_hi ( BytePos ( sp. lo ( ) . 0 + offset as u32 ) ) ;
673+ }
674+ }
675+ sp
676+ }
677+
618678 /// Given a `Span`, try to get a shorter span ending just after the first occurrence of `char`
619679 /// `c`.
620680 pub fn span_through_char ( & self , sp : Span , c : char ) -> Span {
0 commit comments