7662 lines · 295.3 KB · Zig
RawDownload
//! Grid-level resize tests that replay `TranscriptRuntime` output through//! `vt_emulator.Grid` without a TTY or signals. const std = @import("std"); const question_prompt = @import("../core/agent/question_prompt.zig");const debug_trace = @import("../core/shared/debug_trace.zig");const display_width = @import("../core/shared/display_width.zig");const diff_mod = @import("../core/output/diff.zig");const io_mod = @import("../core/shared/io.zig");const skill_runtime = @import("../core/skills/skill_runtime.zig");const types = @import("../core/shared/types.zig");const assistant_presentation = @import("../core/agent/assistant_presentation.zig");const builtin_commands = @import("../builtins/commands.zig"); const surface_frame = @import("footer/surface_frame.zig");const surface_invalidation = @import("footer/surface_invalidation.zig");const interaction_state = @import("footer/interaction_state.zig");const approval_prompt = @import("../core/permissions/approval_prompt.zig");const render_input = @import("footer/render_input.zig");const footer_viewport = @import("footer/viewport.zig");const activity_runtime = @import("../core/output/activity_runtime.zig");const core_input_runtime = @import("../core/input/runtime.zig");const ui_render = @import("render.zig");const render_engine = @import("render_engine.zig");const render_request = @import("render_request.zig");const shell_runtime = @import("shell_runtime.zig");const shimmer_runtime = @import("transcript/shimmer_runtime.zig");const transcript_painter = @import("transcript/painter.zig");const transcript_runtime = @import("transcript/runtime.zig");const full_transcript_screen = @import("full_transcript_screen.zig");const vt_emulator = @import("../core/terminal/engine.zig"); const Allocator = std.mem.Allocator;const Layout = types.Layout;const Metrics = types.Metrics;const TranscriptPreparationSource = transcript_runtime.TranscriptPreparationSource;const TranscriptRuntime = transcript_runtime.TranscriptRuntime;const Grid = vt_emulator.Grid;const InputRuntime = core_input_runtime.Runtime; const TestBodyDisposition = enum {    paint,    retain,}; const TestFrameObservation = struct {    shadow_state: render_engine.terminal_diff.ShadowCommitState = .committed,    body_disposition: TestBodyDisposition = .paint,    body_paints: usize = 0,    retained_transcript_changed_cells: usize = 0,    document_append_bytes: usize = 0,    document_append_clear_rows: ?u16 = null,    transcript_history_floor_respected: bool = true,    planned_scroll_rows: u16 = 0,    committed_scroll_rows: u16 = 0,    unplanned_scroll_rows: u16 = 0,    changed_cells: usize = 0,}; /// Test harness that captures every byte `TranscriptRuntime` emits and/// replays it through a virtual terminal.pub const Harness = struct {    alloc: Allocator,    tmp: std.testing.TmpDir,    file: std.Io.File,    path: []u8,    read_offset: u64 = 0,    vt: Grid,    shell: TranscriptRuntime,    metrics: Metrics = .{},    frame_redraw: bool = false,    last_frame: TestFrameObservation = .{},     pub fn init(alloc: Allocator, cols: u16, rows: u16, footer_rows: u16) !Harness {        var tmp = std.testing.tmpDir(.{});        errdefer tmp.cleanup();         const filename = "ansi.log";        var file = try tmp.dir.createFile(std.testing.io, filename, .{ .read = true });        errdefer file.close(io_mod.getIo());         const path = try alloc.dupe(u8, filename);        errdefer alloc.free(path);         const layout = layoutFor(cols, rows, footer_rows);         var harness: Harness = .{            .alloc = alloc,            .tmp = tmp,            .file = file,            .path = path,            .vt = try Grid.init(alloc, cols, rows),            .shell = .{                .stdout_file = file,                .layout = layout,                .maxxing_mode = .legacy,            },        };        harness.vt.cursor_row = layout.content_bottom;        harness.vt.cursor_col = 1;        try harness.shell.initBacking(alloc);        try harness.shell.enableShadowVt(alloc);        return harness;    }     pub fn deinit(self: *Harness) void {        self.shell.deinit(self.alloc);        self.file.close(io_mod.getIo());        self.tmp.cleanup();        self.alloc.free(self.path);        self.vt.deinit();    }     /// Pull any bytes written since the last flush into the VT grid.    pub fn flush(self: *Harness) !void {        const total = try self.file.length(io_mod.getIo());        if (total <= self.read_offset) return;        const want: usize = @intCast(total - self.read_offset);        const buf = try self.alloc.alloc(u8, want);        defer self.alloc.free(buf);        const n = try self.file.readPositionalAll(io_mod.getIo(), buf, self.read_offset);        try self.vt.feed(buf[0..n]);        self.read_offset += n;    }     pub fn driveResize(self: *Harness, cols: u16, rows: u16, footer_rows: u16, settled: bool) !void {        const new_layout = layoutFor(cols, rows, footer_rows);        try self.vt.resize(cols, rows);        try shell_runtime.applyResizeWithLayout(            &self.shell,            &self.metrics,            new_layout,            settled,        );        try self.renderTranscriptFrameIfDirty();        try self.flush();    }     pub fn renderTranscriptFrame(self: *Harness) !void {        try self.renderTranscriptFrameWithOptions(0, null);    }     pub fn renderTranscriptFrameOmittingEntry(self: *Harness, entry_id: u32) !void {        try self.renderTranscriptFrameWithOptions(0, entry_id);    }     pub fn renderTranscriptFrameIfDirty(self: *Harness) !void {        if (!self.shell.transcript_band_dirty and !self.shell.render_requests.hasPending()) return;        try self.renderTranscriptFrame();    }     pub fn initStartupViewport(self: *Harness, requested_start_row: u16, min_body_rows: u16) !void {        const reserve_rows = @min(min_body_rows, self.shell.layout.content_bottom);        const max_start_row = if (reserve_rows > 0)            self.shell.layout.content_bottom - reserve_rows + 1        else            self.shell.layout.content_bottom;        if (requested_start_row > max_start_row) {            var cursor_buf: [32]u8 = undefined;            const cursor = try std.fmt.bufPrint(&cursor_buf, "\x1b[{d};1H", .{self.shell.layout.rows});            try self.file.writeStreamingAll(io_mod.getIo(), cursor);            var row: u16 = 0;            while (row < requested_start_row - max_start_row) : (row += 1) {                try self.file.writeStreamingAll(io_mod.getIo(), "\n");            }        }        try self.shell.initViewportWithReservedRows(&self.metrics, requested_start_row, min_body_rows);    }     pub fn renderTranscriptFrameWithBottomReservation(self: *Harness, bottom_reserved_rows: u16) !void {        try self.renderTranscriptFrameWithOptions(bottom_reserved_rows, null);    }     fn renderTranscriptFrameWithOptions(        self: *Harness,        bottom_reserved_rows: u16,        omitted_entry_id: ?u32,    ) !void {        if (!self.shell.render_requests.hasPending()) self.shell.render_requests.request(.transcript);        var attempt = (try self.shell.render_requests.beginAttempt()).?;        defer attempt.deinit();        const snapshot = attempt.snapshot;        var source = if (self.shell.fullTranscriptActive())            try self.prepareFullTranscriptSource()        else if (omitted_entry_id) |entry_id|            try self.shell.prepareTranscriptSourceOmittingEntry(self.alloc, entry_id)        else            try self.shell.prepareTranscriptSource(self.alloc, null);        defer source.deinit(self.alloc);        const reserved_rows = @min(bottom_reserved_rows, self.shell.layout.content_bottom -| 1);        const footer_height = self.shell.layout.rows - self.shell.layout.divider_top_row + 1;        var prepared: ?transcript_painter.PreparedTranscriptSurfacePaint = null;        defer if (prepared) |*paint| paint.deinit(self.alloc);        var fixed_point_ctx = ReservedTranscriptSolveContext{            .h = self,            .source = &source,            .prepared = &prepared,            .reserved_rows = reserved_rows,        };        const fixed_point = try render_engine.frame_fixed_point.solve(            ReservedTranscriptSolveContext,            &fixed_point_ctx,            .{                .terminal = self.shell.layout,                .owned_top = self.shell.owned_top_row,                .footer = .{                    .natural_rows = footer_height +| reserved_rows,                    .min_rows = footer_height +| reserved_rows,                    .max_rows = footer_height +| reserved_rows,                },                .transcript = source.preview,                .prior = self.shell.committed_frame_layout,            },            ReservedTranscriptSolveContext.prepareCandidate,            ReservedTranscriptSolveContext.resolveCandidate,        );         var invalidations = snapshot.invalidations;        self.shell.normalizeFrameInvalidations(&invalidations);        const paint = &prepared.?;        var plan = transcriptOnlyPlan(&self.shell, paint, fixed_point.layout.owned_top, invalidations);        var transition = try resolveAndSealTranscriptTransitionForTest(            &self.shell,            self.alloc,            &source,            paint,            &plan,            fixed_point.scroll_plan,        );        defer transition.deinit(self.alloc);        var paint_ctx = TestFramePaintContext{            .h = self,            .prepared = paint,        };        const result = try commitTestFrame(            self,            plan,            paint,            null,            null,            fixed_point.scroll_plan,            &transition,            &paint_ctx,        );        if (result == .committed) {            attempt.commit(0, render_request.animation_interval_ms, false);        } else {            attempt.restore();        }    }     pub fn renderFooterFrame(        self: *Harness,        approval: *const approval_prompt.ApprovalPrompt,        force_redraw: *bool,        ctx: render_input.RenderContext,    ) !void {        if (!self.shell.render_requests.hasPending()) self.shell.render_requests.request(.footer);        var attempt = (try self.shell.render_requests.beginAttempt()).?;        defer attempt.deinit();        const snapshot = attempt.snapshot;        var invalidations = snapshot.invalidations;        self.shell.normalizeFrameInvalidations(&invalidations);        var measurement = try surface_frame.measureSurfaceFooter(self.alloc, &self.shell, approval.projection(), ctx);        defer measurement.deinit(self.alloc);        const footer_reservation_changed = measurement.changesFooterReservation(&self.shell);        const replay_displaced_footer_history =            measurement.replaysDisplacedTranscriptHistory(&self.shell);        var prepared: ?transcript_painter.PreparedTranscriptSurfacePaint = null;        defer if (prepared) |*paint| paint.deinit(self.alloc);        var resolved_target: ?transcript_runtime.TranscriptRuntime.ResolvedTranscriptTarget = null;        const activity = frameActivityState(self, &measurement);        const tracked_entry_id = switch (measurement.activity_projection) {            .tool_slot => |slot| slot.entry_id,            .none, .turn_thinking => null,        };        const omitted_entry_id = switch (measurement.activity_projection) {            .tool_slot => |slot| if (slot.thinking_label != null) slot.entry_id else null,            .none, .turn_thinking => null,        };        var source = if (self.shell.fullTranscriptActive())            try self.prepareFullTranscriptSource()        else if (omitted_entry_id) |entry_id|            try self.shell.prepareTranscriptSourceOmittingEntry(self.alloc, entry_id)        else            try self.shell.prepareTranscriptSource(self.alloc, tracked_entry_id);        defer source.deinit(self.alloc);        const fixed_point = try solveTestFrame(            self,            &measurement,            activity,            &source,            &prepared,            &resolved_target,            footer_reservation_changed,            replay_displaced_footer_history,            invalidations,        );         const footer_rows = measurement.frameLayoutRows(self.shell.layout.rows, fixed_point.layout.footer_area.top);        const activity_placement = render_engine.activity_placement.resolve(            measurement.activity_projection,            activity,            fixed_point.layout,        );        const activity_hides_cursor = switch (activity_placement) {            .transient_row => true,            .none, .overlay_entry => false,        };        const viewport = if (resolved_target) |target|            target.selection()        else if (prepared) |*paint|            paint.selection        else            surface_frame.currentSurfaceFooterTranscriptState(&self.shell).selection;        const cursor_target = if (resolved_target) |target|            render_engine.paint_plan.FrameCursorTarget{                .row = target.cursorRow(),                .col = target.cursorCol(),                .visible = !activity_hides_cursor,            }        else if (prepared) |*paint|            render_engine.paint_plan.FrameCursorTarget{                .row = paint.cursor.cursor_row,                .col = paint.cursor.cursor_col,                .visible = !activity_hides_cursor,            }        else            render_engine.paint_plan.FrameCursorTarget{                .row = footer_rows.input_base,                .col = 1,                .visible = !activity_hides_cursor,            };        const plan = fixed_point.layout.toPaintPlan(.{            .footer_rows = footer_rows,            .viewport = viewport,            .activity = activity_placement,            .cursor_target = cursor_target,            .reset_terminal = self.shell.terminal_reset_pending,            .preserve_scrollback = !self.shell.pending_scroll_compact,        });        var footer_frame = try surface_frame.prepareMeasuredSurfaceFooterFrameForPlan(            self.alloc,            &self.shell,            force_redraw,            approval.projection(),            ctx,            &measurement,            plan,            invalidations,        );        defer footer_frame.deinit(self.alloc);        var transition: ?transcript_runtime.TranscriptTransition = null;        defer if (transition) |*value| value.deinit(self.alloc);        if (prepared) |*paint| {            const target = resolved_target orelse return error.MissingResolvedTranscriptTarget;            transition = try self.shell.sealTranscriptTransition(                self.alloc,                &source,                paint,                &footer_frame.paint,                target,            );        }         var paint_ctx = TestFramePaintContext{            .h = self,            .prepared = if (prepared) |*paint| paint else null,            .footer_frame = &footer_frame,        };        const result = try commitTestFrame(            self,            footer_frame.paint,            if (prepared) |*paint| paint else null,            &footer_frame,            &measurement,            fixed_point.scroll_plan,            if (transition) |*value| value else null,            &paint_ctx,        );        if (result == .committed) {            attempt.commit(0, render_request.animation_interval_ms, paint_ctx.activity_result.painted);            force_redraw.* = false;        } else {            attempt.restore();        }    }     fn prepareFullTranscriptSource(self: *Harness) !TranscriptPreparationSource {        var projection = try full_transcript_screen.buildProjection(            self.alloc,            self.shell.entries.items,            self.shell.tool_details.items,            self.shell.command_output_blocks.items,            self.shell.command_output_render.styles,            self.shell.layout.cols,            self.shell.fullTranscriptAnchorEntryId(),        );        defer projection.deinit(self.alloc);        const measurement = try full_transcript_screen.measureProjectionInterruptible(            self.alloc,            &projection,            null,            self.shell.layout.cols,            null,        );        const visible_rows: u16 = @intCast(@max(@min(measurement.total_rows, std.math.maxInt(u16)), 1));        const bytes = try full_transcript_screen.renderProjectionViewportSourceInterruptible(            self.alloc,            &projection,            null,            self.shell.layout.cols,            visible_rows,            0,            null,        );        return self.shell.prepareFullTranscriptViewportSource(self.alloc, bytes);    }}; const ReservedTranscriptSolveContext = struct {    h: *Harness,    source: *const TranscriptPreparationSource,    prepared: *?transcript_painter.PreparedTranscriptSurfacePaint,    reserved_rows: u16,     fn prepareCandidate(        self: *ReservedTranscriptSolveContext,        candidate: render_engine.frame_layout.FrameLayout,    ) !render_engine.frame_fixed_point.CandidatePreparation {        if (self.prepared.*) |*paint| {            paint.deinit(self.h.alloc);            self.prepared.* = null;        }        const target_bottom = self.h.shell.layout.content_bottom - self.reserved_rows;        if (target_bottom < candidate.owned_top) return error.InvalidFrameScrollPlan;        self.prepared.* = try self.h.shell.prepareTranscriptSurfacePaintFromSourceForArea(            self.h.alloc,            &self.h.metrics,            self.source,            .{ .top = candidate.owned_top, .bottom = target_bottom },        );        self.prepared.*.?.bottom_reserved_rows = self.reserved_rows;        return .{            .inline_advance_rows = self.h.shell.planTranscriptScroll(&self.prepared.*.?).planned_rows,            .occupied_transcript_rows = candidate.transcript_area.height(),        };    }     fn resolveCandidate(        self: *ReservedTranscriptSolveContext,        candidate: render_engine.frame_layout.FrameLayout,        scroll_plan: render_engine.frame_scroll_plan.FrameScrollPlan,    ) !render_engine.frame_fixed_point.CandidateResolution {        _ = self;        _ = scroll_plan;        return .{ .occupied_transcript_rows = candidate.transcript_area.height() };    }}; fn solveTestFrame(    h: *Harness,    measurement: *const surface_frame.SurfaceFooterMeasurement,    activity: render_engine.frame_layout.ActivityState,    source: *const TranscriptPreparationSource,    prepared: *?transcript_painter.PreparedTranscriptSurfacePaint,    resolved_target: *?transcript_runtime.TranscriptRuntime.ResolvedTranscriptTarget,    footer_reservation_changed: bool,    replay_displaced_footer_history: bool,    attempt_invalidations: render_engine.paint_plan.FrameInvalidationSet,) !render_engine.frame_fixed_point.FramePlan {    var ctx = TestFrameSolveContext{        .h = h,        .source = source,        .prepared = prepared,        .resolved_target = resolved_target,        .measurement = measurement,        .activity = activity,        .footer_reservation_changed = footer_reservation_changed,        .replay_displaced_footer_history = replay_displaced_footer_history,        .attempt_invalidations = attempt_invalidations,    };    return render_engine.frame_fixed_point.solve(        TestFrameSolveContext,        &ctx,        .{            .terminal = h.shell.layout,            .owned_top = h.shell.owned_top_row,            .footer = measurement.frameLayoutMeasurement(),            .transcript = source.preview,            .activity = activity,            .prior = h.shell.committed_frame_layout,        },        TestFrameSolveContext.prepareCandidate,        TestFrameSolveContext.resolveCandidate,    );} const TestFrameSolveContext = struct {

Lines 1–500 of 7662.