@@ -533,7 +533,12 @@ impl CodeMap {
533
533
Ok ( FileLines { file : lo. file , lines : lines} )
534
534
}
535
535
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
+ {
537
542
if sp. lo ( ) > sp. hi ( ) {
538
543
return Err ( SpanSnippetError :: IllFormedSpan ( sp) ) ;
539
544
}
@@ -567,9 +572,9 @@ impl CodeMap {
567
572
}
568
573
569
574
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) ) ;
571
576
} 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) ) ;
573
578
} else {
574
579
return Err ( SpanSnippetError :: SourceNotAvailable {
575
580
filename : local_begin. fm . name . clone ( )
@@ -578,6 +583,17 @@ impl CodeMap {
578
583
}
579
584
}
580
585
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
+
581
597
/// Given a `Span`, try to get a shorter span ending before the first occurrence of `c` `char`
582
598
pub fn span_until_char ( & self , sp : Span , c : char ) -> Span {
583
599
match self . span_to_snippet ( sp) {
@@ -593,6 +609,32 @@ impl CodeMap {
593
609
}
594
610
}
595
611
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
+
596
638
/// Given a `Span`, get a new `Span` covering the first token and all its trailing whitespace or
597
639
/// the original `Span`.
598
640
///
@@ -615,6 +657,24 @@ impl CodeMap {
615
657
sp
616
658
}
617
659
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
+
618
678
/// Given a `Span`, try to get a shorter span ending just after the first occurrence of `char`
619
679
/// `c`.
620
680
pub fn span_through_char ( & self , sp : Span , c : char ) -> Span {
0 commit comments