a73x

d7e61651

Force full row rebuild when selection span changes

a73x   2026-04-09 19:24

planRowRefresh only considered VT dirty flags, so pointer-driven
selection changes (motion, click) never triggered row rebuilds and
the highlight was never painted.

Track the selection span before draining the pointer queue and force
.full rebuild mode when it changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

diff --git a/src/main.zig b/src/main.zig
index cc94c5d..4ccf41b 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -248,9 +248,11 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
        // Pointer events → update selection state
        const ptr_cell_w = cell_w / @as(u32, @intCast(geom.buffer_scale));
        const ptr_cell_h = cell_h / @as(u32, @intCast(geom.buffer_scale));
        const prev_selection = activeSelectionSpan(selection);
        for (pointer.event_queue.items) |ev| {
            handlePointerSelectionEvent(&selection, ev, ptr_cell_w, ptr_cell_h, cols, rows);
        }
        const selection_changed = !std.meta.eql(activeSelectionSpan(selection), prev_selection);
        if (pointer.event_queue.items.len > 0) {
            pointer.event_queue.clearRetainingCapacity();
            render_pending = true;
@@ -364,7 +366,7 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
        try render_cache.resizeRows(alloc, term_rows.len);

        const refresh_plan = planRowRefresh(
            if (term.render_state.dirty == .full) .full else .partial,
            if (term.render_state.dirty == .full or selection_changed) .full else .partial,
            dirty_rows,
            .{
                .cursor = .{