fix(tui): use updated v_offset after params_changed in ensure_viewport_cache (#24)
The loading branch of ensure_viewport_cache captured v_offset before the params_changed block, which could reassign self.v_offset. This caused the viewport to use a stale offset when loading + width/format changed together. Remove the stale local variable and read self.v_offset directly, consistent with the non-loading branch. Add regression test.
This commit is contained in:
@@ -246,7 +246,6 @@ impl App {
|
|||||||
/// Returns (start_logical, offset_in_line) for rendering.
|
/// Returns (start_logical, offset_in_line) for rendering.
|
||||||
pub(crate) fn ensure_viewport_cache(&mut self, width: usize) -> (usize, usize) {
|
pub(crate) fn ensure_viewport_cache(&mut self, width: usize) -> (usize, usize) {
|
||||||
let viewport_height = self.content_height as usize;
|
let viewport_height = self.content_height as usize;
|
||||||
let v_offset = self.v_offset;
|
|
||||||
|
|
||||||
if !self.is_loaded() || width == 0 || viewport_height == 0 {
|
if !self.is_loaded() || width == 0 || viewport_height == 0 {
|
||||||
return (0, 0);
|
return (0, 0);
|
||||||
@@ -268,7 +267,7 @@ impl App {
|
|||||||
|
|
||||||
// Find start logical line from v_offset
|
// Find start logical line from v_offset
|
||||||
let (start_logical, offset_in_line) = if self.is_loading() {
|
let (start_logical, offset_in_line) = if self.is_loading() {
|
||||||
(v_offset.min(self.total_lines().saturating_sub(1)), self.v_sub_offset)
|
(self.v_offset.min(self.total_lines().saturating_sub(1)), self.v_sub_offset)
|
||||||
} else {
|
} else {
|
||||||
self.find_logical_line_at_visual_row(self.v_offset, width)
|
self.find_logical_line_at_visual_row(self.v_offset, width)
|
||||||
};
|
};
|
||||||
@@ -2538,6 +2537,42 @@ plain text line
|
|||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Regression test for issue #24:
|
||||||
|
/// ensure_viewport_cache must use the updated self.v_offset after params_changed
|
||||||
|
/// recalculates it, not a stale local captured before the change block.
|
||||||
|
#[test]
|
||||||
|
fn test_loading_viewport_cache_uses_updated_v_offset_on_params_changed() {
|
||||||
|
let content: String = (0..200).map(|i| format!("line{i}\n")).collect();
|
||||||
|
let path = make_temp_file(&content);
|
||||||
|
let result = std::panic::catch_unwind(|| {
|
||||||
|
let mut app = App::new();
|
||||||
|
app.load_file(path.to_str().unwrap()).unwrap();
|
||||||
|
assert!(app.is_loading(), "should be in Loading state");
|
||||||
|
|
||||||
|
app.content_height = 10;
|
||||||
|
app.ensure_viewport_cache(80);
|
||||||
|
|
||||||
|
app.v_offset = 90;
|
||||||
|
app.cursor_line = 100;
|
||||||
|
|
||||||
|
let new_width = 40;
|
||||||
|
app.ensure_viewport_cache(new_width);
|
||||||
|
|
||||||
|
let recomputed_offset = app.v_offset;
|
||||||
|
assert_ne!(
|
||||||
|
recomputed_offset, 90,
|
||||||
|
"v_offset should have been recalculated by params_changed block, still 90"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.viewport_cache.logical_start, recomputed_offset.min(app.total_lines().saturating_sub(1)),
|
||||||
|
"logical_start should match the updated v_offset"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
cleanup(&path);
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
fn install_vhi(app: &mut App, heights: &[usize]) {
|
fn install_vhi(app: &mut App, heights: &[usize]) {
|
||||||
let width = app.get_content_width();
|
let width = app.get_content_width();
|
||||||
let json_format = app.json_format;
|
let json_format = app.json_format;
|
||||||
|
|||||||
Reference in New Issue
Block a user