Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
4 changes: 3 additions & 1 deletion src/app/runtime.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
33 changes: 12 additions & 21 deletions src/render/renderer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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| {
Expand Down Expand Up @@ -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.
Expand Down