aboutsummaryrefslogtreecommitdiff
path: root/src/app/runtime.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/runtime.rs')
-rw-r--r--src/app/runtime.rs98
1 files changed, 96 insertions, 2 deletions
diff --git a/src/app/runtime.rs b/src/app/runtime.rs
index ad90a267..4ddcde6c 100644
--- a/src/app/runtime.rs
+++ b/src/app/runtime.rs
@@ -165,13 +165,15 @@ impl App {
false
}
- pub(crate) fn handle_scheduled_tasks(&mut self, now: Instant) -> bool {
+ pub(crate) fn handle_scheduled_tasks(&mut self, now: Instant, geometry_dirty: bool) -> bool {
let mut changed = false;
+ let mut resized = false;
self.sync_animation_timer(now);
if now >= self.next_resize_poll {
- changed |= self.handle_resize_poll();
+ resized = self.handle_resize_poll();
+ changed |= resized;
self.next_resize_poll = now + RESIZE_POLL_INTERVAL;
}
@@ -247,6 +249,12 @@ impl App {
changed = true;
}
+ if geometry_dirty || resized {
+ self.pending_agent_resume_deadline = None;
+ } else {
+ self.sync_pending_agent_resume_deadline(now);
+ changed |= self.start_pending_agent_resumes(self.pending_agent_resume_due(now));
+ }
self.sync_animation_timer(now);
changed
}
@@ -496,6 +504,7 @@ impl App {
.flatten(),
self.next_auto_update_check,
self.agent_metadata_deadline,
+ self.pending_agent_resume_deadline,
self.session_save_deadline,
self.selection_autoscroll_deadline,
self.selection_highlight_clear_deadline,
@@ -914,4 +923,89 @@ mod tests {
assert!(app.state.selection_autoscroll.is_none());
assert!(app.selection_autoscroll_deadline.is_none());
}
+
+ #[tokio::test]
+ async fn raw_input_batch_does_not_start_pending_agent_resume_before_render() {
+ let (mut app, pane_id) = test_app_with_pane();
+ app.state.ensure_test_terminals();
+ let terminal_id = app.state.workspaces[0]
+ .terminal_id(pane_id)
+ .cloned()
+ .expect("test pane should have a terminal");
+ app.state
+ .terminals
+ .get_mut(&terminal_id)
+ .expect("test terminal should exist")
+ .pending_agent_resume_plan = Some(crate::agent_resume::AgentResumePlan {
+ agent: "codex".into(),
+ argv: vec!["/bin/sh".into(), "-c".into(), "sleep 5".into()],
+ dedupe_key: "herdr:codex\0codex\0Id\0codex-session".into(),
+ });
+
+ assert!(
+ app.handle_raw_input_batch(crate::raw_input::RawInputEvent::HostDefaultColor {
+ kind: crate::terminal_theme::DefaultColorKind::Foreground,
+ color: crate::terminal_theme::RgbColor {
+ r: 220,
+ g: 220,
+ b: 220,
+ },
+ })
+ .await
+ );
+ assert!(
+ app.terminal_runtimes.get(&terminal_id).is_none(),
+ "raw input can mutate active geometry; pending resumes must wait for render to refresh pane_infos"
+ );
+ assert!(app
+ .state
+ .terminals
+ .get(&terminal_id)
+ .expect("test terminal should still exist")
+ .pending_agent_resume_plan
+ .is_some());
+ }
+
+ #[tokio::test]
+ async fn scheduled_tasks_do_not_start_pending_agent_resume_when_geometry_dirty() {
+ let (mut app, pane_id) = test_app_with_pane();
+ app.state.ensure_test_terminals();
+ app.state.host_terminal_theme = crate::terminal_theme::TerminalTheme {
+ foreground: Some(crate::terminal_theme::RgbColor {
+ r: 220,
+ g: 220,
+ b: 220,
+ }),
+ background: Some(crate::terminal_theme::RgbColor {
+ r: 20,
+ g: 20,
+ b: 20,
+ }),
+ };
+ let terminal_id = app.state.workspaces[0]
+ .terminal_id(pane_id)
+ .cloned()
+ .expect("test pane should have a terminal");
+ app.state
+ .terminals
+ .get_mut(&terminal_id)
+ .expect("test terminal should exist")
+ .pending_agent_resume_plan = Some(crate::agent_resume::AgentResumePlan {
+ agent: "codex".into(),
+ argv: vec!["/bin/sh".into(), "-c".into(), "sleep 5".into()],
+ dedupe_key: "herdr:codex\0codex\0Id\0codex-session".into(),
+ });
+ app.pending_agent_resume_deadline = Some(Instant::now() - Duration::from_millis(1));
+
+ assert!(!app.handle_scheduled_tasks(Instant::now(), true));
+ assert!(app.terminal_runtimes.get(&terminal_id).is_none());
+ assert!(app
+ .state
+ .terminals
+ .get(&terminal_id)
+ .expect("test terminal should still exist")
+ .pending_agent_resume_plan
+ .is_some());
+ assert!(app.pending_agent_resume_deadline.is_none());
+ }
}