mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-13 08:05:16 +00:00
[ty] Fix rendering of long lines that are indented with tabs
It turns out that `annotate-snippets` doesn't do a great job of consistently handling tabs. The intent of the implementation is clearly to expand tabs into 4 ASCII whitespace characters. But there are a few places where the column computation wasn't taking this expansion into account. In particular, the `unicode-width` crate returns `None` for a `\t` input, and `annotate-snippets` would in turn treat this as either zero columns or one column. Both are wrong. In patching this, it caused one of the existing `annotate-snippets` tests to fail. I spent a fair bit of time on it trying to fix it before coming to the conclusion that the test itself was wrong. In particular, the annotation ranges are 4 bytes off. However, when the range was wrong, the buggy code was rendering the example as intended since `\t` characters were treated as taking up zero columns of space. Now that they are correctly computed as taking up 4 columns of space, the offsets of the test needed to be adjusted. Fixes #670
This commit is contained in:
parent
6e25cfba2b
commit
76619b96e5
4 changed files with 19 additions and 10 deletions
|
@ -352,7 +352,7 @@ impl DisplaySet<'_> {
|
|||
// FIXME: `unicode_width` sometimes disagrees with terminals on how wide a `char`
|
||||
// is. For now, just accept that sometimes the code line will be longer than
|
||||
// desired.
|
||||
let next = unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1);
|
||||
let next = char_width(ch).unwrap_or(1);
|
||||
if taken + next > right - left {
|
||||
was_cut_right = true;
|
||||
break;
|
||||
|
@ -377,7 +377,7 @@ impl DisplaySet<'_> {
|
|||
let left: usize = text
|
||||
.chars()
|
||||
.take(left)
|
||||
.map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1))
|
||||
.map(|ch| char_width(ch).unwrap_or(1))
|
||||
.sum();
|
||||
|
||||
let mut annotations = annotations.clone();
|
||||
|
@ -1393,6 +1393,7 @@ fn format_body<'m>(
|
|||
let line_length: usize = line.len();
|
||||
let line_range = (current_index, current_index + line_length);
|
||||
let end_line_size = end_line.len();
|
||||
|
||||
body.push(DisplayLine::Source {
|
||||
lineno: Some(current_line),
|
||||
inline_marks: vec![],
|
||||
|
@ -1452,12 +1453,12 @@ fn format_body<'m>(
|
|||
let annotation_start_col = line
|
||||
[0..(start - line_start_index).min(line_length)]
|
||||
.chars()
|
||||
.map(|c| unicode_width::UnicodeWidthChar::width(c).unwrap_or(0))
|
||||
.map(|c| char_width(c).unwrap_or(0))
|
||||
.sum::<usize>();
|
||||
let mut annotation_end_col = line
|
||||
[0..(end - line_start_index).min(line_length)]
|
||||
.chars()
|
||||
.map(|c| unicode_width::UnicodeWidthChar::width(c).unwrap_or(0))
|
||||
.map(|c| char_width(c).unwrap_or(0))
|
||||
.sum::<usize>();
|
||||
if annotation_start_col == annotation_end_col {
|
||||
// At least highlight something
|
||||
|
@ -1499,7 +1500,7 @@ fn format_body<'m>(
|
|||
let annotation_start_col = line
|
||||
[0..(start - line_start_index).min(line_length)]
|
||||
.chars()
|
||||
.map(|c| unicode_width::UnicodeWidthChar::width(c).unwrap_or(0))
|
||||
.map(|c| char_width(c).unwrap_or(0))
|
||||
.sum::<usize>();
|
||||
let annotation_end_col = annotation_start_col + 1;
|
||||
|
||||
|
@ -1558,7 +1559,7 @@ fn format_body<'m>(
|
|||
{
|
||||
let end_mark = line[0..(end - line_start_index).min(line_length)]
|
||||
.chars()
|
||||
.map(|c| unicode_width::UnicodeWidthChar::width(c).unwrap_or(0))
|
||||
.map(|c| char_width(c).unwrap_or(0))
|
||||
.sum::<usize>()
|
||||
.saturating_sub(1);
|
||||
// If the annotation ends on a line-end character, we
|
||||
|
@ -1754,3 +1755,11 @@ fn format_inline_marks(
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn char_width(c: char) -> Option<usize> {
|
||||
if c == '\t' {
|
||||
Some(4)
|
||||
} else {
|
||||
unicode_width::UnicodeWidthChar::width(c)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue