Skip to content

Commit 409d710

Browse files
committed
fix: prevent adjust_scroll interference with mouse scrolling
Added skip_scroll_adjustment flag to prevent adjust_scroll() from interfering with mouse scroll behavior. Previously, adjust_scroll() would enforce 3-line padding which caused viewport to "snap back" after mouse scrolling near edges. Now mouse scroll: - Sets skip_scroll_adjustment flag after moving viewport/selection - adjust_scroll() checks flag and returns early if set - Flag automatically clears on next adjust_scroll() call - Keyboard navigation still gets padding behavior as before This gives smooth vim-like scrolling (Ctrl+E/Ctrl+Y) without the "sticky" feeling near viewport edges. Changes: - Added skip_scroll_adjustment: bool to App struct - Modified adjust_scroll() to check and clear flag - Modified mouse_scroll_down/up() to set flag after scrolling - Added 2 tests to verify flag behavior
1 parent 3aad03b commit 409d710

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

src/app.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ pub struct App {
6161

6262
/// Help overlay visible
6363
pub show_help: bool,
64+
65+
/// Skip scroll adjustment on next render (set by mouse scroll)
66+
skip_scroll_adjustment: bool,
6467
}
6568

6669
impl App {
@@ -81,6 +84,7 @@ impl App {
8184
follow_mode: false,
8285
last_filtered_line: 0,
8386
show_help: false,
87+
skip_scroll_adjustment: false,
8488
}
8589
}
8690

@@ -105,6 +109,12 @@ impl App {
105109

106110
/// Ensure the selected line is visible in the viewport
107111
pub fn adjust_scroll(&mut self, viewport_height: usize) {
112+
// Skip adjustment if mouse scroll just happened (prevents interference)
113+
if self.skip_scroll_adjustment {
114+
self.skip_scroll_adjustment = false;
115+
return;
116+
}
117+
108118
// Add some padding at the edges for better UX
109119
let padding = 3.min(viewport_height / 4);
110120

@@ -145,6 +155,9 @@ impl App {
145155
let max_selection = self.line_indices.len().saturating_sub(1);
146156
self.selected_line = (self.selected_line + actual_scroll).min(max_selection);
147157
}
158+
159+
// Skip scroll adjustment on next render to prevent padding interference
160+
self.skip_scroll_adjustment = true;
148161
}
149162

150163
/// Mouse scroll up - moves viewport and selection together
@@ -157,6 +170,9 @@ impl App {
157170
if actual_scroll > 0 {
158171
self.selected_line = self.selected_line.saturating_sub(actual_scroll);
159172
}
173+
174+
// Skip scroll adjustment on next render to prevent padding interference
175+
self.skip_scroll_adjustment = true;
160176
}
161177

162178
/// Apply filter results (for full filtering)
@@ -1049,4 +1065,49 @@ mod tests {
10491065
// Selection should follow the scroll
10501066
assert_eq!(app.selected_line, 7);
10511067
}
1068+
1069+
#[test]
1070+
fn test_mouse_scroll_skips_adjust_scroll() {
1071+
let mut app = App::new(100);
1072+
let visible_height = 20;
1073+
1074+
// Position selection at top with some scroll
1075+
app.selected_line = 5;
1076+
app.scroll_position = 5;
1077+
1078+
// Mouse scroll down - this would normally trigger adjust_scroll
1079+
// because selection is at top of viewport (within padding zone)
1080+
app.mouse_scroll_down(3, visible_height);
1081+
1082+
// Check flag was set
1083+
assert!(app.skip_scroll_adjustment);
1084+
1085+
// After mouse scroll: viewport=8, selection=8
1086+
assert_eq!(app.scroll_position, 8);
1087+
assert_eq!(app.selected_line, 8);
1088+
1089+
// Call adjust_scroll - it should skip and clear flag
1090+
app.adjust_scroll(visible_height);
1091+
assert!(!app.skip_scroll_adjustment);
1092+
1093+
// Scroll position should NOT have changed (no padding adjustment)
1094+
assert_eq!(app.scroll_position, 8);
1095+
assert_eq!(app.selected_line, 8);
1096+
}
1097+
1098+
#[test]
1099+
fn test_adjust_scroll_works_normally_without_mouse() {
1100+
let mut app = App::new(100);
1101+
let visible_height = 20;
1102+
1103+
// Position selection at top with some scroll
1104+
app.selected_line = 5;
1105+
app.scroll_position = 5;
1106+
1107+
// Call adjust_scroll without mouse scroll
1108+
app.adjust_scroll(visible_height);
1109+
1110+
// Should apply padding adjustment (selection is at top, should add padding)
1111+
assert_eq!(app.scroll_position, 2); // 5 - 3 (padding)
1112+
}
10521113
}

0 commit comments

Comments
 (0)