fix: avoid indentation-only wrapped rows

The shared wrapper treated leading whitespace as a usable word boundary,
pushing a long first token onto a continuation and leaving a numbered blank row.
Only record boundaries after non-whitespace content on the current visual row.
Preserve source whitespace, tab stops, caret rows and paired diff alignment.

Verified: 945 tests, formatting, and live ordinary/split-diff fixture smoke,
including wrap off/on and aligned closing brackets.
This commit is contained in:
Valdemar Lorenzen
2026-10-15 13:54:36 +02:00
parent 16490942d6
commit 75dc31b66f
2 changed files with 30 additions and 2 deletions
+29 -1
View File
@@ -36,6 +36,7 @@ impl WrapCache {
let mut start = 0;
let mut column = 0;
let mut word_boundary = 0;
let mut content_end = 0;
for grapheme in text.graphemes(true) {
let cells = if grapheme == "\t" {
TAB_WIDTH - column % TAB_WIDTH
@@ -64,7 +65,10 @@ impl WrapCache {
}
}
column += cells;
if grapheme.chars().all(char::is_whitespace) {
if !grapheme.chars().all(char::is_whitespace) {
content_end = column;
} else if content_end > start {
// A word break must not leave only whitespace on this visual row.
word_boundary = column;
}
}
@@ -116,6 +120,30 @@ mod tests {
assert_eq!(caret_segment(&segments, 8), 2);
}
#[test]
fn long_words_do_not_wrap_indentation_onto_an_empty_visual_row() {
for source in [
" abcdefghijk",
"\tabcdefghijk",
"head abcdefghijk",
] {
let expanded = source.replace('\t', " ");
let segments = layout(source, 8);
assert_eq!(segments.first().unwrap().start, 0);
assert_eq!(segments.last().unwrap().end, expanded.len());
assert!(segments.windows(2).all(|pair| pair[0].end == pair[1].start));
for segment in segments
.iter()
.filter(|segment| segment.start < segment.end)
{
assert!(
!expanded[segment.start..segment.end].trim().is_empty(),
"whitespace-only visual row {segment:?} in {source:?}"
);
}
}
}
#[test]
fn tabs_use_source_stops_and_unicode_graphemes_remain_intact() {
assert_eq!(