Skip to content

Commit b9d27c6

Browse files
committed
port over a minimal LineWidthBuilder and IndentWidth
1 parent 434e8f9 commit b9d27c6

File tree

3 files changed

+77
-13
lines changed

3 files changed

+77
-13
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ruff_db/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ serde_json = { workspace = true, optional = true }
4242
thiserror = { workspace = true }
4343
tracing = { workspace = true }
4444
tracing-subscriber = { workspace = true, optional = true }
45+
unicode-width = { workspace = true }
4546
zip = { workspace = true }
4647

4748
[target.'cfg(target_arch="wasm32")'.dependencies]

crates/ruff_db/src/diagnostic/render.rs

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::borrow::Cow;
22
use std::collections::BTreeMap;
3+
use std::num::NonZeroU8;
34
use std::path::Path;
45

56
use ruff_annotate_snippets::{
@@ -828,6 +829,73 @@ fn relativize_path<'p>(cwd: &SystemPath, path: &'p str) -> &'p str {
828829
path
829830
}
830831

832+
#[derive(Clone, Copy)]
833+
struct IndentWidth(NonZeroU8);
834+
835+
impl IndentWidth {
836+
fn as_usize(self) -> usize {
837+
self.0.get() as usize
838+
}
839+
}
840+
841+
impl Default for IndentWidth {
842+
fn default() -> Self {
843+
Self(NonZeroU8::new(4).unwrap())
844+
}
845+
}
846+
847+
/// A measure of the width of a line of text.
848+
///
849+
/// This is used to determine if a line is too long.
850+
/// It should be compared to a [`LineLength`].
851+
#[derive(Clone, Copy)]
852+
struct LineWidthBuilder {
853+
/// The width of the line.
854+
width: usize,
855+
/// The column of the line.
856+
/// This is used to calculate the width of tabs.
857+
column: usize,
858+
/// The tab size to use when calculating the width of tabs.
859+
tab_size: IndentWidth,
860+
}
861+
862+
impl LineWidthBuilder {
863+
fn get(&self) -> usize {
864+
self.width
865+
}
866+
867+
/// Creates a new `LineWidth` with the given tab size.
868+
fn new(tab_size: IndentWidth) -> Self {
869+
LineWidthBuilder {
870+
width: 0,
871+
column: 0,
872+
tab_size,
873+
}
874+
}
875+
876+
/// Adds the given character to the line width.
877+
#[must_use]
878+
fn add_char(mut self, c: char) -> Self {
879+
let tab_size: usize = self.tab_size.as_usize();
880+
match c {
881+
'\t' => {
882+
let tab_offset = tab_size - (self.column % tab_size);
883+
self.width += tab_offset;
884+
self.column += tab_offset;
885+
}
886+
'\n' | '\r' => {
887+
self.width = 0;
888+
self.column = 0;
889+
}
890+
_ => {
891+
self.width += unicode_width::UnicodeWidthChar::width(c).unwrap_or(0);
892+
self.column += 1;
893+
}
894+
}
895+
self
896+
}
897+
}
898+
831899
/// Given some source code and annotation ranges, this routine replaces tabs
832900
/// with ASCII whitespace, and unprintable characters with printable
833901
/// representations of them.
@@ -840,8 +908,7 @@ fn replace_whitespace_and_unprintable<'r>(
840908
) -> EscapedSourceCode<'r> {
841909
let mut result = String::new();
842910
let mut last_end = 0;
843-
let mut column = 0;
844-
const TAB_SIZE: usize = 4;
911+
let mut line_width = LineWidthBuilder::new(IndentWidth::default());
845912

846913
// Updates the annotation ranges given by the caller whenever a single byte (at `index` in
847914
// `source`) is replaced with `len` bytes.
@@ -872,24 +939,19 @@ fn replace_whitespace_and_unprintable<'r>(
872939
};
873940

874941
for (index, c) in source.char_indices() {
942+
let old_width = line_width.get();
943+
line_width = line_width.add_char(c);
944+
875945
if matches!(c, '\t') {
876-
let tab_offset = TAB_SIZE - (column % TAB_SIZE);
877-
column += tab_offset;
878-
let tab_width = u32::try_from(tab_offset).expect("small width because of tab size");
946+
let tab_width = u32::try_from(line_width.get() - old_width)
947+
.expect("small width because of tab size");
879948
result.push_str(&source[last_end..index]);
880949
for _ in 0..tab_width {
881950
result.push(' ');
882951
}
883952
last_end = index + 1;
884953
update_ranges(index, tab_width);
885-
} else {
886-
match c {
887-
'\n' | '\r' => column = 0,
888-
_ => column += 1,
889-
}
890-
}
891-
892-
if let Some(printable) = unprintable_replacement(c) {
954+
} else if let Some(printable) = unprintable_replacement(c) {
893955
result.push_str(&source[last_end..index]);
894956
result.push(printable);
895957
last_end = index + 1;

0 commit comments

Comments
 (0)