From 14fe8294d7fe8796c2e3e825b8665873a51b6434 Mon Sep 17 00:00:00 2001 From: Adam Bosnjakovic Date: Sat, 15 Aug 2026 17:32:00 +1000 Subject: [PATCH] fix: clear terminal on resize so shrink+grow can't leave stale rows A resize that lands back on the previous size within one tick (herdr flips 69->34->69 rows in ~400ms) is invisible to ratatui's autoresize, but the emulator has already scrolled the alternate screen. Diff-only redraws then accumulate stale rows. Handle Event::Resize explicitly: mark needs_clear, and have the main loop clear before the next draw. Co-Authored-By: Claude Fable 5 --- .strap/.gitignore | 2 ++ .strap/lessons/archive/msr37myo.md | 11 +++++++++ .strap/lessons/msrbxfq9.md | 12 +++++++++ .strap/lessons/msthsaej.md | 11 +++++++++ .strap/lessons/msthsaep.md | 11 +++++++++ .strap/lessons/msthsaes.md | 11 +++++++++ .strap/lessons/msthtgch.md | 11 +++++++++ .strap/tools.toml | 1 + src/app.rs | 39 +++++++++++++++++++++++++++--- src/main.rs | 3 +++ 10 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 .strap/.gitignore create mode 100644 .strap/lessons/archive/msr37myo.md create mode 100644 .strap/lessons/msrbxfq9.md create mode 100644 .strap/lessons/msthsaej.md create mode 100644 .strap/lessons/msthsaep.md create mode 100644 .strap/lessons/msthsaes.md create mode 100644 .strap/lessons/msthtgch.md create mode 100644 .strap/tools.toml diff --git a/.strap/.gitignore b/.strap/.gitignore new file mode 100644 index 0000000..78c818a --- /dev/null +++ b/.strap/.gitignore @@ -0,0 +1,2 @@ +index.db +runs/ diff --git a/.strap/lessons/archive/msr37myo.md b/.strap/lessons/archive/msr37myo.md new file mode 100644 index 0000000..6f469b1 --- /dev/null +++ b/.strap/lessons/archive/msr37myo.md @@ -0,0 +1,11 @@ ++++ +id = "msr37myo" +tags = ["rust", "debugging", "macos"] +confidence = 0.6 +helped = 0 +harmed = 0 +created = "2026-08-13T05:38:17.472618Z" +last_confirmed = "2026-08-13T05:38:17.472618Z" ++++ + +rust debugging (codelldb/lldb) hangs on launch in this environment until the hosting terminal app (Ghostty) has the macOS Privacy & Security -> Developer Tools grant; even bare 'lldb --batch -o run' hangs. DevToolsSecurity/developer-mode alone is insufficient. python/js/lua debugging unaffected. diff --git a/.strap/lessons/msrbxfq9.md b/.strap/lessons/msrbxfq9.md new file mode 100644 index 0000000..24ffd8f --- /dev/null +++ b/.strap/lessons/msrbxfq9.md @@ -0,0 +1,12 @@ ++++ +id = "msrbxfq9" +tags = ["rust", "debugging", "macos"] +confidence = 0.6 +helped = 0 +harmed = 0 +created = "2026-08-13T09:42:18.081483Z" +last_confirmed = "2026-08-13T09:42:18.081483Z" +supersedes = "msr37myo" ++++ + +rust debugging works here now: Ghostty granted macOS Developer Tools 2026-08-13, codelldb launches clean. If it regresses to launch-hangs after a Ghostty update or TCC reset, re-grant in System Settings -> Privacy & Security -> Developer Tools and restart Ghostty. diff --git a/.strap/lessons/msthsaej.md b/.strap/lessons/msthsaej.md new file mode 100644 index 0000000..ef49577 --- /dev/null +++ b/.strap/lessons/msthsaej.md @@ -0,0 +1,11 @@ ++++ +id = "msthsaej" +tags = ["gitbutler", "workflow"] +confidence = 0.6 +helped = 0 +harmed = 0 +created = "2026-08-14T22:01:47.947046Z" +last_confirmed = "2026-08-14T22:01:47.947046Z" ++++ + +but commit with no positional IDs commits ALL dirty files — if IDs come from command substitution, verify non-empty first or a failed $() silently sweeps unrelated files into the commit diff --git a/.strap/lessons/msthsaep.md b/.strap/lessons/msthsaep.md new file mode 100644 index 0000000..bc3c662 --- /dev/null +++ b/.strap/lessons/msthsaep.md @@ -0,0 +1,11 @@ ++++ +id = "msthsaep" +tags = ["macos", "gpu", "oversee"] +confidence = 0.6 +helped = 0 +harmed = 0 +created = "2026-08-14T22:01:47.953115Z" +last_confirmed = "2026-08-14T22:01:47.953115Z" ++++ + +macOS publishes no per-GPU-core or per-process GPU utilization (powermetrics gpu_power is system-wide only) — never reintroduce fabricated per-core GPU numbers in oversee diff --git a/.strap/lessons/msthsaes.md b/.strap/lessons/msthsaes.md new file mode 100644 index 0000000..7961da2 --- /dev/null +++ b/.strap/lessons/msthsaes.md @@ -0,0 +1,11 @@ ++++ +id = "msthsaes" +tags = ["github", "docs"] +confidence = 0.6 +helped = 0 +harmed = 0 +created = "2026-08-14T22:01:47.956936Z" +last_confirmed = "2026-08-14T22:01:47.956936Z" ++++ + +freshly pushed README images can look stale on github.com for minutes — raw.githubusercontent.com CDN caches ~5min and browsers cache longer; verify with curl -sI content-length vs local file size before debugging the repo diff --git a/.strap/lessons/msthtgch.md b/.strap/lessons/msthtgch.md new file mode 100644 index 0000000..a3e8635 --- /dev/null +++ b/.strap/lessons/msthtgch.md @@ -0,0 +1,11 @@ ++++ +id = "msthtgch" +tags = ["oversee", "ci", "workflow"] +confidence = 0.6 +helped = 0 +harmed = 0 +created = "2026-08-14T22:02:42.305307Z" +last_confirmed = "2026-08-14T22:02:42.305307Z" ++++ + +always run cargo fmt -- --check locally and wait for gh pr checks green BEFORE merging to main — oversee CI gates fmt/clippy/test and cargo test alone does not catch fmt drift diff --git a/.strap/tools.toml b/.strap/tools.toml new file mode 100644 index 0000000..13dfe2c --- /dev/null +++ b/.strap/tools.toml @@ -0,0 +1 @@ +# managed tools — see `strap tool add` diff --git a/src/app.rs b/src/app.rs index f109067..7236d8c 100644 --- a/src/app.rs +++ b/src/app.rs @@ -36,6 +36,11 @@ pub struct App { pub kill_target_pid: Option, pub kill_target_name: String, pub help_mode: bool, + /// Set on terminal resize; main loop must clear the terminal before the + /// next draw. A shrink+grow that lands back on the old size is invisible + /// to ratatui's autoresize, yet the emulator has already scrolled the + /// alternate screen, so a diff-only redraw leaves stale rows behind. + pub needs_clear: bool, pub pinned_pids: HashSet, sort_mode: SortMode, @@ -100,6 +105,7 @@ impl App { kill_target_pid: None, kill_target_name: String::new(), help_mode: false, + needs_clear: false, pinned_pids: HashSet::new(), sort_mode: SortMode::Cpu, @@ -191,14 +197,25 @@ impl App { pub fn handle_event(&mut self) -> Result> { // Poll timeout sets the idle wakeup floor. Crossterm returns immediately // when an event arrives, so key latency is unaffected by this value. - #[allow(clippy::collapsible_if)] // Suggested fix uses unstable let-else syntax if event::poll(Duration::from_millis(100))? { - if let Event::Key(key) = event::read()? { + return Ok(self.apply_event(event::read()?)); + } + Ok(false) + } + + /// Apply one terminal event; returns true if a redraw is needed. + fn apply_event(&mut self, ev: Event) -> bool { + match ev { + Event::Key(key) => { self.handle_key_event(key); - return Ok(true); + true + } + Event::Resize(_, _) => { + self.needs_clear = true; + true } + _ => false, } - Ok(false) } fn handle_key_event(&mut self, key: KeyEvent) { @@ -463,3 +480,17 @@ impl App { processes } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn resize_event_requests_clear_and_redraw() { + let (tx, _rx) = mpsc::channel(); + let mut app = App::new(tx); + assert!(!app.needs_clear); + assert!(app.apply_event(Event::Resize(80, 24))); + assert!(app.needs_clear); + } +} diff --git a/src/main.rs b/src/main.rs index b447c15..9c902cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -113,6 +113,9 @@ fn main() -> Result<(), Box> { // Only render if something changed if data_updated || event_occurred { + if std::mem::take(&mut app.needs_clear) { + terminal.clear()?; + } profile!("render", terminal.draw(|f| ui::render(f, &mut app))?); } }