fix cursor after suspend (#2690)

This was supposed to be fixed by #2569, but I think the actual fix got
lost in the refactoring.

Intended behavior: pressing ^Z moves the cursor below the viewport
before suspending.
This commit is contained in:
Jeremy Rose
2025-08-27 14:17:10 -07:00
committed by GitHub
parent 488a40211a
commit 3e309805ae

View File

@@ -7,6 +7,8 @@ use std::sync::Arc;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
#[cfg(unix)] #[cfg(unix)]
use std::sync::atomic::AtomicU8; use std::sync::atomic::AtomicU8;
#[cfg(unix)]
use std::sync::atomic::AtomicU16;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::time::Duration; use std::time::Duration;
use std::time::Instant; use std::time::Instant;
@@ -168,6 +170,8 @@ pub struct Tui {
alt_saved_viewport: Option<ratatui::layout::Rect>, alt_saved_viewport: Option<ratatui::layout::Rect>,
#[cfg(unix)] #[cfg(unix)]
resume_pending: Arc<AtomicU8>, // Stores a ResumeAction resume_pending: Arc<AtomicU8>, // Stores a ResumeAction
#[cfg(unix)]
suspend_cursor_y: Arc<AtomicU16>, // Bottom line of inline viewport
// True when overlay alt-screen UI is active // True when overlay alt-screen UI is active
alt_screen_active: Arc<AtomicBool>, alt_screen_active: Arc<AtomicBool>,
} }
@@ -274,6 +278,8 @@ impl Tui {
alt_saved_viewport: None, alt_saved_viewport: None,
#[cfg(unix)] #[cfg(unix)]
resume_pending: Arc::new(AtomicU8::new(0)), 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)), alt_screen_active: Arc::new(AtomicBool::new(false)),
} }
} }
@@ -292,6 +298,8 @@ impl Tui {
let resume_pending = self.resume_pending.clone(); let resume_pending = self.resume_pending.clone();
#[cfg(unix)] #[cfg(unix)]
let alt_screen_active = self.alt_screen_active.clone(); 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! { let event_stream = async_stream::stream! {
loop { loop {
select! { select! {
@@ -340,6 +348,11 @@ impl Tui {
} else { } else {
resume_pending.store(ResumeAction::RealignInline as u8, Ordering::Relaxed); 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 _ = execute!(stdout(), crossterm::cursor::Show);
let _ = Tui::suspend(); let _ = Tui::suspend();
yield TuiEvent::Draw; yield TuiEvent::Draw;
@@ -396,7 +409,7 @@ impl Tui {
))) )))
} }
ResumeAction::RestoreAlt => { ResumeAction::RestoreAlt => {
if let Ok((_x, y)) = crossterm::cursor::position() if let Ok(ratatui::layout::Position { y, .. }) = self.terminal.get_cursor_position()
&& let Some(saved) = self.alt_saved_viewport.as_mut() && let Some(saved) = self.alt_saved_viewport.as_mut()
{ {
saved.y = y; saved.y = y;
@@ -532,6 +545,19 @@ impl Tui {
); );
self.pending_history_lines.clear(); 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| { terminal.draw(|frame| {
draw_fn(frame); draw_fn(frame);
})?; })?;