@@ -524,6 +524,7 @@ pub(crate) enum DisplaySourceLine<'a> {
524524 Content {
525525 text : & ' a str ,
526526 range : ( usize , usize ) , // meta information for annotation placement.
527+ end_line : EndLine ,
527528 } ,
528529 /// An empty source line.
529530 Empty ,
@@ -658,7 +659,8 @@ impl<'a> CursorLines<'a> {
658659 }
659660}
660661
661- enum EndLine {
662+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
663+ pub ( crate ) enum EndLine {
662664 Eof = 0 ,
663665 Crlf = 1 ,
664666 Lf = 2 ,
@@ -847,13 +849,20 @@ fn format_header<'a>(
847849
848850 for item in body {
849851 if let DisplayLine :: Source {
850- line : DisplaySourceLine :: Content { text, range } ,
852+ line :
853+ DisplaySourceLine :: Content {
854+ text,
855+ range,
856+ end_line,
857+ } ,
851858 lineno,
852859 ..
853860 } = item
854861 {
855- if main_range >= range. 0 && main_range <= range. 1 {
856- let char_column = text[ 0 ..( main_range - range. 0 ) ] . chars ( ) . count ( ) ;
862+ if main_range >= range. 0 && main_range <= range. 1 + * end_line as usize {
863+ let char_column = text[ 0 ..( main_range - range. 0 ) . min ( text. len ( ) ) ]
864+ . chars ( )
865+ . count ( ) ;
857866 col = char_column + 1 ;
858867 line_offset = lineno. unwrap_or ( 1 ) ;
859868 break ;
@@ -927,8 +936,18 @@ fn fold_body(body: Vec<DisplayLine<'_>>) -> Vec<DisplayLine<'_>> {
927936 let mut unhighlighed_lines = vec ! [ ] ;
928937 for line in body {
929938 match & line {
930- DisplayLine :: Source { annotations, .. } => {
931- if annotations. is_empty ( ) {
939+ DisplayLine :: Source {
940+ annotations,
941+ inline_marks,
942+ ..
943+ } => {
944+ if annotations. is_empty ( )
945+ // A multiline start mark (`/`) needs be treated as an
946+ // annotation or the line could get folded.
947+ && inline_marks
948+ . iter ( )
949+ . all ( |m| m. mark_type != DisplayMarkType :: AnnotationStart )
950+ {
932951 unhighlighed_lines. push ( line) ;
933952 } else {
934953 if lines. is_empty ( ) {
@@ -1016,12 +1035,14 @@ fn format_body(
10161035 for ( idx, ( line, end_line) ) in CursorLines :: new ( snippet. source ) . enumerate ( ) {
10171036 let line_length: usize = line. len ( ) ;
10181037 let line_range = ( current_index, current_index + line_length) ;
1038+ let end_line_size = end_line as usize ;
10191039 body. push ( DisplayLine :: Source {
10201040 lineno : Some ( current_line) ,
10211041 inline_marks : vec ! [ ] ,
10221042 line : DisplaySourceLine :: Content {
10231043 text : line,
10241044 range : line_range,
1045+ end_line,
10251046 } ,
10261047 annotations : vec ! [ ] ,
10271048 } ) ;
@@ -1045,7 +1066,7 @@ fn format_body(
10451066 let line_start_index = line_range. 0 ;
10461067 let line_end_index = line_range. 1 ;
10471068 current_line += 1 ;
1048- current_index += line_length + end_line as usize ;
1069+ current_index += line_length + end_line_size ;
10491070
10501071 // It would be nice to use filter_drain here once it's stable.
10511072 annotations. retain ( |annotation| {
@@ -1057,18 +1078,24 @@ fn format_body(
10571078 } ;
10581079 let label_right = annotation. label . map_or ( 0 , |label| label. len ( ) + 1 ) ;
10591080 match annotation. range {
1060- Range { start, .. } if start > line_end_index => true ,
1081+ // This handles if the annotation is on the next line. We add
1082+ // the `end_line_size` to account for annotating the line end.
1083+ Range { start, .. } if start > line_end_index + end_line_size => true ,
1084+ // This handles the case where an annotation is contained
1085+ // within the current line including any line-end characters.
10611086 Range { start, end }
1062- if start >= line_start_index && end <= line_end_index
1063- // Allow annotating eof or stripped eol
1064- || start == line_end_index && end - start <= 1 =>
1087+ if start >= line_start_index
1088+ // We add at least one to `line_end_index` to allow
1089+ // highlighting the end of a file
1090+ && end <= line_end_index + max ( end_line_size, 1 ) =>
10651091 {
10661092 if let DisplayLine :: Source {
10671093 ref mut annotations,
10681094 ..
10691095 } = body[ body_idx]
10701096 {
1071- let annotation_start_col = line[ 0 ..( start - line_start_index) ]
1097+ let annotation_start_col = line
1098+ [ 0 ..( start - line_start_index) . min ( line_length) ]
10721099 . chars ( )
10731100 . map ( |c| unicode_width:: UnicodeWidthChar :: width ( c) . unwrap_or ( 0 ) )
10741101 . sum :: < usize > ( ) ;
@@ -1101,11 +1128,16 @@ fn format_body(
11011128 }
11021129 false
11031130 }
1131+ // This handles the case where a multiline annotation starts
1132+ // somewhere on the current line, including any line-end chars
11041133 Range { start, end }
11051134 if start >= line_start_index
1106- && start <= line_end_index
1135+ // The annotation can start on a line ending
1136+ && start <= line_end_index + end_line_size. saturating_sub ( 1 )
11071137 && end > line_end_index =>
11081138 {
1139+ // Special case for multiline annotations that start at the
1140+ // beginning of a line, which requires a special mark (`/`)
11091141 if start - line_start_index == 0 {
11101142 if let DisplayLine :: Source {
11111143 ref mut inline_marks,
@@ -1122,7 +1154,8 @@ fn format_body(
11221154 ..
11231155 } = body[ body_idx]
11241156 {
1125- let annotation_start_col = line[ 0 ..( start - line_start_index) ]
1157+ let annotation_start_col = line
1158+ [ 0 ..( start - line_start_index) . min ( line_length) ]
11261159 . chars ( )
11271160 . map ( |c| unicode_width:: UnicodeWidthChar :: width ( c) . unwrap_or ( 0 ) )
11281161 . sum :: < usize > ( ) ;
@@ -1147,7 +1180,11 @@ fn format_body(
11471180 }
11481181 true
11491182 }
1150- Range { start, end } if start < line_start_index && end > line_end_index => {
1183+ // This handles the case where a multiline annotation starts
1184+ // somewhere before this line and ends after it as well
1185+ Range { start, end }
1186+ if start < line_start_index && end > line_end_index + max ( end_line_size, 1 ) =>
1187+ {
11511188 if let DisplayLine :: Source {
11521189 ref mut inline_marks,
11531190 ..
@@ -1160,10 +1197,14 @@ fn format_body(
11601197 }
11611198 true
11621199 }
1200+ // This handles the case where a multiline annotation ends
1201+ // somewhere on the current line, including any line-end chars
11631202 Range { start, end }
11641203 if start < line_start_index
11651204 && end >= line_start_index
1166- && end <= line_end_index =>
1205+ // We add at least one to `line_end_index` to allow
1206+ // highlighting the end of a file
1207+ && end <= line_end_index + max ( end_line_size, 1 ) =>
11671208 {
11681209 if let DisplayLine :: Source {
11691210 ref mut inline_marks,
@@ -1175,13 +1216,21 @@ fn format_body(
11751216 mark_type : DisplayMarkType :: AnnotationThrough ,
11761217 annotation_type : DisplayAnnotationType :: from ( annotation. level ) ,
11771218 } ) ;
1178- let end_mark = line[ 0 ..( end - line_start_index) ]
1219+ let end_mark = line[ 0 ..( end - line_start_index) . min ( line_length ) ]
11791220 . chars ( )
11801221 . map ( |c| unicode_width:: UnicodeWidthChar :: width ( c) . unwrap_or ( 0 ) )
11811222 . sum :: < usize > ( )
11821223 . saturating_sub ( 1 ) ;
1183-
1184- let end_plus_one = end_mark + 1 ;
1224+ // If the annotation ends on a line-end character, we
1225+ // need to annotate one past the end of the line
1226+ let ( end_mark, end_plus_one) = if end > line_end_index
1227+ // Special case for highlighting the end of a file
1228+ || ( end == line_end_index + 1 && end_line_size == 0 )
1229+ {
1230+ ( end_mark + 1 , end_mark + 2 )
1231+ } else {
1232+ ( end_mark, end_mark + 1 )
1233+ } ;
11851234
11861235 span_left_margin = min ( span_left_margin, end_mark) ;
11871236 span_right_margin = max ( span_right_margin, end_plus_one) ;
0 commit comments