@@ -293,11 +293,23 @@ fn format_body(
293
293
let mut body = vec ! [ ] ;
294
294
let mut current_line = slice. line_start ;
295
295
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
+ }
297
304
298
305
for ( line, end_line) in CursorLines :: new ( slice. source ) {
299
306
let line_length = line. chars ( ) . count ( ) ;
300
307
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 < _ > > ( ) ;
301
313
body. push ( DisplayLine :: Source {
302
314
lineno : Some ( current_line) ,
303
315
inline_marks : vec ! [ ] ,
@@ -306,16 +318,28 @@ fn format_body(
306
318
range : line_range,
307
319
} ,
308
320
} ) ;
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
+ } ) ;
310
326
current_line += 1 ;
311
327
current_index += line_length + end_line as usize ;
312
328
}
313
329
314
330
let mut annotation_line_count = 0 ;
315
331
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
+ {
317
341
let margin_left = margin
318
- . map ( |m| m. left ( line_end - line_start ) )
342
+ . map ( |m| m. left ( line_end_index - line_start_index ) )
319
343
. unwrap_or_default ( ) ;
320
344
// It would be nice to use filter_drain here once it's stable.
321
345
annotations = annotations
@@ -328,15 +352,22 @@ fn format_body(
328
352
_ => DisplayAnnotationType :: from ( annotation. annotation_type ) ,
329
353
} ;
330
354
match annotation. range {
331
- ( start, _) if start > line_end => true ,
355
+ ( start, _) if start > line_end_index => true ,
332
356
( 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 =>
335
359
{
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) ;
340
371
body. insert (
341
372
body_idx + 1 ,
342
373
DisplayLine :: Source {
@@ -359,8 +390,12 @@ fn format_body(
359
390
annotation_line_count += 1 ;
360
391
false
361
392
}
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 {
364
399
if let DisplayLine :: Source {
365
400
ref mut inline_marks,
366
401
..
@@ -374,7 +409,11 @@ fn format_body(
374
409
} ) ;
375
410
}
376
411
} 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 ) ;
378
417
body. insert (
379
418
body_idx + 1 ,
380
419
DisplayLine :: Source {
@@ -398,7 +437,7 @@ fn format_body(
398
437
}
399
438
true
400
439
}
401
- ( start, end) if start < line_start && end > line_end => {
440
+ ( start, end) if start < line_start_index && end > line_end_index => {
402
441
if let DisplayLine :: Source {
403
442
ref mut inline_marks,
404
443
..
@@ -413,7 +452,11 @@ fn format_body(
413
452
}
414
453
true
415
454
}
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
+ {
417
460
if let DisplayLine :: Source {
418
461
ref mut inline_marks,
419
462
..
@@ -427,11 +470,12 @@ fn format_body(
427
470
} ) ;
428
471
}
429
472
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) ;
435
479
body. insert (
436
480
body_idx + 1 ,
437
481
DisplayLine :: Source {
0 commit comments