4061 lines · 151.9 KB · Zig
RawDownload
const std = @import("std");const builtin = @import("builtin");const debug_trace = @import("../../core/shared/debug_trace.zig");const types = @import("../../core/shared/types.zig");const ui_terminal = @import("../terminal/terminal.zig");const vt_emulator = @import("../../core/terminal/engine.zig");const frame_cell_match = @import("frame_cell_match.zig");const frame_scroll_plan = @import("frame_scroll_plan.zig");const frame_surface = @import("frame_surface.zig");const paint_plan = @import("paint_plan.zig"); const Allocator = std.mem.Allocator;const Metrics = types.Metrics; pub const ShadowCommitState = enum {    committed,    terminal_partial_write,    shadow_feed_failed,     pub fn is_committed(self: ShadowCommitState) bool {        return self == .committed;    }}; pub const FrameSinkWriteResult = union(enum) {    complete,    partial: struct {        accepted_bytes: usize,        err: anyerror,    },}; pub const FrameSink = struct {    ctx: *anyopaque,    write_frame: *const fn (ctx: *anyopaque, metrics: *Metrics, bytes: []const u8) FrameSinkWriteResult,}; pub const FrameTerminalTransition = union(enum) {    none,    restore_normal_screen: struct {        mouse_tracking_active: bool,    },     fn sequence(self: FrameTerminalTransition) []const u8 {        return switch (self) {            .none => "",            .restore_normal_screen => |restore| ui_terminal.alternateScreenFrameRestoreSequence(                restore.mouse_tracking_active,            ),        };    }}; pub const FrameCommitInput = struct {    previous: *vt_emulator.Grid,    surface: *const frame_surface.FrameSurface,    repaint_window: paint_plan.FrameRepaintWindow,    synchronized_update: bool,    history_reset_uses_ris: bool = false,    scroll_plan: frame_scroll_plan.FrameScrollPlan,    document_append: frame_scroll_plan.FrameDocumentAppend = .{},    terminal_transition: FrameTerminalTransition = .none,    prepared_movement: ?*const PreparedTerminalMovement = null,    sink: FrameSink,    metrics: *Metrics,}; pub const TerminalMovementSegment = struct {    start: usize = 0,    end: usize = 0,    scroll_rows: u16 = 0,     pub fn hasBytes(self: TerminalMovementSegment) bool {        return self.end > self.start;    }     fn absolute(self: TerminalMovementSegment, base: usize) TerminalMovementSegment {        return .{            .start = base + self.start,            .end = base + self.end,            .scroll_rows = self.scroll_rows,        };    }}; pub const TerminalMovementSegments = struct {    terminal_transition: TerminalMovementSegment = .{},    document_append: TerminalMovementSegment = .{},    alignment_scroll: TerminalMovementSegment = .{},}; pub const FrameScrollAttribution = struct {    control_prefix_scroll_rows: u16 = 0,    document_append_scroll_rows: u16 = 0,    alignment_scroll_rows: u16 = 0,    movement_gap_scroll_rows: u16 = 0,    paint_tail_scroll_rows: u16 = 0,     pub fn movementScrollRows(self: FrameScrollAttribution) u16 {        return self.document_append_scroll_rows +| self.alignment_scroll_rows;    }     pub fn neutralScrollRows(self: FrameScrollAttribution) u16 {        return self.control_prefix_scroll_rows +|            self.movement_gap_scroll_rows +|            self.paint_tail_scroll_rows;    }     pub fn totalScrollRows(self: FrameScrollAttribution) u16 {        return self.movementScrollRows() +| self.neutralScrollRows();    }}; pub const PreparedTerminalMovement = struct {    bytes: []u8,    post_movement: vt_emulator.Grid,    document_append_start: usize = 0,    document_append_end: usize = 0,    segments: TerminalMovementSegments = .{},    scroll_rows: frame_scroll_plan.TerminalMovementRows = .{        .planned_scroll_rows = 0,        .materialized_scroll_rows = 0,        .alignment_scroll_rows = 0,        .expected_scroll_rows = 0,    },    terminal_transition: FrameTerminalTransition = .none,    reset_replay: bool = false,    source_rows: u16,    source_cols: u16,    target_rows: u16,    target_cols: u16,     pub fn deinit(self: *PreparedTerminalMovement, alloc: Allocator) void {        if (self.bytes.len > 0) alloc.free(self.bytes);        self.post_movement.deinit();        self.* = undefined;    }     pub fn hasDocumentAppend(self: PreparedTerminalMovement) bool {        return self.segments.document_append.hasBytes();    }     fn validateForCommit(        self: *const PreparedTerminalMovement,        source: *const vt_emulator.Grid,        target_cols: u16,        target_rows: u16,        planned_scroll_rows: u16,        non_deferable_scroll_rows: u16,        terminal_transition: FrameTerminalTransition,        reset_replay: bool,    ) !void {        const expected_rows = try resolveTerminalMovementRows(            planned_scroll_rows,            self.scroll_rows.materialized_scroll_rows,            non_deferable_scroll_rows,            reset_replay,            source.cols,            source.rows,            target_cols,            target_rows,        );        if (self.source_rows != source.rows or            self.source_cols != source.cols or            self.target_rows != target_rows or            self.target_cols != target_cols or            !std.meta.eql(self.scroll_rows, expected_rows) or            !std.meta.eql(self.terminal_transition, terminal_transition) or            self.reset_replay != reset_replay or            self.segments.terminal_transition.scroll_rows != 0 or            self.segments.document_append.scroll_rows != self.scroll_rows.materialized_scroll_rows or            self.segments.alignment_scroll.scroll_rows != self.scroll_rows.alignment_scroll_rows)        {            return error.InvalidFrameScrollPlan;        }    }     fn validateCompleteWrite(        self: *const PreparedTerminalMovement,        accepted_bytes: usize,        frame_bytes: usize,        scroll_attribution: FrameScrollAttribution,    ) !void {        if (accepted_bytes != frame_bytes) return;        if (scroll_attribution.neutralScrollRows() != 0 or            scroll_attribution.document_append_scroll_rows != self.scroll_rows.materialized_scroll_rows or            scroll_attribution.alignment_scroll_rows != self.scroll_rows.alignment_scroll_rows or            scroll_attribution.totalScrollRows() != self.scroll_rows.emittedScrollRows())        {            return error.InvalidFrameScrollPlan;        }    }     fn documentAppendWireRange(self: *const PreparedTerminalMovement, prefix_len: usize) DocumentAppendWireRange {        if (!self.hasDocumentAppend()) return .{};        return .{            .start = prefix_len + self.document_append_start,            .end = prefix_len + self.document_append_end,        };    }}; pub const FrameCommitResult = struct {    bytes_written: usize,    changed_cells: usize,    full_repaint: bool,    terminal_scroll_rows_committed: u16 = 0,    scroll_commit_receipt: ?frame_scroll_plan.FrameScrollCommit = null,    scroll_attribution: FrameScrollAttribution = .{},    document_append_committed: bool = false,    committed_cursor_row: u16,    committed_cursor_col: u16,    committed_cursor_visible: bool = true,    shadow_state: ShadowCommitState,    next_invalidation: paint_plan.FrameInvalidationSet,     pub fn state(self: FrameCommitResult) ShadowCommitState {        return self.shadow_state;    }     pub fn is_committed(self: FrameCommitResult) bool {        return self.state().is_committed();    }     pub fn terminal_scroll_rows_applied(self: FrameCommitResult) u16 {        return self.terminal_scroll_rows_committed;    }     pub fn document_append_applied(self: FrameCommitResult) bool {        return self.document_append_committed;    }     pub fn committed_cursor(self: FrameCommitResult) ?paint_plan.FrameCursorTarget {        if (!self.is_committed()) return null;        return .{            .row = self.committed_cursor_row,            .col = self.committed_cursor_col,            .visible = self.committed_cursor_visible,        };    }     pub fn retry_invalidation(self: FrameCommitResult) ?paint_plan.FrameInvalidationRange {        if (self.is_committed()) return null;        std.debug.assert(self.next_invalidation.len <= 1);        if (self.next_invalidation.isEmpty()) return null;        return self.next_invalidation.ranges()[0];    }     pub fn scrollCommit(        self: FrameCommitResult,        scroll_plan: frame_scroll_plan.FrameScrollPlan,    ) frame_scroll_plan.FrameScrollCommit {        if (self.scroll_commit_receipt) |receipt| {            std.debug.assert(receipt.matchesPlan(scroll_plan));            return receipt;        }        std.debug.assert(builtin.is_test);        return scroll_plan.commit(self.terminal_scroll_rows_committed);    }}; const CleanupState = enum {    none,    complete,    failed,}; const DocumentAppendWireRange = struct {    start: usize = 0,    end: usize = 0,     fn isEmpty(self: DocumentAppendWireRange) bool {        return self.end == 0;    }     fn committed(self: DocumentAppendWireRange, accepted_bytes: usize) bool {        return !self.isEmpty() and accepted_bytes >= self.end;    }     fn interrupted(self: DocumentAppendWireRange, accepted_bytes: usize) bool {        return !self.isEmpty() and accepted_bytes > self.start and !self.committed(accepted_bytes);    }}; const AcceptedFrameWrite = struct {    accepted_bytes: usize,    applied_scroll_rows: u16,    scroll_attribution: FrameScrollAttribution,    document_append_committed: bool,    document_append_interrupted: bool,}; const DocumentAppendMovement = struct {    segment: TerminalMovementSegment = .{},}; const FrameMovementSegments = struct {    movement_start: usize = 0,    movement_end: usize = 0,    document_append: TerminalMovementSegment = .{},    alignment_scroll: TerminalMovementSegment = .{},     fn none() FrameMovementSegments {        return .{};    }     fn fromPreparedMovement(prefix_len: usize, movement: PreparedTerminalMovement) FrameMovementSegments {        return .{            .movement_start = prefix_len,            .movement_end = prefix_len + movement.bytes.len,            .document_append = movement.segments.document_append.absolute(prefix_len),            .alignment_scroll = movement.segments.alignment_scroll.absolute(prefix_len),        };    }}; const ScrollAttributionBucket = enum {    control_prefix,    document_append,    alignment_scroll,    movement_gap,    paint_tail,}; const ShadowTestFault = enum {    none,    normal_clone_feed,    normal_clone_invalid,    repair_resize,    repair_canonical_feed,}; var shadow_test_fault: if (builtin.is_test) ShadowTestFault else void = if (builtin.is_test) .none else {}; pub fn flushFrame(input: FrameCommitInput) !FrameCommitResult {    try input.surface.plan.validate();    try input.surface.validate();     const alloc = input.surface.alloc;    var target = try input.surface.copyToTargetGrid(alloc);    defer target.deinit();    try input.scroll_plan.validate(target.rows);    try input.repaint_window.validate(input.surface.plan);     const repaint_window = input.repaint_window;    const terminal_scroll_rows = input.scroll_plan.terminal_scroll_rows;    if (input.document_append.reset_replay and !input.surface.plan.reset_terminal) {        return error.InvalidFrameScrollPlan;    }    var local_movement: ?PreparedTerminalMovement = null;    defer if (local_movement) |*movement| movement.deinit(alloc);    const movement = if (input.prepared_movement) |prepared|        prepared    else blk: {        local_movement = try prepareTerminalMovementForFrame(            alloc,            input.previous,            input.document_append,            terminal_scroll_rows,            input.scroll_plan.preserved_release_rows,            target.cols,            target.rows,            0,            input.terminal_transition,        );        break :blk &local_movement.?;    };    try movement.validateForCommit(        input.previous,        target.cols,        target.rows,        terminal_scroll_rows,        input.scroll_plan.preserved_release_rows,        input.terminal_transition,        input.document_append.reset_replay,    );    const terminal_scroll_bytes = movement.bytes;    if (terminal_scroll_rows > 0 or movement.hasDocumentAppend()) {        debug_trace.logf(            "frame_commit",            "terminal_movement planned_rows={d} materialized_rows={d} alignment_rows={d} append_bytes={d} append_wire_bytes={d}",            .{                terminal_scroll_rows,                movement.scroll_rows.materialized_scroll_rows,                movement.scroll_rows.alignment_scroll_rows,                input.document_append.bytes.len,                movement.document_append_end -| movement.document_append_start,            },        );    }     const dimensions_changed = input.previous.rows != target.rows or input.previous.cols != target.cols;    const previous_for_diff = movement.post_movement;    const changed_cells = countChangedCells(previous_for_diff, target, repaint_window);    const full_repaint = input.surface.plan.reset_terminal or dimensions_changed or terminal_scroll_rows > 0 or invalidationRequiresFullRepaint(input.surface.plan.invalidation);    if (terminal_scroll_bytes.len == 0 and        terminal_scroll_rows == 0 and        !full_repaint and        changed_cells == 0 and        cursorMatches(previous_for_diff, target))    {        debug_trace.logf(            "frame_commit",            "skipped_noop bytes=0 changed_cells=0 band={d}..{d} cursor={d},{d}",            .{ firstRepaintRow(repaint_window), lastRepaintRow(repaint_window), target.cursor_row, target.cursor_col },        );        return committed_result(            0,            0,            false,            input.scroll_plan.commit(0),            .{},            false,            &target,        );    }     var wire_frame: std.Io.Writer.Allocating = .init(alloc);    defer wire_frame.deinit();    const prefix_len = try composeWireFrame(        &wire_frame,        input,        &previous_for_diff,        &target,        repaint_window,        full_repaint,        terminal_scroll_bytes,    );    const wire_frame_bytes = wire_frame.written();    const document_append_range = movement.documentAppendWireRange(prefix_len);    const frame_movement_segments = FrameMovementSegments.fromPreparedMovement(prefix_len, movement.*);    const complete_scroll_attribution = try validateFrameScrollAttribution(        alloc,        input.previous,        target.cols,        target.rows,        wire_frame_bytes,        frame_movement_segments,        movement.scroll_rows,    );     const sink_result = input.sink.write_frame(input.sink.ctx, input.metrics, wire_frame_bytes);    const accepted_write = try acceptedFrameWrite(        alloc,        input.previous,        target.cols,        target.rows,        wire_frame_bytes,        sink_result,        document_append_range,        frame_movement_segments,        complete_scroll_attribution,    );    try movement.validateCompleteWrite(        accepted_write.accepted_bytes,        wire_frame_bytes.len,        accepted_write.scroll_attribution,    );    const scroll_commit = input.scroll_plan.commitWithExpectedRows(        accepted_write.applied_scroll_rows,        movement.scroll_rows.expected_scroll_rows,    );    switch (sink_result) {        .complete => {},        .partial => |partial| {            debug_trace.logf(                "frame_commit",                "wire_frame bytes={d} accepted_bytes={d} applied_scroll_rows={d} cleanup={s} err={s}",                .{ wire_frame_bytes.len, accepted_write.accepted_bytes, accepted_write.applied_scroll_rows, @tagName(CleanupState.none), @errorName(partial.err) },            );            return recoverPartialFrame(                input,                changed_cells,                full_repaint,                wire_frame_bytes,                accepted_write,                scroll_commit,            );        },    }     var fed_shadow = cloneAuthoritativeShadow(alloc, input.previous, target.cols, target.rows) catch |err| {        return shadowFeedFailedWithRepair(input, changed_cells, full_repaint, accepted_write.accepted_bytes, scroll_commit, accepted_write.scroll_attribution, accepted_write.document_append_committed, err);    };    var fed_shadow_initialized = true;    defer if (fed_shadow_initialized) fed_shadow.deinit();    if (consumeShadowTestFault(.normal_clone_feed)) {        return shadowFeedFailedWithRepair(            input,            changed_cells,            full_repaint,            accepted_write.accepted_bytes,            scroll_commit,            accepted_write.scroll_attribution,            accepted_write.document_append_committed,            error.TestShadowFeedFailure,        );    }    fed_shadow.feed(wire_frame_bytes) catch |err| {        return shadowFeedFailedWithRepair(input, changed_cells, full_repaint, accepted_write.accepted_bytes, scroll_commit, accepted_write.scroll_attribution, accepted_write.document_append_committed, err);

Lines 1–500 of 4061.