3232//!
3333//! The above snippet has been built out of the following structure:
3434use crate :: snippet;
35+ use itertools:: FoldWhile :: { Continue , Done } ;
36+ use itertools:: Itertools ;
3537use std:: fmt:: { Display , Write } ;
38+ use std:: ops:: Range ;
3639use std:: { cmp, fmt} ;
3740
3841use crate :: renderer:: { stylesheet:: Stylesheet , Margin , Style } ;
@@ -766,7 +769,7 @@ fn format_slice(
766769 has_footer : bool ,
767770 margin : Option < Margin > ,
768771) -> Vec < DisplayLine < ' _ > > {
769- let main_range = slice. annotations . first ( ) . map ( |x| x. range . 0 ) ;
772+ let main_range = slice. annotations . first ( ) . map ( |x| x. range . start ) ;
770773 let origin = slice. origin ;
771774 let need_empty_header = origin. is_some ( ) || is_first;
772775 let mut body = format_body ( slice, need_empty_header, has_footer, margin) ;
@@ -804,13 +807,27 @@ fn format_header<'a>(
804807
805808 for item in body {
806809 if let DisplayLine :: Source {
807- line : DisplaySourceLine :: Content { range , .. } ,
810+ line : DisplaySourceLine :: Content { text , range } ,
808811 lineno,
809812 ..
810813 } = item
811814 {
812815 if main_range >= range. 0 && main_range <= range. 1 {
813- col = main_range - range. 0 + 1 ;
816+ let char_column = text
817+ . chars ( )
818+ . map ( |c| unicode_width:: UnicodeWidthChar :: width ( c) . unwrap_or ( 0 ) )
819+ . chain ( std:: iter:: once ( 1 ) ) // treat the end of line as single-width
820+ . enumerate ( )
821+ . fold_while ( ( 0 , 0 ) , |( count, acc) , ( i, width) | {
822+ if acc <= main_range - range. 0 {
823+ Continue ( ( i, acc + width) )
824+ } else {
825+ Done ( ( count, acc) )
826+ }
827+ } )
828+ . into_inner ( )
829+ . 0 ;
830+ col = char_column + 1 ;
814831 line_offset = lineno. unwrap_or ( 1 ) ;
815832 break ;
816833 }
@@ -932,11 +949,11 @@ fn format_body(
932949 has_footer : bool ,
933950 margin : Option < Margin > ,
934951) -> Vec < DisplayLine < ' _ > > {
935- let source_len = slice. source . chars ( ) . count ( ) ;
952+ let source_len = slice. source . len ( ) ;
936953 if let Some ( bigger) = slice. annotations . iter ( ) . find_map ( |x| {
937954 // Allow highlighting one past the last character in the source.
938- if source_len + 1 < x. range . 1 {
939- Some ( x. range )
955+ if source_len + 1 < x. range . end {
956+ Some ( & x. range )
940957 } else {
941958 None
942959 }
@@ -955,18 +972,14 @@ fn format_body(
955972 struct LineInfo {
956973 line_start_index : usize ,
957974 line_end_index : usize ,
958- // How many spaces each character in the line take up when displayed
959- char_widths : Vec < usize > ,
960975 }
961976
962977 for ( line, end_line) in CursorLines :: new ( slice. source ) {
963- let line_length = line. chars ( ) . count ( ) ;
964- let line_range = ( current_index, current_index + line_length) ;
965- let char_widths = line
978+ let line_length: usize = line
966979 . chars ( )
967980 . map ( |c| unicode_width:: UnicodeWidthChar :: width ( c) . unwrap_or ( 0 ) )
968- . chain ( std :: iter :: once ( 1 ) ) // treat the end of line as single-width
969- . collect :: < Vec < _ > > ( ) ;
981+ . sum ( ) ;
982+ let line_range = ( current_index , current_index + line_length ) ;
970983 body. push ( DisplayLine :: Source {
971984 lineno : Some ( current_line) ,
972985 inline_marks : vec ! [ ] ,
@@ -978,7 +991,6 @@ fn format_body(
978991 line_info. push ( LineInfo {
979992 line_start_index : line_range. 0 ,
980993 line_end_index : line_range. 1 ,
981- char_widths,
982994 } ) ;
983995 current_line += 1 ;
984996 current_index += line_length + end_line as usize ;
@@ -991,7 +1003,6 @@ fn format_body(
9911003 LineInfo {
9921004 line_start_index,
9931005 line_end_index,
994- char_widths,
9951006 } ,
9961007 ) in line_info. into_iter ( ) . enumerate ( )
9971008 {
@@ -1007,21 +1018,13 @@ fn format_body(
10071018 _ => DisplayAnnotationType :: from ( annotation. annotation_type ) ,
10081019 } ;
10091020 match annotation. range {
1010- ( start, _ ) if start > line_end_index => true ,
1011- ( start, end)
1021+ Range { start, .. } if start > line_end_index => true ,
1022+ Range { start, end }
10121023 if start >= line_start_index && end <= line_end_index
10131024 || start == line_end_index && end - start <= 1 =>
10141025 {
1015- let annotation_start_col = char_widths
1016- . iter ( )
1017- . take ( start - line_start_index)
1018- . sum :: < usize > ( )
1019- - margin_left;
1020- let annotation_end_col = char_widths
1021- . iter ( )
1022- . take ( end - line_start_index)
1023- . sum :: < usize > ( )
1024- - margin_left;
1026+ let annotation_start_col = start - line_start_index - margin_left;
1027+ let annotation_end_col = end - line_start_index - margin_left;
10251028 let range = ( annotation_start_col, annotation_end_col) ;
10261029 body. insert (
10271030 body_idx + 1 ,
@@ -1045,7 +1048,7 @@ fn format_body(
10451048 annotation_line_count += 1 ;
10461049 false
10471050 }
1048- ( start, end)
1051+ Range { start, end }
10491052 if start >= line_start_index
10501053 && start <= line_end_index
10511054 && end > line_end_index =>
@@ -1064,10 +1067,7 @@ fn format_body(
10641067 } ) ;
10651068 }
10661069 } else {
1067- let annotation_start_col = char_widths
1068- . iter ( )
1069- . take ( start - line_start_index)
1070- . sum :: < usize > ( ) ;
1070+ let annotation_start_col = start - line_start_index;
10711071 let range = ( annotation_start_col, annotation_start_col + 1 ) ;
10721072 body. insert (
10731073 body_idx + 1 ,
@@ -1092,7 +1092,7 @@ fn format_body(
10921092 }
10931093 true
10941094 }
1095- ( start, end) if start < line_start_index && end > line_end_index => {
1095+ Range { start, end } if start < line_start_index && end > line_end_index => {
10961096 if let DisplayLine :: Source {
10971097 ref mut inline_marks,
10981098 ..
@@ -1107,7 +1107,7 @@ fn format_body(
11071107 }
11081108 true
11091109 }
1110- ( start, end)
1110+ Range { start, end }
11111111 if start < line_start_index
11121112 && end >= line_start_index
11131113 && end <= line_end_index =>
@@ -1125,11 +1125,7 @@ fn format_body(
11251125 } ) ;
11261126 }
11271127
1128- let end_mark = char_widths
1129- . iter ( )
1130- . take ( end - line_start_index)
1131- . sum :: < usize > ( )
1132- . saturating_sub ( 1 ) ;
1128+ let end_mark = ( end - line_start_index) . saturating_sub ( 1 ) ;
11331129 let range = ( end_mark - margin_left, ( end_mark + 1 ) - margin_left) ;
11341130 body. insert (
11351131 body_idx + 1 ,
@@ -1380,7 +1376,7 @@ mod tests {
13801376 let line_2 = "This is line 2" ;
13811377 let source = [ line_1, line_2] . join ( "\n " ) ;
13821378 // In line 2
1383- let range = ( 22 , 24 ) ;
1379+ let range = 22 .. 24 ;
13841380 let input = snippet:: Snippet {
13851381 title : None ,
13861382 footer : vec ! [ ] ,
@@ -1389,7 +1385,7 @@ mod tests {
13891385 line_start: 5402 ,
13901386 origin: None ,
13911387 annotations: vec![ snippet:: SourceAnnotation {
1392- range,
1388+ range: range . clone ( ) ,
13931389 label: "Test annotation" ,
13941390 annotation_type: snippet:: AnnotationType :: Info ,
13951391 } ] ,
@@ -1430,7 +1426,10 @@ mod tests {
14301426 style: DisplayTextStyle :: Regular ,
14311427 } ] ,
14321428 } ,
1433- range: ( range. 0 - ( line_1. len( ) + 1 ) , range. 1 - ( line_1. len( ) + 1 ) ) ,
1429+ range: (
1430+ range. start - ( line_1. len( ) + 1 ) ,
1431+ range. end - ( line_1. len( ) + 1 ) ,
1432+ ) ,
14341433 annotation_type: DisplayAnnotationType :: Info ,
14351434 annotation_part: DisplayAnnotationPart :: Standalone ,
14361435 } ,
@@ -1480,7 +1479,7 @@ mod tests {
14801479 footer : vec ! [ ] ,
14811480 slices : vec ! [ snippet:: Slice {
14821481 annotations: vec![ snippet:: SourceAnnotation {
1483- range: ( 0 , source. len( ) + 2 ) ,
1482+ range: 0 .. source. len( ) + 2 ,
14841483 label,
14851484 annotation_type: snippet:: AnnotationType :: Error ,
14861485 } ] ,
@@ -1507,7 +1506,7 @@ mod tests {
15071506 line_start: 1 ,
15081507 origin: Some ( "<current file>" ) ,
15091508 annotations: vec![ snippet:: SourceAnnotation {
1510- range: ( 19 , 23 ) ,
1509+ range: 19 .. 23 ,
15111510 label: "oops" ,
15121511 annotation_type: snippet:: AnnotationType :: Error ,
15131512 } ] ,
0 commit comments