@@ -293,11 +293,23 @@ fn format_body(
293293 let mut body = vec ! [ ] ;
294294 let mut current_line = slice. line_start ;
295295 let mut current_index = 0 ;
296- let mut line_index_ranges = vec ! [ ] ;
296+ let mut line_info = vec ! [ ] ;
297+
298+ struct LineInfo {
299+ line_start_index : usize ,
300+ line_end_index : usize ,
301+ // How many spaces each character in the line take up when displayed
302+ char_widths : Vec < usize > ,
303+ }
297304
298305 for ( line, end_line) in CursorLines :: new ( slice. source ) {
299306 let line_length = line. chars ( ) . count ( ) ;
300307 let line_range = ( current_index, current_index + line_length) ;
308+ let char_widths = line
309+ . chars ( )
310+ . map ( |c| unicode_width:: UnicodeWidthChar :: width ( c) . unwrap_or ( 0 ) )
311+ . chain ( std:: iter:: once ( 1 ) ) // treat the end of line as signle-width
312+ . collect :: < Vec < _ > > ( ) ;
301313 body. push ( DisplayLine :: Source {
302314 lineno : Some ( current_line) ,
303315 inline_marks : vec ! [ ] ,
@@ -306,16 +318,28 @@ fn format_body(
306318 range : line_range,
307319 } ,
308320 } ) ;
309- line_index_ranges. push ( line_range) ;
321+ line_info. push ( LineInfo {
322+ line_start_index : line_range. 0 ,
323+ line_end_index : line_range. 1 ,
324+ char_widths,
325+ } ) ;
310326 current_line += 1 ;
311327 current_index += line_length + end_line as usize ;
312328 }
313329
314330 let mut annotation_line_count = 0 ;
315331 let mut annotations = slice. annotations ;
316- for ( idx, ( line_start, line_end) ) in line_index_ranges. into_iter ( ) . enumerate ( ) {
332+ for (
333+ idx,
334+ LineInfo {
335+ line_start_index,
336+ line_end_index,
337+ char_widths,
338+ } ,
339+ ) in line_info. into_iter ( ) . enumerate ( )
340+ {
317341 let margin_left = margin
318- . map ( |m| m. left ( line_end - line_start ) )
342+ . map ( |m| m. left ( line_end_index - line_start_index ) )
319343 . unwrap_or_default ( ) ;
320344 // It would be nice to use filter_drain here once it's stable.
321345 annotations = annotations
@@ -328,15 +352,22 @@ fn format_body(
328352 _ => DisplayAnnotationType :: from ( annotation. annotation_type ) ,
329353 } ;
330354 match annotation. range {
331- ( start, _) if start > line_end => true ,
355+ ( start, _) if start > line_end_index => true ,
332356 ( start, end)
333- if start >= line_start && end <= line_end
334- || start == line_end && end - start <= 1 =>
357+ if start >= line_start_index && end <= line_end_index
358+ || start == line_end_index && end - start <= 1 =>
335359 {
336- let range = (
337- ( start - line_start) - margin_left,
338- ( end - line_start) - margin_left,
339- ) ;
360+ let annotation_start_col = char_widths
361+ . iter ( )
362+ . take ( start - line_start_index)
363+ . sum :: < usize > ( )
364+ - margin_left;
365+ let annotation_end_col = char_widths
366+ . iter ( )
367+ . take ( end - line_start_index)
368+ . sum :: < usize > ( )
369+ - margin_left;
370+ let range = ( annotation_start_col, annotation_end_col) ;
340371 body. insert (
341372 body_idx + 1 ,
342373 DisplayLine :: Source {
@@ -359,8 +390,12 @@ fn format_body(
359390 annotation_line_count += 1 ;
360391 false
361392 }
362- ( start, end) if start >= line_start && start <= line_end && end > line_end => {
363- if start - line_start == 0 {
393+ ( start, end)
394+ if start >= line_start_index
395+ && start <= line_end_index
396+ && end > line_end_index =>
397+ {
398+ if start - line_start_index == 0 {
364399 if let DisplayLine :: Source {
365400 ref mut inline_marks,
366401 ..
@@ -374,7 +409,11 @@ fn format_body(
374409 } ) ;
375410 }
376411 } else {
377- let range = ( start - line_start, start - line_start + 1 ) ;
412+ let annotation_start_col = char_widths
413+ . iter ( )
414+ . take ( start - line_start_index)
415+ . sum :: < usize > ( ) ;
416+ let range = ( annotation_start_col, annotation_start_col + 1 ) ;
378417 body. insert (
379418 body_idx + 1 ,
380419 DisplayLine :: Source {
@@ -398,7 +437,7 @@ fn format_body(
398437 }
399438 true
400439 }
401- ( start, end) if start < line_start && end > line_end => {
440+ ( start, end) if start < line_start_index && end > line_end_index => {
402441 if let DisplayLine :: Source {
403442 ref mut inline_marks,
404443 ..
@@ -413,7 +452,11 @@ fn format_body(
413452 }
414453 true
415454 }
416- ( start, end) if start < line_start && end >= line_start && end <= line_end => {
455+ ( start, end)
456+ if start < line_start_index
457+ && end >= line_start_index
458+ && end <= line_end_index =>
459+ {
417460 if let DisplayLine :: Source {
418461 ref mut inline_marks,
419462 ..
@@ -427,11 +470,12 @@ fn format_body(
427470 } ) ;
428471 }
429472
430- let end_mark = ( end - line_start) . saturating_sub ( 1 ) ;
431- let range = (
432- end_mark - margin_left,
433- ( end_mark + 1 ) - margin_left,
434- ) ;
473+ let end_mark = char_widths
474+ . iter ( )
475+ . take ( end - line_start_index)
476+ . sum :: < usize > ( )
477+ . saturating_sub ( 1 ) ;
478+ let range = ( end_mark - margin_left, ( end_mark + 1 ) - margin_left) ;
435479 body. insert (
436480 body_idx + 1 ,
437481 DisplayLine :: Source {
0 commit comments