diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 584e196..e18dcea 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -95,7 +95,7 @@ Platform Session Rendering UI Overlay - Runtime persistence is updated during the frame loop when runtime state changes (cwd changes, terminal spawn/despawn, window move/resize, font size changes), and finalization is explicit at the end of `app/runtime.zig`: final save and deinit `Persistence` before deferred subsystem teardown begins. - Font reload paths are transactional: acquire both replacement fonts first, then swap and destroy old fonts, so a partial reload failure cannot leave deinit hooks pointing at already-freed font resources. - Window-resize scale handling follows a single ordered path (`reload-if-needed`, then `resize`) to keep behavior consistent between changed-scale and unchanged-scale events. -- Terminal resizes follow Ghostty's ordering: update the PTY winsize first, then resize the ghostty-vt terminal model, allowing ghostty-vt's semantic prompt clearing when the shell opted into prompt redraws. Architect records new terminal row/column sizes only after resize calls succeed and skips PTY resize calls when the terminal row/column count is unchanged. Grid/full transitions update the backing PTY/VT size after the stable view mode is reached, and grid sizing accounts for grid font scaling plus the reserved CWD-bar space so compact tiles wrap to the visible area. Grid rendering follows the active cursor row so compact tiles show short sessions from the top and long sessions near the latest output. During synchronized output and immediately after terminal resizes, Architect reuses that session's last rendered texture when it matches the current render mode and size, while continuing to present the rest of the scene. Synchronized-output holds wait for output to go quiet with a hard cap; resize holds are short settle windows so continuously streaming sessions do not stay hidden behind stale pre-resize textures. +- Terminal resizes follow Ghostty's ordering: update the PTY winsize first, then resize the ghostty-vt terminal model, allowing ghostty-vt's semantic prompt clearing when the shell opted into prompt redraws. Architect records new terminal row/column sizes only after resize calls succeed and skips PTY resize calls when the terminal row/column count is unchanged. Grid/full transitions update the backing PTY/VT size after the stable view mode is reached, and grid sizing accounts for grid font scaling plus the reserved CWD-bar space so compact tiles wrap to the visible area. Grid rendering follows the active cursor row so compact tiles show short sessions from the top and long sessions near the latest output. During synchronized output and immediately after terminal resizes, Architect reuses that session's last rendered texture when it matches the current render mode; same-mode output holds may scale the old texture across grid-cell pixel-size changes until output settles. Synchronized-output holds wait for output to go quiet with a hard cap; resize holds are short settle windows so continuously streaming sessions do not stay hidden behind stale pre-resize textures. - Shared Utilities (`geom`, `colors`, `dpi`, `config`, `logging`, `metrics`, etc.) may be imported by any layer but never import from layers above them. - **Exception:** `app/*` modules may import `c.zig` directly for SDL type definitions used in input handling. This is a pragmatic shortcut for FFI constants, not a general license to depend on the Platform layer. diff --git a/src/app/runtime.zig b/src/app/runtime.zig index 159e975..ab63564 100644 --- a/src/app/runtime.zig +++ b/src/app/runtime.zig @@ -2320,7 +2320,9 @@ pub fn run() !void { const prev_cwd_ptr = if (session.cwd_path) |p| p.ptr else null; session.updateCwd(now); _ = session.expireSynchronizedOutput(now); - _ = session.expireTerminalResizeHold(now); + if (anim_state.mode != .GridResizing) { + _ = session.expireTerminalResizeHold(now); + } if (session.cwd_path) |new_cwd| { // Compare pointers: if they differ, cwd changed (and old memory was freed by updateCwd) const changed = prev_cwd_ptr == null or prev_cwd_ptr != new_cwd.ptr; diff --git a/src/render/renderer.zig b/src/render/renderer.zig index e81111a..a444ce4 100644 --- a/src/render/renderer.zig +++ b/src/render/renderer.zig @@ -915,17 +915,12 @@ fn shouldHoldSessionCacheRefresh( output_hold_active: bool, has_texture: bool, cache_epoch: u64, - cache_width: c_int, - cache_height: c_int, - requested_rect: Rect, cached_render_mode: RenderCache.CacheRenderMode, requested_render_mode: RenderCache.CacheRenderMode, ) bool { return output_hold_active and has_texture and cache_epoch != 0 and - cache_width == requested_rect.w and - cache_height == requested_rect.h and cached_render_mode == requested_render_mode; } @@ -945,16 +940,15 @@ fn renderHeldSessionTexture( ui_scale: f32, ) bool { const render_mode = cacheRenderMode(is_grid_view); - if (!shouldHoldSessionCacheRefresh( - session.outputHoldActive(), + const output_hold_active = session.outputHoldActive(); + const should_hold = shouldHoldSessionCacheRefresh( + output_hold_active, cache_entry.texture != null, cache_entry.cache_epoch, - cache_entry.width, - cache_entry.height, - rect, cache_entry.cache_render_mode, render_mode, - )) return false; + ); + if (!should_hold) return false; const tex = cache_entry.texture orelse return false; if (wave_effect) |wave| { @@ -1080,16 +1074,13 @@ fn renderSessionCached( cache_entry.presented_epoch = session.render_epoch; } -test "synchronized output hold reuses populated cache only" { - const rect = Rect{ .x = 0, .y = 0, .w = 100, .h = 80 }; - - try std.testing.expect(shouldHoldSessionCacheRefresh(true, true, 1, 100, 80, rect, .grid, .grid)); - try std.testing.expect(!shouldHoldSessionCacheRefresh(false, true, 1, 100, 80, rect, .grid, .grid)); - try std.testing.expect(!shouldHoldSessionCacheRefresh(true, false, 1, 100, 80, rect, .grid, .grid)); - try std.testing.expect(!shouldHoldSessionCacheRefresh(true, true, 0, 100, 80, rect, .grid, .grid)); - try std.testing.expect(!shouldHoldSessionCacheRefresh(true, true, 1, 99, 80, rect, .grid, .grid)); - try std.testing.expect(!shouldHoldSessionCacheRefresh(true, true, 1, 100, 79, rect, .grid, .grid)); - try std.testing.expect(!shouldHoldSessionCacheRefresh(true, true, 1, 100, 80, rect, .grid, .full)); +test "output hold reuses same-mode populated cache only" { + try std.testing.expect(shouldHoldSessionCacheRefresh(true, true, 1, .grid, .grid)); + try std.testing.expect(!shouldHoldSessionCacheRefresh(false, true, 1, .grid, .grid)); + try std.testing.expect(!shouldHoldSessionCacheRefresh(true, false, 1, .grid, .grid)); + try std.testing.expect(!shouldHoldSessionCacheRefresh(true, true, 0, .grid, .grid)); + try std.testing.expect(!shouldHoldSessionCacheRefresh(true, true, 1, .grid, .full)); + try std.testing.expect(!shouldHoldSessionCacheRefresh(true, true, 1, .full, .grid)); } /// Render the cached tile texture in horizontal strips with per-strip wave scaling.