const std = @import("std");const command_output_runtime = @import("command_output_runtime.zig");const debug_trace = @import("../../core/shared/debug_trace.zig");const transcript_release = @import("../../core/output/transcript_release.zig");const build_checkpoint = @import("../render_engine/build_checkpoint.zig");const tool_group_projection = @import("tool_group_projection.zig");const render_engine = @import("../render_engine.zig");const user_message_card = @import("../assistant/user_message_card.zig");const ui_render = @import("../render.zig");const types = @import("../../core/shared/types.zig"); const Allocator = std.mem.Allocator;const transcript_blocks = render_engine.transcript_blocks;const viewport_selection = render_engine.viewport_selection; const FoldedCommandBlock = command_output_runtime.FoldedCommandBlock;const TranscriptBuffer = viewport_selection.TranscriptBuffer;const TranscriptRef = viewport_selection.TranscriptRef;const buildHardLineStarts = viewport_selection.buildHardLineStarts;const buildHardLineStartsInterruptible = viewport_selection.buildHardLineStartsInterruptible;const hardLineRefAt = viewport_selection.hardLineRefAt;const leadingWelcomeBoundary = transcript_blocks.leadingWelcomeBoundary;const leadingWelcomeCutLine = transcript_blocks.leadingWelcomeCutLine;const stripTrailingNewline = transcript_blocks.stripTrailingNewline;const tailVisibleBlockKind = transcript_blocks.tailVisibleBlockKind;const visualRowsForLine = transcript_blocks.visualRowsForLine; test { _ = tool_group_projection;} const FinalityNominationKind = enum { mutation_pin, tool_turn, assistant_tail }; const FinalityNomination = struct { entry_id: u32, kind: FinalityNominationKind, turn_id: u64 = 0,}; const ToolFinalityIdentity = struct { turn_id: u64, presentation_group_id: ?types.ToolPresentationGroupId,}; const ToolTurnNomination = struct { earliest_entry_id: u32, selected_entry_id: u32, selected_group_id: ?types.ToolPresentationGroupId,}; fn entryHiddenByActions( entry_actions: []const transcript_blocks.EntryRenderAction, index: usize,) bool { if (entry_actions.len == 0) return false; return entry_actions[index] == .hide;} /// Nominate the entries whose rendered start bytes bound the final flow/// prefix: the first entry carrying a live mutation pin, the first rendered/// entry of each tool turn, and a trailing assistant entry. Omitted and/// hidden entries contribute no flow bytes and are skipped.fn collectFinalityNominations( self: anytype, alloc: Allocator, omitted_entry_id: ?u32, entry_actions: []const transcript_blocks.EntryRenderAction,) !std.ArrayList(FinalityNomination) { var nominations: std.ArrayList(FinalityNomination) = .empty; errdefer nominations.deinit(alloc); var entry_tool_identities: std.AutoHashMapUnmanaged(u32, ToolFinalityIdentity) = .empty; defer entry_tool_identities.deinit(alloc); for (self.tool_details.items) |detail| { const identity: ToolFinalityIdentity = if (detail.presentation_group_id) |group| .{ .turn_id = group.turn_id, .presentation_group_id = group } else if (detail.lifecycle_id) |lifecycle| .{ .turn_id = lifecycle.turn_id, .presentation_group_id = null } else continue; try entry_tool_identities.put(alloc, detail.entry_id, identity); } var mutation_pin_entry_id: ?u32 = null; var turn_nominations: std.AutoHashMapUnmanaged(u64, ToolTurnNomination) = .empty; defer turn_nominations.deinit(alloc); for (self.entries.items, 0..) |entry, index| { const entry_id = entry.id(); if (omitted_entry_id == entry_id) continue; if (entryHiddenByActions(entry_actions, index)) continue; const tool_identity = if (entry == .raw_bytes and entry.raw_bytes.class == .tool_status) entry_tool_identities.get(entry_id) else null; if (mutation_pin_entry_id == null) { const pinned = switch (entry) { .raw_bytes => |raw| raw.lifecycle_pinned and tool_identity == null, .semantic_notice => |notice| notice.pending_replacement, else => false, }; if (pinned) mutation_pin_entry_id = entry_id; } if (tool_identity) |identity| { const result = try turn_nominations.getOrPut(alloc, identity.turn_id); if (!result.found_existing) { result.value_ptr.* = .{ .earliest_entry_id = entry_id, .selected_entry_id = entry_id, .selected_group_id = identity.presentation_group_id, }; continue; } const turn = result.value_ptr; if (turn.selected_group_id == null) continue; const group_id = identity.presentation_group_id orelse { turn.selected_entry_id = turn.earliest_entry_id; turn.selected_group_id = null; continue; }; const selected_group = turn.selected_group_id.?; if (group_id.anchor_step_id > selected_group.anchor_step_id) { turn.selected_entry_id = entry_id; turn.selected_group_id = group_id; } } } for (self.entries.items, 0..) |entry, index| { const entry_id = entry.id(); if (omitted_entry_id == entry_id) continue; if (entryHiddenByActions(entry_actions, index)) continue; if (mutation_pin_entry_id == entry_id) { try nominations.append(alloc, .{ .entry_id = entry_id, .kind = .mutation_pin, }); } if (entry != .raw_bytes or entry.raw_bytes.class != .tool_status) continue; const identity = entry_tool_identities.get(entry_id) orelse continue; const turn = turn_nominations.get(identity.turn_id).?; if (turn.selected_entry_id != entry_id) continue; try nominations.append(alloc, .{ .entry_id = entry_id, .kind = .tool_turn, .turn_id = identity.turn_id, }); } if (self.entries.items.len > 0) { const tail = self.entries.items[self.entries.items.len - 1]; if (tail == .assistant_turn and omitted_entry_id != tail.id() and !entryHiddenByActions(entry_actions, self.entries.items.len - 1)) { try nominations.append(alloc, .{ .entry_id = tail.id(), .kind = .assistant_tail, }); } } return nominations;} pub const TranscriptPreparationSource = struct { bytes: []u8, folded_summary_indices: []usize, line_provenance: []const transcript_blocks.LineProvenance = &.{}, preview: render_engine.frame_layout.TranscriptFlowPreview, tail_kind: ?transcript_blocks.TranscriptBlockKind, tracked_entry_id: ?u32, tracked_entry_start_line: ?usize, replaceable_last_line: bool, replaceable_start: usize, replaceable_row: u16, welcome_cut_line: ?usize, welcome_boundary: ?transcript_blocks.LeadingWelcomeBoundary, cols: u16, recorded_entries_authoritative: bool = false, cache_origin_untrimmed: bool = false, hard_line_starts: []usize = &.{}, hard_lines_end_with_newline: bool = false, transcript_visible_lines: []viewport_selection.VisibleTranscriptLine = &.{}, transcript_line_visual_rows: []u16 = &.{}, transcript_visual_row_offsets: []u32 = &.{}, finality: transcript_release.Candidates = .{}, pub fn deinit(self: *TranscriptPreparationSource, alloc: Allocator) void { if (self.bytes.len > 0) alloc.free(self.bytes); if (self.folded_summary_indices.len > 0) alloc.free(self.folded_summary_indices); if (self.line_provenance.len > 0) alloc.free(self.line_provenance); if (self.hard_line_starts.len > 0) alloc.free(self.hard_line_starts); if (self.transcript_visible_lines.len > 0) alloc.free(self.transcript_visible_lines); if (self.transcript_line_visual_rows.len > 0) alloc.free(self.transcript_line_visual_rows); if (self.transcript_visual_row_offsets.len > 0) alloc.free(self.transcript_visual_row_offsets); self.finality.deinit(alloc); self.* = undefined; } pub fn ensureLineIndex(self: *TranscriptPreparationSource, alloc: Allocator) !void { return self.ensureLineIndexInterruptible(alloc, null) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, }; } pub fn ensureLineIndexInterruptible( self: *TranscriptPreparationSource, alloc: Allocator, checkpoint: ?*build_checkpoint.BuildCheckpoint, ) !void { if (self.bytes.len == 0) return build_checkpoint.poll(checkpoint); if (self.hard_line_starts.len > 0) return; const hard_lines = try buildHardLineStartsInterruptible(alloc, self.bytes, checkpoint); errdefer hard_lines.deinit(alloc); const line_visual_rows = try alloc.alloc(u16, hard_lines.len()); errdefer alloc.free(line_visual_rows); const visible_lines = try alloc.alloc(viewport_selection.VisibleTranscriptLine, hard_lines.len()); errdefer alloc.free(visible_lines); const visual_row_offsets = try alloc.alloc(u32, hard_lines.len() + 1); errdefer alloc.free(visual_row_offsets); visual_row_offsets[0] = 0; const transcript = TranscriptBuffer{ .bytes = self.bytes }; for (line_visual_rows, visible_lines, 0..) |*rows, *line, index| { const ref = hardLineRefAt(hard_lines, self.bytes.len, index); const bytes = (TranscriptRef{ .ref = ref }).resolve(transcript); try build_checkpoint.consume(checkpoint, bytes.len); rows.* = visualRowsForLine(bytes, self.cols); line.* = viewport_selection.visibleFromTranscript(ref); visual_row_offsets[index + 1] = visual_row_offsets[index] + rows.*; } self.hard_line_starts = hard_lines.starts; self.hard_lines_end_with_newline = hard_lines.ends_with_newline; self.transcript_visible_lines = visible_lines; self.transcript_line_visual_rows = line_visual_rows; self.transcript_visual_row_offsets = visual_row_offsets; } pub fn clone(self: *const TranscriptPreparationSource, alloc: Allocator) !TranscriptPreparationSource { const bytes = try alloc.dupe(u8, self.bytes); errdefer alloc.free(bytes); const folded_summary_indices = try alloc.dupe(usize, self.folded_summary_indices); errdefer alloc.free(folded_summary_indices); const line_provenance = try alloc.dupe( transcript_blocks.LineProvenance, self.line_provenance, ); errdefer alloc.free(line_provenance); const hard_line_starts = try alloc.dupe(usize, self.hard_line_starts); errdefer alloc.free(hard_line_starts); const transcript_visible_lines = try alloc.dupe( viewport_selection.VisibleTranscriptLine, self.transcript_visible_lines, ); errdefer alloc.free(transcript_visible_lines); const transcript_line_visual_rows = try alloc.dupe(u16, self.transcript_line_visual_rows); errdefer alloc.free(transcript_line_visual_rows); const transcript_visual_row_offsets = try alloc.dupe(u32, self.transcript_visual_row_offsets); errdefer alloc.free(transcript_visual_row_offsets); var finality = try self.finality.clone(alloc); errdefer finality.deinit(alloc); return .{ .bytes = bytes, .folded_summary_indices = folded_summary_indices, .line_provenance = line_provenance, .preview = self.preview, .tail_kind = self.tail_kind, .tracked_entry_id = self.tracked_entry_id, .tracked_entry_start_line = self.tracked_entry_start_line, .replaceable_last_line = self.replaceable_last_line, .replaceable_start = self.replaceable_start, .replaceable_row = self.replaceable_row, .welcome_cut_line = self.welcome_cut_line, .welcome_boundary = self.welcome_boundary, .cols = self.cols, .recorded_entries_authoritative = self.recorded_entries_authoritative, .cache_origin_untrimmed = self.cache_origin_untrimmed, .hard_line_starts = hard_line_starts, .hard_lines_end_with_newline = self.hard_lines_end_with_newline, .transcript_visible_lines = transcript_visible_lines, .transcript_line_visual_rows = transcript_line_visual_rows, .transcript_visual_row_offsets = transcript_visual_row_offsets, .finality = finality, }; }}; pub fn prepareTranscriptSource( self: anytype, alloc: Allocator, tracked_entry_id: ?u32,) !TranscriptPreparationSource { return prepareTranscriptSourceInternal(self, alloc, tracked_entry_id, null, null, null) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, };} pub fn prepareTranscriptSourceWithFocusedEntry( self: anytype, alloc: Allocator, focused_entry_id: u32,) !TranscriptPreparationSource { return prepareTranscriptSourceInternal(self, alloc, focused_entry_id, focused_entry_id, null, null) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, };} pub fn prepareTranscriptSourceOmittingEntry( self: anytype, alloc: Allocator, omitted_entry_id: u32,) !TranscriptPreparationSource { return prepareTranscriptSourceInternal(self, alloc, null, null, omitted_entry_id, null) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, };} pub fn prepareTranscriptSourceInterruptible( self: anytype, alloc: Allocator, tracked_entry_id: ?u32, focused_entry_id: ?u32, omitted_entry_id: ?u32, checkpoint: ?*build_checkpoint.BuildCheckpoint,) !TranscriptPreparationSource { return prepareTranscriptSourceInternal( self, alloc, tracked_entry_id, focused_entry_id, omitted_entry_id, checkpoint, );} pub fn renderCompactTranscriptBytes( self: anytype, alloc: Allocator,) ![]u8 { var command_overrides = try buildCommandOutputOverrides(self, alloc); defer command_overrides.deinit(alloc); const styles = self.command_output_render.styles; if (self.maxxing_mode == .legacy) { const entry_actions = try buildCommandOutputActions( alloc, &command_overrides, self.entries.items.len, ); defer if (entry_actions.len > 0) alloc.free(entry_actions); return transcript_blocks.renderEntriesWithProjectionToBytes( alloc, self.entries.items, self.layout.cols, styles, entry_actions, self.maxxing_mode, ); } var projection = try buildMinimalTranscriptProjection( self, alloc, &command_overrides, null, ); defer projection.deinit(alloc); return transcript_blocks.renderEntriesWithProjectionToBytes( alloc, self.entries.items, self.layout.cols, styles, projection.entry_actions.items, self.maxxing_mode, );} /// Takes ownership of a bounded full-transcript visual window and prepares it/// for the ordinary transcript surface painter. Ctrl-O uses this only after/// the full document source has selected its current visual window.pub fn prepareFullTranscriptViewportSource( self: anytype, alloc: Allocator, bytes: []u8,) !TranscriptPreparationSource { return prepareFullTranscriptViewportSourceInterruptible(self, alloc, bytes, null) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, };} pub fn prepareFullTranscriptViewportSourceInterruptible( self: anytype, alloc: Allocator, bytes: []u8, checkpoint: ?*build_checkpoint.BuildCheckpoint,) !TranscriptPreparationSource { errdefer alloc.free(bytes); const line_provenance = if (observationEnabled(self, alloc)) try unattributedLineProvenance(alloc, bytes) else &.{}; errdefer if (line_provenance.len > 0) alloc.free(line_provenance); const tail_kind = tailVisibleBlockKind(self.entries.items); const preview = try transcriptFlowPreviewFromSourceInterruptible( self, alloc, bytes, &.{}, 0, false, tail_kind, checkpoint, ); return .{ .bytes = bytes, .folded_summary_indices = try alloc.alloc(usize, 0), .line_provenance = line_provenance, .preview = preview, .tail_kind = tail_kind, .tracked_entry_id = null, .tracked_entry_start_line = null, .replaceable_last_line = false, .replaceable_start = 0, .replaceable_row = self.replaceable_row, .welcome_cut_line = null, .welcome_boundary = null, .cols = self.layout.cols, };} fn prepareTranscriptSourceInternal( self: anytype, alloc: Allocator, tracked_entry_id: ?u32, focused_entry_id: ?u32, omitted_entry_id: ?u32, checkpoint: ?*build_checkpoint.BuildCheckpoint,) !TranscriptPreparationSource { var bytes: []u8 = &.{}; errdefer if (bytes.len > 0) alloc.free(bytes); var folded_summary_indices: []usize = &.{}; errdefer if (folded_summary_indices.len > 0) alloc.free(folded_summary_indices); var line_provenance: []const transcript_blocks.LineProvenance = &.{}; errdefer if (line_provenance.len > 0) alloc.free(line_provenance); var trailing_boundary_blank_rows: u16 = 0; var tracked_entry_start_line: ?usize = null; var replaceable_entry_start_byte: ?usize = null; var rendered_from_entries = false; var command_overrides = try buildCommandOutputOverridesInterruptible(self, alloc, checkpoint); defer command_overrides.deinit(alloc); var minimal_projection: ?tool_group_projection.Projection = null; defer if (minimal_projection) |*projection| projection.deinit(alloc); if (self.maxxing_mode == .minimal and self.entries.items.len > 0 and self.layout.cols > 0) { minimal_projection = try buildMinimalTranscriptProjectionInterruptible( self, alloc, &command_overrides, focused_entry_id, checkpoint, ); } const aligned_actions = if (minimal_projection == null) try buildCommandOutputActions( alloc, &command_overrides, self.entries.items.len, ) else &.{}; defer if (aligned_actions.len > 0) alloc.free(aligned_actions); const entry_actions = if (minimal_projection) |*projection| projection.entry_actions.items else aligned_actions; var finality: transcript_release.Candidates = .{}; errdefer finality.deinit(alloc); if (self.entries.items.len > 0 and self.layout.cols > 0) { rendered_from_entries = true; const capture_provenance = observationEnabled(self, alloc) or self.command_output_blocks.items.len > 0; const replaceable_entry_id: ?u32 = if (self.replaceable_last_line and self.entries.items[self.entries.items.len - 1] == .raw_bytes) self.entries.items[self.entries.items.len - 1].raw_bytes.id else null; var finality_nominations = try collectFinalityNominations( self, alloc, omitted_entry_id, entry_actions, ); defer finality_nominations.deinit(alloc); const finality_entry_ids = try alloc.alloc(u32, finality_nominations.items.len);Lines 1–500 of 1112. Load more
const std = @import("std"); const command_output_runtime = @import("command_output_runtime.zig"); const debug_trace = @import("../../core/shared/debug_trace.zig"); const transcript_release = @import("../../core/output/transcript_release.zig"); const build_checkpoint = @import("../render_engine/build_checkpoint.zig"); const tool_group_projection = @import("tool_group_projection.zig"); const render_engine = @import("../render_engine.zig"); const user_message_card = @import("../assistant/user_message_card.zig"); const ui_render = @import("../render.zig"); const types = @import("../../core/shared/types.zig"); const Allocator = std.mem.Allocator; const transcript_blocks = render_engine.transcript_blocks; const viewport_selection = render_engine.viewport_selection; const FoldedCommandBlock = command_output_runtime.FoldedCommandBlock; const TranscriptBuffer = viewport_selection.TranscriptBuffer; const TranscriptRef = viewport_selection.TranscriptRef; const buildHardLineStarts = viewport_selection.buildHardLineStarts; const buildHardLineStartsInterruptible = viewport_selection.buildHardLineStartsInterruptible; const hardLineRefAt = viewport_selection.hardLineRefAt; const leadingWelcomeBoundary = transcript_blocks.leadingWelcomeBoundary; const leadingWelcomeCutLine = transcript_blocks.leadingWelcomeCutLine; const stripTrailingNewline = transcript_blocks.stripTrailingNewline; const tailVisibleBlockKind = transcript_blocks.tailVisibleBlockKind; const visualRowsForLine = transcript_blocks.visualRowsForLine; test { _ = tool_group_projection; } const FinalityNominationKind = enum { mutation_pin, tool_turn, assistant_tail }; const FinalityNomination = struct { entry_id: u32, kind: FinalityNominationKind, turn_id: u64 = 0, }; const ToolFinalityIdentity = struct { turn_id: u64, presentation_group_id: ?types.ToolPresentationGroupId, }; const ToolTurnNomination = struct { earliest_entry_id: u32, selected_entry_id: u32, selected_group_id: ?types.ToolPresentationGroupId, }; fn entryHiddenByActions( entry_actions: []const transcript_blocks.EntryRenderAction, index: usize, ) bool { if (entry_actions.len == 0) return false; return entry_actions[index] == .hide; } /// Nominate the entries whose rendered start bytes bound the final flow /// prefix: the first entry carrying a live mutation pin, the first rendered /// entry of each tool turn, and a trailing assistant entry. Omitted and /// hidden entries contribute no flow bytes and are skipped. fn collectFinalityNominations( self: anytype, alloc: Allocator, omitted_entry_id: ?u32, entry_actions: []const transcript_blocks.EntryRenderAction, ) !std.ArrayList(FinalityNomination) { var nominations: std.ArrayList(FinalityNomination) = .empty; errdefer nominations.deinit(alloc); var entry_tool_identities: std.AutoHashMapUnmanaged(u32, ToolFinalityIdentity) = .empty; defer entry_tool_identities.deinit(alloc); for (self.tool_details.items) |detail| { const identity: ToolFinalityIdentity = if (detail.presentation_group_id) |group| .{ .turn_id = group.turn_id, .presentation_group_id = group } else if (detail.lifecycle_id) |lifecycle| .{ .turn_id = lifecycle.turn_id, .presentation_group_id = null } else continue; try entry_tool_identities.put(alloc, detail.entry_id, identity); } var mutation_pin_entry_id: ?u32 = null; var turn_nominations: std.AutoHashMapUnmanaged(u64, ToolTurnNomination) = .empty; defer turn_nominations.deinit(alloc); for (self.entries.items, 0..) |entry, index| { const entry_id = entry.id(); if (omitted_entry_id == entry_id) continue; if (entryHiddenByActions(entry_actions, index)) continue; const tool_identity = if (entry == .raw_bytes and entry.raw_bytes.class == .tool_status) entry_tool_identities.get(entry_id) else null; if (mutation_pin_entry_id == null) { const pinned = switch (entry) { .raw_bytes => |raw| raw.lifecycle_pinned and tool_identity == null, .semantic_notice => |notice| notice.pending_replacement, else => false, }; if (pinned) mutation_pin_entry_id = entry_id; } if (tool_identity) |identity| { const result = try turn_nominations.getOrPut(alloc, identity.turn_id); if (!result.found_existing) { result.value_ptr.* = .{ .earliest_entry_id = entry_id, .selected_entry_id = entry_id, .selected_group_id = identity.presentation_group_id, }; continue; } const turn = result.value_ptr; if (turn.selected_group_id == null) continue; const group_id = identity.presentation_group_id orelse { turn.selected_entry_id = turn.earliest_entry_id; turn.selected_group_id = null; continue; }; const selected_group = turn.selected_group_id.?; if (group_id.anchor_step_id > selected_group.anchor_step_id) { turn.selected_entry_id = entry_id; turn.selected_group_id = group_id; } } } for (self.entries.items, 0..) |entry, index| { const entry_id = entry.id(); if (omitted_entry_id == entry_id) continue; if (entryHiddenByActions(entry_actions, index)) continue; if (mutation_pin_entry_id == entry_id) { try nominations.append(alloc, .{ .entry_id = entry_id, .kind = .mutation_pin, }); } if (entry != .raw_bytes or entry.raw_bytes.class != .tool_status) continue; const identity = entry_tool_identities.get(entry_id) orelse continue; const turn = turn_nominations.get(identity.turn_id).?; if (turn.selected_entry_id != entry_id) continue; try nominations.append(alloc, .{ .entry_id = entry_id, .kind = .tool_turn, .turn_id = identity.turn_id, }); } if (self.entries.items.len > 0) { const tail = self.entries.items[self.entries.items.len - 1]; if (tail == .assistant_turn and omitted_entry_id != tail.id() and !entryHiddenByActions(entry_actions, self.entries.items.len - 1)) { try nominations.append(alloc, .{ .entry_id = tail.id(), .kind = .assistant_tail, }); } } return nominations; } pub const TranscriptPreparationSource = struct { bytes: []u8, folded_summary_indices: []usize, line_provenance: []const transcript_blocks.LineProvenance = &.{}, preview: render_engine.frame_layout.TranscriptFlowPreview, tail_kind: ?transcript_blocks.TranscriptBlockKind, tracked_entry_id: ?u32, tracked_entry_start_line: ?usize, replaceable_last_line: bool, replaceable_start: usize, replaceable_row: u16, welcome_cut_line: ?usize, welcome_boundary: ?transcript_blocks.LeadingWelcomeBoundary, cols: u16, recorded_entries_authoritative: bool = false, cache_origin_untrimmed: bool = false, hard_line_starts: []usize = &.{}, hard_lines_end_with_newline: bool = false, transcript_visible_lines: []viewport_selection.VisibleTranscriptLine = &.{}, transcript_line_visual_rows: []u16 = &.{}, transcript_visual_row_offsets: []u32 = &.{}, finality: transcript_release.Candidates = .{}, pub fn deinit(self: *TranscriptPreparationSource, alloc: Allocator) void { if (self.bytes.len > 0) alloc.free(self.bytes); if (self.folded_summary_indices.len > 0) alloc.free(self.folded_summary_indices); if (self.line_provenance.len > 0) alloc.free(self.line_provenance); if (self.hard_line_starts.len > 0) alloc.free(self.hard_line_starts); if (self.transcript_visible_lines.len > 0) alloc.free(self.transcript_visible_lines); if (self.transcript_line_visual_rows.len > 0) alloc.free(self.transcript_line_visual_rows); if (self.transcript_visual_row_offsets.len > 0) alloc.free(self.transcript_visual_row_offsets); self.finality.deinit(alloc); self.* = undefined; } pub fn ensureLineIndex(self: *TranscriptPreparationSource, alloc: Allocator) !void { return self.ensureLineIndexInterruptible(alloc, null) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, }; } pub fn ensureLineIndexInterruptible( self: *TranscriptPreparationSource, alloc: Allocator, checkpoint: ?*build_checkpoint.BuildCheckpoint, ) !void { if (self.bytes.len == 0) return build_checkpoint.poll(checkpoint); if (self.hard_line_starts.len > 0) return; const hard_lines = try buildHardLineStartsInterruptible(alloc, self.bytes, checkpoint); errdefer hard_lines.deinit(alloc); const line_visual_rows = try alloc.alloc(u16, hard_lines.len()); errdefer alloc.free(line_visual_rows); const visible_lines = try alloc.alloc(viewport_selection.VisibleTranscriptLine, hard_lines.len()); errdefer alloc.free(visible_lines); const visual_row_offsets = try alloc.alloc(u32, hard_lines.len() + 1); errdefer alloc.free(visual_row_offsets); visual_row_offsets[0] = 0; const transcript = TranscriptBuffer{ .bytes = self.bytes }; for (line_visual_rows, visible_lines, 0..) |*rows, *line, index| { const ref = hardLineRefAt(hard_lines, self.bytes.len, index); const bytes = (TranscriptRef{ .ref = ref }).resolve(transcript); try build_checkpoint.consume(checkpoint, bytes.len); rows.* = visualRowsForLine(bytes, self.cols); line.* = viewport_selection.visibleFromTranscript(ref); visual_row_offsets[index + 1] = visual_row_offsets[index] + rows.*; } self.hard_line_starts = hard_lines.starts; self.hard_lines_end_with_newline = hard_lines.ends_with_newline; self.transcript_visible_lines = visible_lines; self.transcript_line_visual_rows = line_visual_rows; self.transcript_visual_row_offsets = visual_row_offsets; } pub fn clone(self: *const TranscriptPreparationSource, alloc: Allocator) !TranscriptPreparationSource { const bytes = try alloc.dupe(u8, self.bytes); errdefer alloc.free(bytes); const folded_summary_indices = try alloc.dupe(usize, self.folded_summary_indices); errdefer alloc.free(folded_summary_indices); const line_provenance = try alloc.dupe( transcript_blocks.LineProvenance, self.line_provenance, ); errdefer alloc.free(line_provenance); const hard_line_starts = try alloc.dupe(usize, self.hard_line_starts); errdefer alloc.free(hard_line_starts); const transcript_visible_lines = try alloc.dupe( viewport_selection.VisibleTranscriptLine, self.transcript_visible_lines, ); errdefer alloc.free(transcript_visible_lines); const transcript_line_visual_rows = try alloc.dupe(u16, self.transcript_line_visual_rows); errdefer alloc.free(transcript_line_visual_rows); const transcript_visual_row_offsets = try alloc.dupe(u32, self.transcript_visual_row_offsets); errdefer alloc.free(transcript_visual_row_offsets); var finality = try self.finality.clone(alloc); errdefer finality.deinit(alloc); return .{ .bytes = bytes, .folded_summary_indices = folded_summary_indices, .line_provenance = line_provenance, .preview = self.preview, .tail_kind = self.tail_kind, .tracked_entry_id = self.tracked_entry_id, .tracked_entry_start_line = self.tracked_entry_start_line, .replaceable_last_line = self.replaceable_last_line, .replaceable_start = self.replaceable_start, .replaceable_row = self.replaceable_row, .welcome_cut_line = self.welcome_cut_line, .welcome_boundary = self.welcome_boundary, .cols = self.cols, .recorded_entries_authoritative = self.recorded_entries_authoritative, .cache_origin_untrimmed = self.cache_origin_untrimmed, .hard_line_starts = hard_line_starts, .hard_lines_end_with_newline = self.hard_lines_end_with_newline, .transcript_visible_lines = transcript_visible_lines, .transcript_line_visual_rows = transcript_line_visual_rows, .transcript_visual_row_offsets = transcript_visual_row_offsets, .finality = finality, }; } }; pub fn prepareTranscriptSource( self: anytype, alloc: Allocator, tracked_entry_id: ?u32, ) !TranscriptPreparationSource { return prepareTranscriptSourceInternal(self, alloc, tracked_entry_id, null, null, null) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, }; } pub fn prepareTranscriptSourceWithFocusedEntry( self: anytype, alloc: Allocator, focused_entry_id: u32, ) !TranscriptPreparationSource { return prepareTranscriptSourceInternal(self, alloc, focused_entry_id, focused_entry_id, null, null) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, }; } pub fn prepareTranscriptSourceOmittingEntry( self: anytype, alloc: Allocator, omitted_entry_id: u32, ) !TranscriptPreparationSource { return prepareTranscriptSourceInternal(self, alloc, null, null, omitted_entry_id, null) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, }; } pub fn prepareTranscriptSourceInterruptible( self: anytype, alloc: Allocator, tracked_entry_id: ?u32, focused_entry_id: ?u32, omitted_entry_id: ?u32, checkpoint: ?*build_checkpoint.BuildCheckpoint, ) !TranscriptPreparationSource { return prepareTranscriptSourceInternal( self, alloc, tracked_entry_id, focused_entry_id, omitted_entry_id, checkpoint, ); } pub fn renderCompactTranscriptBytes( self: anytype, alloc: Allocator, ) ![]u8 { var command_overrides = try buildCommandOutputOverrides(self, alloc); defer command_overrides.deinit(alloc); const styles = self.command_output_render.styles; if (self.maxxing_mode == .legacy) { const entry_actions = try buildCommandOutputActions( alloc, &command_overrides, self.entries.items.len, ); defer if (entry_actions.len > 0) alloc.free(entry_actions); return transcript_blocks.renderEntriesWithProjectionToBytes( alloc, self.entries.items, self.layout.cols, styles, entry_actions, self.maxxing_mode, ); } var projection = try buildMinimalTranscriptProjection( self, alloc, &command_overrides, null, ); defer projection.deinit(alloc); return transcript_blocks.renderEntriesWithProjectionToBytes( alloc, self.entries.items, self.layout.cols, styles, projection.entry_actions.items, self.maxxing_mode, ); } /// Takes ownership of a bounded full-transcript visual window and prepares it /// for the ordinary transcript surface painter. Ctrl-O uses this only after /// the full document source has selected its current visual window. pub fn prepareFullTranscriptViewportSource( self: anytype, alloc: Allocator, bytes: []u8, ) !TranscriptPreparationSource { return prepareFullTranscriptViewportSourceInterruptible(self, alloc, bytes, null) catch |err| switch (err) { error.InputPending => unreachable, else => |other| return other, }; } pub fn prepareFullTranscriptViewportSourceInterruptible( self: anytype, alloc: Allocator, bytes: []u8, checkpoint: ?*build_checkpoint.BuildCheckpoint, ) !TranscriptPreparationSource { errdefer alloc.free(bytes); const line_provenance = if (observationEnabled(self, alloc)) try unattributedLineProvenance(alloc, bytes) else &.{}; errdefer if (line_provenance.len > 0) alloc.free(line_provenance); const tail_kind = tailVisibleBlockKind(self.entries.items); const preview = try transcriptFlowPreviewFromSourceInterruptible( self, alloc, bytes, &.{}, 0, false, tail_kind, checkpoint, ); return .{ .bytes = bytes, .folded_summary_indices = try alloc.alloc(usize, 0), .line_provenance = line_provenance, .preview = preview, .tail_kind = tail_kind, .tracked_entry_id = null, .tracked_entry_start_line = null, .replaceable_last_line = false, .replaceable_start = 0, .replaceable_row = self.replaceable_row, .welcome_cut_line = null, .welcome_boundary = null, .cols = self.layout.cols, }; } fn prepareTranscriptSourceInternal( self: anytype, alloc: Allocator, tracked_entry_id: ?u32, focused_entry_id: ?u32, omitted_entry_id: ?u32, checkpoint: ?*build_checkpoint.BuildCheckpoint, ) !TranscriptPreparationSource { var bytes: []u8 = &.{}; errdefer if (bytes.len > 0) alloc.free(bytes); var folded_summary_indices: []usize = &.{}; errdefer if (folded_summary_indices.len > 0) alloc.free(folded_summary_indices); var line_provenance: []const transcript_blocks.LineProvenance = &.{}; errdefer if (line_provenance.len > 0) alloc.free(line_provenance); var trailing_boundary_blank_rows: u16 = 0; var tracked_entry_start_line: ?usize = null; var replaceable_entry_start_byte: ?usize = null; var rendered_from_entries = false; var command_overrides = try buildCommandOutputOverridesInterruptible(self, alloc, checkpoint); defer command_overrides.deinit(alloc); var minimal_projection: ?tool_group_projection.Projection = null; defer if (minimal_projection) |*projection| projection.deinit(alloc); if (self.maxxing_mode == .minimal and self.entries.items.len > 0 and self.layout.cols > 0) { minimal_projection = try buildMinimalTranscriptProjectionInterruptible( self, alloc, &command_overrides, focused_entry_id, checkpoint, ); } const aligned_actions = if (minimal_projection == null) try buildCommandOutputActions( alloc, &command_overrides, self.entries.items.len, ) else &.{}; defer if (aligned_actions.len > 0) alloc.free(aligned_actions); const entry_actions = if (minimal_projection) |*projection| projection.entry_actions.items else aligned_actions; var finality: transcript_release.Candidates = .{}; errdefer finality.deinit(alloc); if (self.entries.items.len > 0 and self.layout.cols > 0) { rendered_from_entries = true; const capture_provenance = observationEnabled(self, alloc) or self.command_output_blocks.items.len > 0; const replaceable_entry_id: ?u32 = if (self.replaceable_last_line and self.entries.items[self.entries.items.len - 1] == .raw_bytes) self.entries.items[self.entries.items.len - 1].raw_bytes.id else null; var finality_nominations = try collectFinalityNominations( self, alloc, omitted_entry_id, entry_actions, ); defer finality_nominations.deinit(alloc); const finality_entry_ids = try alloc.alloc(u32, finality_nominations.items.len);