fix: preserve diff backgrounds and align file markers

This commit is contained in:
Valdemar Lorenzen
2026-10-14 13:15:37 +02:00
parent 8a1e98819c
commit 15968a328c
2 changed files with 76 additions and 78 deletions
+73 -77
View File
@@ -3319,9 +3319,6 @@ fn draw_diff_pane(
continue;
};
let segment = segments.and_then(|segments| segments[usize::from(!before)]);
if segments.is_some() && segment.is_none() {
continue;
}
let left = segment.map_or(left, |segment| segment.start);
let text_width = segment.map_or(width, |segment| segment.end - segment.start);
let paint_width = segment.map_or(width, |segment| {
@@ -3339,6 +3336,12 @@ fn draw_diff_pane(
} else {
Color::Reset
};
frame
.buffer_mut()
.set_style(row_area, Style::default().bg(background));
if segments.is_some() && segment.is_none() {
continue;
}
frame.render_widget(
Paragraph::new(visible_text(source_text, left, text_width.min(width), true))
.style(Style::default().fg(Color::Reset).bg(background)),
@@ -4635,27 +4638,25 @@ fn draw_file_list(
let old_path = changed
.and_then(|file| file.old_path.as_deref())
.or(entry.old_path);
let prefix = format!(
"{} {:indent$}",
if selected { ">" } else { " " },
"",
indent = if picker.view == FileView::Tree {
entry.depth * 2
} else {
0
},
);
let mut spans = Vec::with_capacity(if status.is_some() { 7 } else { 3 });
spans.push(Span::raw(prefix));
if changed.is_some() {
let reviewed = entry.catalog_index.is_some_and(|index| {
let mut spans = Vec::with_capacity(8);
let reviewed = changed.is_some()
&& entry.catalog_index.is_some_and(|index| {
changed_files.is_some_and(|(_, reviewed)| reviewed.contains(&index))
});
spans.push(Span::raw(if selected { ">" } else { " " }));
if changed_files.is_some() {
spans.push(Span::styled(
if reviewed { "✓ " } else { " " },
if reviewed { "✓" } else { " " },
Style::default().fg(Color::Green),
));
} else {
spans.push(Span::raw(" "));
}
spans.push(Span::raw(if picker.view == FileView::Tree {
" ".repeat(entry.depth * 2)
} else {
String::new()
}));
if let Some(status) = status {
let color = match status {
FileStatus::Added => Color::Green,
@@ -6825,6 +6826,44 @@ mod tests {
assert_eq!(diff.focus, Focus::Before);
}
#[test]
fn diff_row_tint_covers_blank_lines_and_wrapped_gutters() {
for wrapped in [false, true] {
let mut diff = diff_comparison(vec![syntax_diff_file(
"changed.txt",
"old old old old old old old old old old old old old old old old old old old old\n",
"new\n",
)]);
diff.files_visible = false;
diff.word_wrap = wrapped;
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(60, 20)).unwrap();
let mut panels = WheelPanels {
diff_colors: DiffColors::new(Some(LIGHT_DIFF_THEME)),
..WheelPanels::default()
};
render_diff(&mut terminal, &diff, &mut panels);
for side in 0..2 {
let area = diff_inner(panels.diff.as_ref().unwrap().regions[side + 1].0);
let buffer = terminal.backend().buffer();
let empty = (area.y..area.bottom())
.find(|&y| buffer[(area.x, y)].symbol() == "2")
.unwrap();
for y in area.y..=empty {
for x in area.x..area.x + 3 {
assert_eq!(
buffer[(x, y)].bg,
panels.diff_colors.row[side],
"{wrapped} {side} {x} {y}"
);
}
}
for x in area.x..area.right() {
assert_eq!(buffer[(x, empty)].bg, panels.diff_colors.row[side]);
}
}
}
}
#[test]
fn diff_added_rows_hatch_missing_before_but_tint_real_empty_after_lines() {
let mut diff = diff_comparison(vec![ChangedFile {
@@ -7152,14 +7191,26 @@ mod tests {
.unwrap_or_else(|| panic!("missing {expected}"));
assert_eq!(buffer[(x, y)].fg, color);
assert_eq!(
buffer[(x - 2, y)].symbol(),
buffer[(2, y)].symbol(),
if catalog_index == index { "✓" } else { " " }
);
assert_eq!(buffer[(x - 1, y)].symbol(), " ");
let depth = picker
.entries()
.find(|entry| entry.catalog_index == Some(catalog_index))
.unwrap()
.depth;
assert_eq!(
x,
3 + if view == FileView::Tree {
depth as u16 * 2
} else {
0
}
);
if catalog_index == index {
assert_eq!(buffer[(x - 2, y)].fg, Color::Green);
assert_eq!(buffer[(2, y)].fg, Color::Green);
assert_eq!(
buffer[(x - 2, y)].bg,
buffer[(2, y)].bg,
if focused {
Color::Blue
} else {
@@ -7206,7 +7257,6 @@ mod tests {
})
.unwrap();
let text = screen_text(&terminal);
assert!(text.contains("✓ M "));
assert_eq!(text.matches('✓').count(), 1);
assert!(!text.contains("R r.txt"));
assert_eq!(
@@ -7234,60 +7284,6 @@ mod tests {
assert!(!screen_text(&terminal).contains('✓'));
}
#[test]
fn reviewed_file_prefix_tracks_state_and_clips_in_narrow_panes() {
let mut file = deletion_file();
file.path = "界.txt".into();
file.status = FileStatus::Modified;
let files = [file];
let mut picker = FilePicker::from_paths(PathBuf::new(), [(0, files[0].path.clone())]);
picker.set_view(FileView::List);
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(12, 3)).unwrap();
let mut reviewed = BTreeSet::new();
for marked in [true, false, true] {
if marked {
reviewed.insert(0);
} else {
reviewed.remove(&0);
}
for width in 1..=8 {
terminal
.draw(|frame| {
frame.render_widget(
Paragraph::new("XXXXXXXXXXXX\nXXXXXXXXXXXX\nXXXXXXXXXXXX"),
frame.area(),
);
draw_file_list(
frame,
&picker,
Rect::new(0, 0, width, 3),
"",
&mut WheelPanels::default(),
Some((&files, &reviewed)),
);
})
.unwrap();
let buffer = terminal.backend().buffer();
let prefix = if marked { "> ✓ M " } else { "> M " };
for (x, symbol) in prefix.chars().take(usize::from(width)).enumerate() {
assert_eq!(buffer[(x as u16, 1)].symbol(), symbol.to_string());
}
for x in width..12 {
assert_eq!(buffer[(x, 1)].symbol(), "X");
}
if width >= 3 && marked {
assert_eq!(buffer[(2, 1)].fg, Color::Green);
}
if width >= 5 {
assert_eq!(buffer[(4, 1)].fg, Color::Yellow);
}
if width >= 8 {
assert_eq!(buffer[(6, 1)].symbol(), "界");
}
}
}
}
#[test]
fn normal_file_markers_keep_clean_rows_and_match_diff_colors_in_every_view() {
use crate::repository::WorkingFileChange;