Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit ac31f8a

Browse files
Fix display of annotation for double width characters
1 parent a0e10a8 commit ac31f8a

File tree

2 files changed

+85
-21
lines changed

2 files changed

+85
-21
lines changed

‎src/display_list/from_snippet.rs‎

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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,7 @@ fn format_body(
374409
});
375410
}
376411
} else {
377-
let range = (start - line_start, start - line_start + 1);
412+
let range = (start - line_start_index, start - line_start_index + 1);
378413
body.insert(
379414
body_idx + 1,
380415
DisplayLine::Source {
@@ -398,7 +433,7 @@ fn format_body(
398433
}
399434
true
400435
}
401-
(start, end) if start < line_start && end > line_end => {
436+
(start, end) if start < line_start_index && end > line_end_index => {
402437
if let DisplayLine::Source {
403438
ref mut inline_marks,
404439
..
@@ -413,7 +448,11 @@ fn format_body(
413448
}
414449
true
415450
}
416-
(start, end) if start < line_start && end >= line_start && end <= line_end => {
451+
(start, end)
452+
if start < line_start_index
453+
&& end >= line_start_index
454+
&& end <= line_end_index =>
455+
{
417456
if let DisplayLine::Source {
418457
ref mut inline_marks,
419458
..
@@ -427,11 +466,8 @@ fn format_body(
427466
});
428467
}
429468

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-
);
469+
let end_mark = (end - line_start_index).saturating_sub(1);
470+
let range = (end_mark - margin_left, (end_mark + 1) - margin_left);
435471
body.insert(
436472
body_idx + 1,
437473
DisplayLine::Source {

‎tests/formatter.rs‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,3 +550,31 @@ fn test_i_29() {
550550

551551
assert_eq!(DisplayList::from(snippets).to_string(), expected);
552552
}
553+
554+
#[test]
555+
fn test_point_to_double_width_characters() {
556+
let snippets = Snippet {
557+
slices: vec![snippet::Slice {
558+
source: "こんにちは、世界",
559+
line_start: 1,
560+
origin: Some("<current file>"),
561+
annotations: vec![snippet::SourceAnnotation {
562+
range: (6, 8),
563+
label: "world",
564+
annotation_type: snippet::AnnotationType::Error,
565+
}],
566+
fold: false,
567+
}],
568+
title: None,
569+
footer: vec![],
570+
opt: Default::default(),
571+
};
572+
573+
let expected = r#" --> <current file>:1:7
574+
|
575+
1 | こんにちは、世界
576+
| ^^^^ world
577+
|"#;
578+
579+
assert_eq!(DisplayList::from(snippets).to_string(), expected);
580+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /