aboutsummaryrefslogtreecommitdiff
path: root/src/app/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/mod.rs')
-rw-r--r--src/app/mod.rs49
1 files changed, 49 insertions, 0 deletions
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 1c818a9c..13b8ecc0 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -29,6 +29,7 @@ const MIN_RENDER_INTERVAL: Duration = Duration::from_millis(16);
pub(crate) const ANIMATION_INTERVAL: Duration = Duration::from_millis(16);
pub(crate) const HEADLESS_ANIMATION_INTERVAL: Duration = Duration::from_millis(128);
pub(crate) const HEADLESS_ANIMATION_TICK_STEP: u32 = 8;
+pub(crate) const SELECTION_AUTOSCROLL_INTERVAL: Duration = Duration::from_millis(30);
const RESIZE_POLL_INTERVAL: Duration = Duration::from_millis(100);
const GIT_REMOTE_STATUS_REFRESH_INTERVAL: Duration = Duration::from_millis(1500);
const AUTO_UPDATE_CHECK_INTERVAL: Duration = Duration::from_secs(30 * 60);
@@ -77,6 +78,7 @@ pub struct App {
pub(crate) next_resize_poll: Instant,
pub(crate) next_animation_tick: Option<Instant>,
pub(crate) next_auto_update_check: Option<Instant>,
+ pub(crate) selection_autoscroll_deadline: Option<Instant>,
pub(crate) session_save_deadline: Option<Instant>,
pub(crate) last_render_at: Option<Instant>,
pub(crate) suppressed_repeat_keys:
@@ -363,6 +365,7 @@ impl App {
workspace_press: None,
tab_press: None,
selection: None,
+ selection_autoscroll: None,
context_menu: None,
update_available,
update_install_command,
@@ -451,6 +454,7 @@ impl App {
next_auto_update_check: auto_updates_enabled(no_session)
.then_some(Instant::now() + AUTO_UPDATE_CHECK_INTERVAL),
session_save_deadline: None,
+ selection_autoscroll_deadline: None,
last_render_at: None,
suppressed_repeat_keys: HashSet::new(),
api_rx,
@@ -2043,6 +2047,51 @@ mod tests {
assert!(app.session_save_deadline.is_none());
}
+ #[test]
+ fn next_loop_deadline_includes_selection_autoscroll_deadline() {
+ let mut app = test_app();
+ let now = Instant::now();
+ app.selection_autoscroll_deadline = Some(now + Duration::from_millis(5));
+ app.next_animation_tick = Some(now + Duration::from_millis(100));
+ app.session_save_deadline = Some(now + Duration::from_millis(200));
+ assert_eq!(
+ app.next_loop_deadline(now, false),
+ app.selection_autoscroll_deadline
+ );
+ }
+
+ #[test]
+ fn tick_selection_autoscroll_self_heals_when_state_cleared() {
+ let mut app = test_app();
+ let now = Instant::now();
+ app.state.selection_autoscroll = None;
+ app.selection_autoscroll_deadline = Some(now);
+ app.tick_selection_autoscroll(now);
+ assert!(app.selection_autoscroll_deadline.is_none());
+ }
+
+ #[test]
+ fn tick_selection_autoscroll_stops_on_rect_change() {
+ let mut app = test_app();
+ let now = Instant::now();
+ let ws = Workspace::test_new("test");
+ let pane_id = ws.tabs[0].root_pane;
+ app.state.workspaces.push(ws);
+ app.state.active = Some(0);
+ app.state.selection = Some(crate::selection::Selection::anchor(pane_id, 0, 0, None));
+ // Set autoscroll with a stale inner_rect that doesn't match pane_infos
+ app.state.selection_autoscroll = Some(state::SelectionAutoscroll {
+ direction: state::SelectionAutoscrollDirection::Down,
+ last_mouse_screen_col: 0,
+ last_mouse_screen_row: 999,
+ inner_rect: ratatui::layout::Rect::new(0, 0, 1, 1), // wrong rect
+ });
+ app.selection_autoscroll_deadline = Some(now);
+ app.tick_selection_autoscroll(now);
+ assert!(app.state.selection_autoscroll.is_none());
+ assert!(app.selection_autoscroll_deadline.is_none());
+ }
+
#[tokio::test]
async fn full_internal_event_queue_eventually_applies_working_to_idle_transition() {
let mut app = test_app();