From 756ad04a88d4602a4cc5cbdf7039fc837d486a1a Mon Sep 17 00:00:00 2001 From: Jeremy Rose Date: Mon, 25 Aug 2025 16:34:24 -0700 Subject: [PATCH 1/2] fix cursor after suspend --- codex-rs/tui/src/tui.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/codex-rs/tui/src/tui.rs b/codex-rs/tui/src/tui.rs index d30e9a6e17..6b3ccd6a51 100644 --- a/codex-rs/tui/src/tui.rs +++ b/codex-rs/tui/src/tui.rs @@ -7,6 +7,8 @@ use std::sync::Arc; use std::sync::atomic::AtomicBool; #[cfg(unix)] use std::sync::atomic::AtomicU8; +#[cfg(unix)] +use std::sync::atomic::AtomicU16; use std::sync::atomic::Ordering; use std::time::Duration; use std::time::Instant; @@ -33,6 +35,7 @@ use ratatui::crossterm::execute; use ratatui::crossterm::terminal::disable_raw_mode; use ratatui::crossterm::terminal::enable_raw_mode; use ratatui::layout::Offset; +use ratatui::layout::Position; use ratatui::text::Line; use crate::clipboard_paste::paste_image_to_temp_png; @@ -125,6 +128,8 @@ pub struct Tui { alt_saved_viewport: Option, #[cfg(unix)] resume_pending: Arc, // Stores a ResumeAction + #[cfg(unix)] + suspend_cursor_y: Arc, // Bottom line of inline viewport // True when overlay alt-screen UI is active alt_screen_active: Arc, } @@ -231,6 +236,8 @@ impl Tui { alt_saved_viewport: None, #[cfg(unix)] resume_pending: Arc::new(AtomicU8::new(0)), + #[cfg(unix)] + suspend_cursor_y: Arc::new(AtomicU16::new(0)), alt_screen_active: Arc::new(AtomicBool::new(false)), } } @@ -249,6 +256,8 @@ impl Tui { let resume_pending = self.resume_pending.clone(); #[cfg(unix)] let alt_screen_active = self.alt_screen_active.clone(); + #[cfg(unix)] + let suspend_cursor_y = self.suspend_cursor_y.clone(); let event_stream = async_stream::stream! { loop { select! { @@ -295,6 +304,11 @@ impl Tui { } else { resume_pending.store(ResumeAction::RealignInline as u8, Ordering::Relaxed); } + #[cfg(unix)] + { + let y = suspend_cursor_y.load(Ordering::Relaxed); + let _ = execute!(stdout(), MoveTo(0, y)); + } let _ = execute!(stdout(), crossterm::cursor::Show); let _ = Tui::suspend(); yield TuiEvent::Draw; @@ -351,7 +365,7 @@ impl Tui { ))) } ResumeAction::RestoreAlt => { - if let Ok((_x, y)) = crossterm::cursor::position() + if let Ok(Position { y, .. }) = self.terminal.get_cursor_position() && let Some(saved) = self.alt_saved_viewport.as_mut() { saved.y = y; @@ -481,6 +495,19 @@ impl Tui { ); self.pending_history_lines.clear(); } + // Update the y position for suspending so Ctrl-Z can place the cursor correctly. + #[cfg(unix)] + { + let inline_area_bottom = if self.alt_screen_active.load(Ordering::Relaxed) { + self.alt_saved_viewport + .map(|r| r.bottom().saturating_sub(1)) + .unwrap_or_else(|| area.bottom().saturating_sub(1)) + } else { + area.bottom().saturating_sub(1) + }; + self.suspend_cursor_y + .store(inline_area_bottom, Ordering::Relaxed); + } terminal.draw(|frame| { draw_fn(frame); })?; From eb547d462c265e574f0d4c054161d13d9b7adffb Mon Sep 17 00:00:00 2001 From: Jeremy Rose Date: Mon, 25 Aug 2025 17:09:26 -0700 Subject: [PATCH 2/2] win --- codex-rs/tui/src/tui.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/codex-rs/tui/src/tui.rs b/codex-rs/tui/src/tui.rs index 6b3ccd6a51..8660528cc7 100644 --- a/codex-rs/tui/src/tui.rs +++ b/codex-rs/tui/src/tui.rs @@ -35,7 +35,6 @@ use ratatui::crossterm::execute; use ratatui::crossterm::terminal::disable_raw_mode; use ratatui::crossterm::terminal::enable_raw_mode; use ratatui::layout::Offset; -use ratatui::layout::Position; use ratatui::text::Line; use crate::clipboard_paste::paste_image_to_temp_png; @@ -365,7 +364,7 @@ impl Tui { ))) } ResumeAction::RestoreAlt => { - if let Ok(Position { y, .. }) = self.terminal.get_cursor_position() + if let Ok(ratatui::layout::Position { y, .. }) = self.terminal.get_cursor_position() && let Some(saved) = self.alt_saved_viewport.as_mut() { saved.y = y;