e0e1171e
main: widen computePollTimeoutMs to accept a second deadline
a73x 2026-04-19 07:00
Prep for cursor blink deadline. Call site still passes null for the blink slot until the blink state machine lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
diff --git a/src/main.zig b/src/main.zig index 49ca018..384cee0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -341,7 +341,8 @@ fn runTerminal(alloc: std.mem.Allocator) !void { while (!window.should_close and p.isChildAlive()) { const repeat_timeout_ms = remainingRepeatTimeoutMs(keyboard.nextRepeatDeadlineNs()); const timeout = computePollTimeoutMs(repeat_timeout_ms, render_pending); // Blink deadline wired up in Task 4; null for now. const timeout = computePollTimeoutMs(repeat_timeout_ms, null, render_pending); try frame_loop.waitForWork(&pollfds_extra, timeout); // PTY output @@ -788,9 +789,17 @@ fn remainingRepeatTimeoutMs(deadline_ns: ?i128) ?i32 { return @intCast(@divTrunc(remaining_ns + std.time.ns_per_ms - 1, std.time.ns_per_ms)); } fn computePollTimeoutMs(next_repeat_in_ms: ?i32, render_pending: bool) i32 { fn computePollTimeoutMs( next_repeat_in_ms: ?i32, next_blink_in_ms: ?i32, render_pending: bool, ) i32 { if (render_pending) return 0; return next_repeat_in_ms orelse -1; if (next_repeat_in_ms) |r| { if (next_blink_in_ms) |b| return if (r < b) r else b; return r; } return next_blink_in_ms orelse -1; } fn extractSelectedText( @@ -1627,10 +1636,26 @@ fn mapKeysymToInputKey(keysym: u32) ?vt.InputKey { }; } test "event loop waits indefinitely when idle and wakes for imminent repeat" { try std.testing.expectEqual(@as(i32, -1), computePollTimeoutMs(null, false)); try std.testing.expectEqual(@as(i32, 0), computePollTimeoutMs(5, true)); try std.testing.expectEqual(@as(i32, 17), computePollTimeoutMs(17, false)); test "computePollTimeoutMs: idle with no deadlines returns -1" { try std.testing.expectEqual(@as(i32, -1), computePollTimeoutMs(null, null, false)); } test "computePollTimeoutMs: render_pending forces zero regardless of deadlines" { try std.testing.expectEqual(@as(i32, 0), computePollTimeoutMs(5, null, true)); try std.testing.expectEqual(@as(i32, 0), computePollTimeoutMs(null, 5, true)); try std.testing.expectEqual(@as(i32, 0), computePollTimeoutMs(3, 7, true)); try std.testing.expectEqual(@as(i32, 0), computePollTimeoutMs(null, null, true)); } test "computePollTimeoutMs: single deadline passes through" { try std.testing.expectEqual(@as(i32, 17), computePollTimeoutMs(17, null, false)); try std.testing.expectEqual(@as(i32, 500), computePollTimeoutMs(null, 500, false)); } test "computePollTimeoutMs: returns min of two deadlines" { try std.testing.expectEqual(@as(i32, 17), computePollTimeoutMs(17, 500, false)); try std.testing.expectEqual(@as(i32, 17), computePollTimeoutMs(500, 17, false)); try std.testing.expectEqual(@as(i32, 7), computePollTimeoutMs(7, 7, false)); } test "planRowRefresh requests full rebuild for full dirty state" {