const std = @import("std");const question_prompt = @import("../agent/question_prompt.zig");const app_auth_runtime = @import("app_auth_runtime.zig");const app_permission_runtime = @import("app_permission_runtime.zig");const app_session_runtime = @import("app_session_runtime.zig");const app_workspace_runtime = @import("app_workspace_runtime.zig");const app_commands = @import("app_commands.zig");const app_worker_runtime = @import("app_worker_runtime.zig");const app_render_runtime = @import("app_render_runtime.zig");const auth_runtime = @import("../auth/auth_runtime.zig");const host = @import("../hosts/host.zig");const runtime_profile = @import("../hosts/runtime_profile.zig");const composer_insertion = @import("../input/composer_insertion.zig");const gesture_state = @import("../input/gesture_state.zig");const horizontal_navigation = @import("../input/horizontal_navigation.zig");const input_action = @import("../input/input_action.zig");const transcript_presentation = @import("../output/transcript_presentation.zig");const core_input_runtime = @import("../input/runtime.zig");const input_limit_rejection = @import("../input/input_limit_rejection.zig");const input_reset = @import("../input/input_reset.zig");const picker_state = @import("../input/picker_state.zig");const paste_framing = @import("../input/paste_framing.zig");const text_scalar = @import("../input/text_scalar.zig");const io_mod = @import("../shared/io.zig");const debug_trace = @import("../shared/debug_trace.zig");const image_attachments = @import("../images/image_attachments.zig");const image_commands = @import("../images/image_commands.zig");const model_capabilities = @import("../config/model_capabilities.zig");const model_cache_runtime = @import("model_cache_runtime.zig");const permission_request = @import("../permissions/permission_request.zig");const approval_decision = @import("../permissions/approval_decision.zig");const permissions = @import("../permissions/permissions.zig");const session_commands = @import("../session/session_commands.zig");const session_catalog = @import("../session/session_catalog.zig");const session_runtime = @import("../session/session.zig");const session_store = @import("../session/session_store.zig");const usage_report = @import("../session/usage_report.zig");const skill_runtime = @import("../skills/skill_runtime.zig");const file_index = @import("../workspace/file_index.zig");const command_specs = @import("../slash_commands/command_specs.zig");const types = @import("../shared/types.zig");const subagent_input = @import("../subagent/input_action.zig");const worker_runtime = @import("../agent/worker_runtime.zig");const auto_upgrade = @import("../upgrade/auto_upgrade.zig");const upgrade_helpers = @import("../upgrade/upgrade_helpers.zig");const test_ui_input = @import("../../ui/input/runtime.zig");const visual_layout = @import("../../ui/input/visual_layout.zig");const approval_ui = @import("../../ui/footer/approval_ui.zig");const interaction_state = @import("../../ui/footer/interaction_state.zig");const approval_prompt = @import("../permissions/approval_prompt.zig");const picker_presentation = @import("../../ui/footer/picker_presentation.zig");const paste_blocks = @import("../input/pasted_blocks.zig");const registered_entities = @import("../input/registered_entities.zig");const prompt_history_runtime = @import("prompt_history_runtime.zig");const prompt_history_store = @import("../session/prompt_history_store.zig");const shell_runtime = @import("../../ui/shell_runtime.zig");const render_request = @import("../../ui/render_request.zig");const transcript_runtime = @import("../../ui/transcript/runtime.zig");const input_interrupt_runtime = @import("input_interrupt_runtime.zig");const input_queue_runtime = @import("input_queue_runtime.zig");const input_history_runtime = @import("input_history_runtime.zig");const input_subagent_runtime = @import("input_subagent_runtime.zig");const input_completion_runtime = @import("input_completion_runtime.zig");const input_paste_runtime = @import("input_paste_runtime.zig");const input_submit_runtime = @import("input_submit_runtime.zig");const input_approval_runtime = @import("input_approval_runtime.zig");const input_question_runtime = @import("input_question_runtime.zig");const input_full_transcript_runtime = @import("input_full_transcript_runtime.zig");const input_selection_runtime = @import("input_selection_runtime.zig");const input_limit_feedback = @import("input_limit_feedback.zig");const app_upgrade_runtime = @import("app_upgrade_runtime.zig"); const ModelPickerStage = picker_state.ModelPickerStage;const ToolPermissionDecision = types.ToolPermissionDecision; pub const file_picker_completion_cap = input_completion_runtime.file_picker_completion_cap;const ctrl_g_upgrade_byte: u8 = 7;const ctrl_x_manager_byte: u8 = 24; fn classifyResumeFailure(err: anyerror) session_catalog.ResumeFailure { return switch (err) { error.SessionBusy => .open_elsewhere, error.SessionAuthorityBoundaryUnavailable, error.SessionCommitBoundaryUnavailable, => .being_updated, else => .unavailable, };} const ExplicitModelSelection = struct { model: []const u8, effort: types.ReasoningEffort, fast_mode: bool, has_fast_mode_token: bool = false,}; const ExplicitModelSelectionParse = union(enum) { none, invalid, selection: ExplicitModelSelection,}; fn shortcutMayMutateQueuedDraft(action: input_action.ShortcutAction) bool { return switch (action) { .move, .select_all, .copy_selection, .redraw, => false, .cut_selection, .undo, .redo, .history_previous, .history_next, .delete_backward, .delete_forward, .delete_word_left, .delete_whitespace_word_left, .delete_word_right, .delete_to_line_start, .delete_to_line_end, .yank, .insert_newline, => true, };} fn shortcutDeletesQueuedDraft(action: input_action.ShortcutAction) bool { return switch (action) { .delete_backward, .delete_forward, .delete_word_left, .delete_whitespace_word_left, .delete_word_right, .delete_to_line_start, .delete_to_line_end, => true, else => false, };} fn parseExplicitModelSelection(input: []const u8) ExplicitModelSelectionParse { const trimmed = std.mem.trim(u8, input, " \t\r\n"); if (!std.ascii.startsWithIgnoreCase(trimmed, "/model")) return .none; if (trimmed.len == "/model".len) return .none; if (trimmed["/model".len] != ' ' and trimmed["/model".len] != '\t') return .none; var tokens: [4][]const u8 = undefined; var token_count: usize = 0; var iterator = std.mem.tokenizeAny(u8, trimmed["/model".len..], " \t\r\n"); while (iterator.next()) |token| { if (token_count == tokens.len) return .invalid; tokens[token_count] = token; token_count += 1; } if (token_count < 2) return .none; const effort = types.ReasoningEffort.parse(tokens[1]) orelse return .none; if (token_count == 2) { return .{ .selection = .{ .model = tokens[0], .effort = effort, .fast_mode = false, .has_fast_mode_token = false, } }; } if (token_count != 3) return .invalid; const fast_mode = if (std.ascii.eqlIgnoreCase(tokens[2], "fast")) true else if (std.ascii.eqlIgnoreCase(tokens[2], "normal")) false else return .invalid; return .{ .selection = .{ .model = tokens[0], .effort = effort, .fast_mode = fast_mode, .has_fast_mode_token = true, } };} fn validateExplicitModelSelection(selection: ExplicitModelSelection, capabilities: model_capabilities.Capabilities) ExplicitModelSelectionParse { if (!model_capabilities.reasoningEffortSupported(capabilities, selection.effort)) return .invalid; if (capabilities.supports_fast_mode != selection.has_fast_mode_token) return .invalid; return .{ .selection = selection };} pub fn Runtime(comptime App: type) type { return struct { const history_rt = input_history_runtime.HistoryRuntime(App); const subagent_rt = input_subagent_runtime.SubagentRuntime(App); const completion_rt = input_completion_runtime.CompletionRuntime(App); const paste_rt = input_paste_runtime.PasteEditRuntime(App); const submit_rt = input_submit_runtime.SubmitRuntime(App); const approval_rt = input_approval_runtime.ApprovalRuntime(App); const question_rt = input_question_runtime.QuestionRuntime(App); const interrupt_rt = input_interrupt_runtime.InterruptRuntime(App); const queue_rt = input_queue_runtime.Runtime(App); const full_transcript_rt = input_full_transcript_runtime.Runtime(App); const ctrl_c_exit_window_ms = gesture_state.ctrl_c_exit_window_ms; const ResolvedEscapeRoute = union(enum) { done, remapped_byte: u8, }; const routeSlashCompletionMove = completion_rt.routeSlashCompletionMove; const advanceModelPickerOnSpace = completion_rt.advanceModelPickerOnSpace; const routeModifiedHistory = completion_rt.routeModifiedHistory; const routePlainVertical = completion_rt.routePlainVertical; const routeVisiblePickerMove = completion_rt.routeVisiblePickerMove; const navigateModelPicker = completion_rt.navigateModelPicker; const cancelApprovalOperation = approval_rt.cancelApprovalOperation; fn selectedChildRouteActive(app: *const App) bool { if (comptime @hasDecl(@TypeOf(app.subagents), "childRouteId")) { return app.subagents.childRouteId() != null; } return false; } const routeApprovalEscapeAction = approval_rt.routeApprovalEscapeAction; const routeQuestionEscapeAction = question_rt.routeQuestionEscapeAction; const submitQuestionBatch = question_rt.submitQuestionBatch; pub const rerenderQuestionBlock = question_rt.rerenderQuestionBlock; const finishPaste = paste_rt.finishPaste; const finalizePastedBlock = paste_rt.finalizePastedBlock; const handlePastedBytes = paste_rt.handlePastedBytes; const submit = submit_rt.submit; pub const installPromptHistory = history_rt.installPromptHistory; pub const loadAndInstallPromptHistory = history_rt.loadAndInstallPromptHistory; fn insertComposerSliceBounded( app: *App, bytes: []const u8, max_input_len: usize, preserve_model_picker: bool, ) !composer_insertion.InsertResult { const picker_policy: composer_insertion.PickerPolicy = if (preserve_model_picker) .preserve else .clear; return app.input_runtime.replacementState(&app.pending_images).replaceSelectionOrInsertSliceBounded( app.alloc, bytes, max_input_len, picker_policy, ); } pub fn clearPendingImages(app: *App) void { app.input_runtime.vertical_navigation.reset(); app.input_runtime.entities.image_tokens.clearRetainingCapacity(); image_attachments.discardImageSnapshots(app.alloc, app.pending_images.items); for (app.pending_images.items) |image| { types.freeImageAttachment(app.alloc, image); } app.pending_images.clearRetainingCapacity(); } pub fn releasePendingImages(app: *App) void { app.input_runtime.vertical_navigation.reset(); app.input_runtime.entities.image_tokens.clearRetainingCapacity(); for (app.pending_images.items) |image| { types.freeImageAttachment(app.alloc, image); } app.pending_images.clearRetainingCapacity(); } fn routeComposerShortcutAction(app: *App, action: input_action.ShortcutAction, max_input_len: usize) !void { if (comptime @hasField(App, "queued_prompt_review")) { if (shortcutDeletesQueuedDraft(action) and try queue_rt.deleteEmptyVisibleDraft(app)) return; if (shortcutMayMutateQueuedDraft(action)) queue_rt.markVisibleSelectionDirty(app); } switch (action) { .move => |intent| { switch (intent.kind) { .character_left => { app.input_runtime.vertical_navigation.reset(); if (!intent.extend_selection and app.input_runtime.edit_state.selectionRange() == null and !app.stream.active and try completion_rt.stepBackModelPicker(app)) { app.shell.render_requests.request(.footer); return; } _ = app.input_runtime.moveInputCursor(intent); }, .character_right => { app.input_runtime.vertical_navigation.reset(); if (!intent.extend_selection and app.input_runtime.edit_state.selectionRange() == null) { switch (try completion_rt.autocompleteInlineCompletion(app, max_input_len)) { .inserted => { app.shell.render_requests.request(.footer); return; }, .inactive => {}, .limit_exceeded => { try input_limit_feedback.report(App, app, .composer, 1); app.shell.render_requests.request(.footer); return; }, } } _ = app.input_runtime.moveInputCursor(intent); }, .word_left, .word_right, .line_start, .line_end, .draft_start, .draft_end, .paragraph_up, .paragraph_down, => { completion_rt.abandonModelPickerOptions(app); _ = app.input_runtime.moveInputCursor(intent); }, .visual_up, .visual_down, .page_up, .page_down, => { const direction: visual_layout.Direction = switch (intent.kind) { .visual_up, .page_up => .up, .visual_down, .page_down => .down, else => unreachable, }; const delta: i32 = if (direction == .up) -1 else 1; try completion_rt.routeComposerVertical( app, direction, delta, intent.extend_selection, intent.kind == .page_up or intent.kind == .page_down, ); }, } app.shell.render_requests.request(.footer); }, .select_all => { dismissActiveMenusThenRedraw(app); if (app.input_runtime.selectionState().selectAll()) { app.shell.render_requests.request(.footer); } }, .copy_selection => { if (comptime @hasDecl(App, "clipboard")) { if (input_selection_runtime.copySelection( &app.input_runtime.edit_state, app.clipboard(), ) == .copy_failed) { debug_trace.logf( "input", "composer selection copy preserved reason=clipboard_copy_failed", .{}, ); } } }, .cut_selection => { if (comptime @hasDecl(App, "clipboard")) { switch (input_selection_runtime.cutSelection( app.alloc, app.input_runtime.selectionState(), &app.pending_images, app.clipboard(), )) { .cut => { dismissActiveMenusThenRedraw(app); syncCatalogMenus(app); app.shell.render_requests.request(.footer); }, .copy_failed => debug_trace.logf( "input", "composer selection cut preserved reason=clipboard_copy_failed", .{}, ), .delete_failed => debug_trace.logf( "input", "composer selection cut delete skipped reason=delete_failed", .{}, ), .inactive, .copied => {}, } } }, .undo => { dismissActiveMenusThenRedraw(app); if (try app.input_runtime.undoState().undo(app.alloc)) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .redo => { dismissActiveMenusThenRedraw(app); if (try app.input_runtime.undoState().redo(app.alloc)) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .redraw => { if (!composerPickerSurfaceVisible(app) or activeCatalogMenuOwnsByte(app, 12)) return; if (comptime @hasField(App, "pacer") and @hasField(App, "metrics") and @hasDecl(@TypeOf(app.pacer), "discardDeferredPresentationForVisualEpoch")) { _ = try app_render_runtime.Runtime(App).resetVisualEpoch(app, .ctrl_l); } }, .history_previous => { try completion_rt.navigatePromptHistory(app, -1); syncCatalogMenus(app); app.shell.render_requests.request(.footer); }, .history_next => { try completion_rt.navigatePromptHistory(app, 1); syncCatalogMenus(app); app.shell.render_requests.request(.footer); }, .delete_backward => { if (app.input_runtime.edit_state.input.items.len > 0) { const picker_policy: composer_insertion.PickerPolicy = if (completion_rt.shouldPreserveModelPickerBackspace(app)) .preserve else .clear; const changed = app.input_runtime.deletionState( &app.pending_images, ).delete(app.alloc, .character_left, picker_policy); if (changed) { app.input_runtime.picker.resetFilePickerIndex(); syncCatalogMenus(app); app.shell.render_requests.request(.footer); } } }, .delete_forward => { dismissActiveMenusThenRedraw(app); if (app.input_runtime.deletionState(&app.pending_images).delete( app.alloc, .character_right, .clear, )) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .delete_word_left => { dismissActiveMenusThenRedraw(app); completion_rt.abandonModelPickerOptions(app); if (app.input_runtime.deletionState(&app.pending_images).delete( app.alloc, .word_left, .clear, )) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .delete_whitespace_word_left => { if (try app.input_runtime.killRingState(&app.pending_images).delete( app.alloc, .whitespace_word_left, )) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .delete_word_right => { dismissActiveMenusThenRedraw(app); completion_rt.abandonModelPickerOptions(app); if (app.input_runtime.deletionState(&app.pending_images).delete( app.alloc, .word_right, .clear, )) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .delete_to_line_start => { dismissActiveMenusThenRedraw(app); if (try app.input_runtime.killRingState(&app.pending_images).delete( app.alloc, .line_start, )) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .delete_to_line_end => { dismissActiveMenusThenRedraw(app); if (try app.input_runtime.killRingState(&app.pending_images).delete( app.alloc,Lines 1–500 of 13761. Load more
const std = @import("std"); const question_prompt = @import("../agent/question_prompt.zig"); const app_auth_runtime = @import("app_auth_runtime.zig"); const app_permission_runtime = @import("app_permission_runtime.zig"); const app_session_runtime = @import("app_session_runtime.zig"); const app_workspace_runtime = @import("app_workspace_runtime.zig"); const app_commands = @import("app_commands.zig"); const app_worker_runtime = @import("app_worker_runtime.zig"); const app_render_runtime = @import("app_render_runtime.zig"); const auth_runtime = @import("../auth/auth_runtime.zig"); const host = @import("../hosts/host.zig"); const runtime_profile = @import("../hosts/runtime_profile.zig"); const composer_insertion = @import("../input/composer_insertion.zig"); const gesture_state = @import("../input/gesture_state.zig"); const horizontal_navigation = @import("../input/horizontal_navigation.zig"); const input_action = @import("../input/input_action.zig"); const transcript_presentation = @import("../output/transcript_presentation.zig"); const core_input_runtime = @import("../input/runtime.zig"); const input_limit_rejection = @import("../input/input_limit_rejection.zig"); const input_reset = @import("../input/input_reset.zig"); const picker_state = @import("../input/picker_state.zig"); const paste_framing = @import("../input/paste_framing.zig"); const text_scalar = @import("../input/text_scalar.zig"); const io_mod = @import("../shared/io.zig"); const debug_trace = @import("../shared/debug_trace.zig"); const image_attachments = @import("../images/image_attachments.zig"); const image_commands = @import("../images/image_commands.zig"); const model_capabilities = @import("../config/model_capabilities.zig"); const model_cache_runtime = @import("model_cache_runtime.zig"); const permission_request = @import("../permissions/permission_request.zig"); const approval_decision = @import("../permissions/approval_decision.zig"); const permissions = @import("../permissions/permissions.zig"); const session_commands = @import("../session/session_commands.zig"); const session_catalog = @import("../session/session_catalog.zig"); const session_runtime = @import("../session/session.zig"); const session_store = @import("../session/session_store.zig"); const usage_report = @import("../session/usage_report.zig"); const skill_runtime = @import("../skills/skill_runtime.zig"); const file_index = @import("../workspace/file_index.zig"); const command_specs = @import("../slash_commands/command_specs.zig"); const types = @import("../shared/types.zig"); const subagent_input = @import("../subagent/input_action.zig"); const worker_runtime = @import("../agent/worker_runtime.zig"); const auto_upgrade = @import("../upgrade/auto_upgrade.zig"); const upgrade_helpers = @import("../upgrade/upgrade_helpers.zig"); const test_ui_input = @import("../../ui/input/runtime.zig"); const visual_layout = @import("../../ui/input/visual_layout.zig"); const approval_ui = @import("../../ui/footer/approval_ui.zig"); const interaction_state = @import("../../ui/footer/interaction_state.zig"); const approval_prompt = @import("../permissions/approval_prompt.zig"); const picker_presentation = @import("../../ui/footer/picker_presentation.zig"); const paste_blocks = @import("../input/pasted_blocks.zig"); const registered_entities = @import("../input/registered_entities.zig"); const prompt_history_runtime = @import("prompt_history_runtime.zig"); const prompt_history_store = @import("../session/prompt_history_store.zig"); const shell_runtime = @import("../../ui/shell_runtime.zig"); const render_request = @import("../../ui/render_request.zig"); const transcript_runtime = @import("../../ui/transcript/runtime.zig"); const input_interrupt_runtime = @import("input_interrupt_runtime.zig"); const input_queue_runtime = @import("input_queue_runtime.zig"); const input_history_runtime = @import("input_history_runtime.zig"); const input_subagent_runtime = @import("input_subagent_runtime.zig"); const input_completion_runtime = @import("input_completion_runtime.zig"); const input_paste_runtime = @import("input_paste_runtime.zig"); const input_submit_runtime = @import("input_submit_runtime.zig"); const input_approval_runtime = @import("input_approval_runtime.zig"); const input_question_runtime = @import("input_question_runtime.zig"); const input_full_transcript_runtime = @import("input_full_transcript_runtime.zig"); const input_selection_runtime = @import("input_selection_runtime.zig"); const input_limit_feedback = @import("input_limit_feedback.zig"); const app_upgrade_runtime = @import("app_upgrade_runtime.zig"); const ModelPickerStage = picker_state.ModelPickerStage; const ToolPermissionDecision = types.ToolPermissionDecision; pub const file_picker_completion_cap = input_completion_runtime.file_picker_completion_cap; const ctrl_g_upgrade_byte: u8 = 7; const ctrl_x_manager_byte: u8 = 24; fn classifyResumeFailure(err: anyerror) session_catalog.ResumeFailure { return switch (err) { error.SessionBusy => .open_elsewhere, error.SessionAuthorityBoundaryUnavailable, error.SessionCommitBoundaryUnavailable, => .being_updated, else => .unavailable, }; } const ExplicitModelSelection = struct { model: []const u8, effort: types.ReasoningEffort, fast_mode: bool, has_fast_mode_token: bool = false, }; const ExplicitModelSelectionParse = union(enum) { none, invalid, selection: ExplicitModelSelection, }; fn shortcutMayMutateQueuedDraft(action: input_action.ShortcutAction) bool { return switch (action) { .move, .select_all, .copy_selection, .redraw, => false, .cut_selection, .undo, .redo, .history_previous, .history_next, .delete_backward, .delete_forward, .delete_word_left, .delete_whitespace_word_left, .delete_word_right, .delete_to_line_start, .delete_to_line_end, .yank, .insert_newline, => true, }; } fn shortcutDeletesQueuedDraft(action: input_action.ShortcutAction) bool { return switch (action) { .delete_backward, .delete_forward, .delete_word_left, .delete_whitespace_word_left, .delete_word_right, .delete_to_line_start, .delete_to_line_end, => true, else => false, }; } fn parseExplicitModelSelection(input: []const u8) ExplicitModelSelectionParse { const trimmed = std.mem.trim(u8, input, " \t\r\n"); if (!std.ascii.startsWithIgnoreCase(trimmed, "/model")) return .none; if (trimmed.len == "/model".len) return .none; if (trimmed["/model".len] != ' ' and trimmed["/model".len] != '\t') return .none; var tokens: [4][]const u8 = undefined; var token_count: usize = 0; var iterator = std.mem.tokenizeAny(u8, trimmed["/model".len..], " \t\r\n"); while (iterator.next()) |token| { if (token_count == tokens.len) return .invalid; tokens[token_count] = token; token_count += 1; } if (token_count < 2) return .none; const effort = types.ReasoningEffort.parse(tokens[1]) orelse return .none; if (token_count == 2) { return .{ .selection = .{ .model = tokens[0], .effort = effort, .fast_mode = false, .has_fast_mode_token = false, } }; } if (token_count != 3) return .invalid; const fast_mode = if (std.ascii.eqlIgnoreCase(tokens[2], "fast")) true else if (std.ascii.eqlIgnoreCase(tokens[2], "normal")) false else return .invalid; return .{ .selection = .{ .model = tokens[0], .effort = effort, .fast_mode = fast_mode, .has_fast_mode_token = true, } }; } fn validateExplicitModelSelection(selection: ExplicitModelSelection, capabilities: model_capabilities.Capabilities) ExplicitModelSelectionParse { if (!model_capabilities.reasoningEffortSupported(capabilities, selection.effort)) return .invalid; if (capabilities.supports_fast_mode != selection.has_fast_mode_token) return .invalid; return .{ .selection = selection }; } pub fn Runtime(comptime App: type) type { return struct { const history_rt = input_history_runtime.HistoryRuntime(App); const subagent_rt = input_subagent_runtime.SubagentRuntime(App); const completion_rt = input_completion_runtime.CompletionRuntime(App); const paste_rt = input_paste_runtime.PasteEditRuntime(App); const submit_rt = input_submit_runtime.SubmitRuntime(App); const approval_rt = input_approval_runtime.ApprovalRuntime(App); const question_rt = input_question_runtime.QuestionRuntime(App); const interrupt_rt = input_interrupt_runtime.InterruptRuntime(App); const queue_rt = input_queue_runtime.Runtime(App); const full_transcript_rt = input_full_transcript_runtime.Runtime(App); const ctrl_c_exit_window_ms = gesture_state.ctrl_c_exit_window_ms; const ResolvedEscapeRoute = union(enum) { done, remapped_byte: u8, }; const routeSlashCompletionMove = completion_rt.routeSlashCompletionMove; const advanceModelPickerOnSpace = completion_rt.advanceModelPickerOnSpace; const routeModifiedHistory = completion_rt.routeModifiedHistory; const routePlainVertical = completion_rt.routePlainVertical; const routeVisiblePickerMove = completion_rt.routeVisiblePickerMove; const navigateModelPicker = completion_rt.navigateModelPicker; const cancelApprovalOperation = approval_rt.cancelApprovalOperation; fn selectedChildRouteActive(app: *const App) bool { if (comptime @hasDecl(@TypeOf(app.subagents), "childRouteId")) { return app.subagents.childRouteId() != null; } return false; } const routeApprovalEscapeAction = approval_rt.routeApprovalEscapeAction; const routeQuestionEscapeAction = question_rt.routeQuestionEscapeAction; const submitQuestionBatch = question_rt.submitQuestionBatch; pub const rerenderQuestionBlock = question_rt.rerenderQuestionBlock; const finishPaste = paste_rt.finishPaste; const finalizePastedBlock = paste_rt.finalizePastedBlock; const handlePastedBytes = paste_rt.handlePastedBytes; const submit = submit_rt.submit; pub const installPromptHistory = history_rt.installPromptHistory; pub const loadAndInstallPromptHistory = history_rt.loadAndInstallPromptHistory; fn insertComposerSliceBounded( app: *App, bytes: []const u8, max_input_len: usize, preserve_model_picker: bool, ) !composer_insertion.InsertResult { const picker_policy: composer_insertion.PickerPolicy = if (preserve_model_picker) .preserve else .clear; return app.input_runtime.replacementState(&app.pending_images).replaceSelectionOrInsertSliceBounded( app.alloc, bytes, max_input_len, picker_policy, ); } pub fn clearPendingImages(app: *App) void { app.input_runtime.vertical_navigation.reset(); app.input_runtime.entities.image_tokens.clearRetainingCapacity(); image_attachments.discardImageSnapshots(app.alloc, app.pending_images.items); for (app.pending_images.items) |image| { types.freeImageAttachment(app.alloc, image); } app.pending_images.clearRetainingCapacity(); } pub fn releasePendingImages(app: *App) void { app.input_runtime.vertical_navigation.reset(); app.input_runtime.entities.image_tokens.clearRetainingCapacity(); for (app.pending_images.items) |image| { types.freeImageAttachment(app.alloc, image); } app.pending_images.clearRetainingCapacity(); } fn routeComposerShortcutAction(app: *App, action: input_action.ShortcutAction, max_input_len: usize) !void { if (comptime @hasField(App, "queued_prompt_review")) { if (shortcutDeletesQueuedDraft(action) and try queue_rt.deleteEmptyVisibleDraft(app)) return; if (shortcutMayMutateQueuedDraft(action)) queue_rt.markVisibleSelectionDirty(app); } switch (action) { .move => |intent| { switch (intent.kind) { .character_left => { app.input_runtime.vertical_navigation.reset(); if (!intent.extend_selection and app.input_runtime.edit_state.selectionRange() == null and !app.stream.active and try completion_rt.stepBackModelPicker(app)) { app.shell.render_requests.request(.footer); return; } _ = app.input_runtime.moveInputCursor(intent); }, .character_right => { app.input_runtime.vertical_navigation.reset(); if (!intent.extend_selection and app.input_runtime.edit_state.selectionRange() == null) { switch (try completion_rt.autocompleteInlineCompletion(app, max_input_len)) { .inserted => { app.shell.render_requests.request(.footer); return; }, .inactive => {}, .limit_exceeded => { try input_limit_feedback.report(App, app, .composer, 1); app.shell.render_requests.request(.footer); return; }, } } _ = app.input_runtime.moveInputCursor(intent); }, .word_left, .word_right, .line_start, .line_end, .draft_start, .draft_end, .paragraph_up, .paragraph_down, => { completion_rt.abandonModelPickerOptions(app); _ = app.input_runtime.moveInputCursor(intent); }, .visual_up, .visual_down, .page_up, .page_down, => { const direction: visual_layout.Direction = switch (intent.kind) { .visual_up, .page_up => .up, .visual_down, .page_down => .down, else => unreachable, }; const delta: i32 = if (direction == .up) -1 else 1; try completion_rt.routeComposerVertical( app, direction, delta, intent.extend_selection, intent.kind == .page_up or intent.kind == .page_down, ); }, } app.shell.render_requests.request(.footer); }, .select_all => { dismissActiveMenusThenRedraw(app); if (app.input_runtime.selectionState().selectAll()) { app.shell.render_requests.request(.footer); } }, .copy_selection => { if (comptime @hasDecl(App, "clipboard")) { if (input_selection_runtime.copySelection( &app.input_runtime.edit_state, app.clipboard(), ) == .copy_failed) { debug_trace.logf( "input", "composer selection copy preserved reason=clipboard_copy_failed", .{}, ); } } }, .cut_selection => { if (comptime @hasDecl(App, "clipboard")) { switch (input_selection_runtime.cutSelection( app.alloc, app.input_runtime.selectionState(), &app.pending_images, app.clipboard(), )) { .cut => { dismissActiveMenusThenRedraw(app); syncCatalogMenus(app); app.shell.render_requests.request(.footer); }, .copy_failed => debug_trace.logf( "input", "composer selection cut preserved reason=clipboard_copy_failed", .{}, ), .delete_failed => debug_trace.logf( "input", "composer selection cut delete skipped reason=delete_failed", .{}, ), .inactive, .copied => {}, } } }, .undo => { dismissActiveMenusThenRedraw(app); if (try app.input_runtime.undoState().undo(app.alloc)) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .redo => { dismissActiveMenusThenRedraw(app); if (try app.input_runtime.undoState().redo(app.alloc)) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .redraw => { if (!composerPickerSurfaceVisible(app) or activeCatalogMenuOwnsByte(app, 12)) return; if (comptime @hasField(App, "pacer") and @hasField(App, "metrics") and @hasDecl(@TypeOf(app.pacer), "discardDeferredPresentationForVisualEpoch")) { _ = try app_render_runtime.Runtime(App).resetVisualEpoch(app, .ctrl_l); } }, .history_previous => { try completion_rt.navigatePromptHistory(app, -1); syncCatalogMenus(app); app.shell.render_requests.request(.footer); }, .history_next => { try completion_rt.navigatePromptHistory(app, 1); syncCatalogMenus(app); app.shell.render_requests.request(.footer); }, .delete_backward => { if (app.input_runtime.edit_state.input.items.len > 0) { const picker_policy: composer_insertion.PickerPolicy = if (completion_rt.shouldPreserveModelPickerBackspace(app)) .preserve else .clear; const changed = app.input_runtime.deletionState( &app.pending_images, ).delete(app.alloc, .character_left, picker_policy); if (changed) { app.input_runtime.picker.resetFilePickerIndex(); syncCatalogMenus(app); app.shell.render_requests.request(.footer); } } }, .delete_forward => { dismissActiveMenusThenRedraw(app); if (app.input_runtime.deletionState(&app.pending_images).delete( app.alloc, .character_right, .clear, )) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .delete_word_left => { dismissActiveMenusThenRedraw(app); completion_rt.abandonModelPickerOptions(app); if (app.input_runtime.deletionState(&app.pending_images).delete( app.alloc, .word_left, .clear, )) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .delete_whitespace_word_left => { if (try app.input_runtime.killRingState(&app.pending_images).delete( app.alloc, .whitespace_word_left, )) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .delete_word_right => { dismissActiveMenusThenRedraw(app); completion_rt.abandonModelPickerOptions(app); if (app.input_runtime.deletionState(&app.pending_images).delete( app.alloc, .word_right, .clear, )) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .delete_to_line_start => { dismissActiveMenusThenRedraw(app); if (try app.input_runtime.killRingState(&app.pending_images).delete( app.alloc, .line_start, )) { syncCatalogMenus(app); app.shell.render_requests.request(.footer); } }, .delete_to_line_end => { dismissActiveMenusThenRedraw(app); if (try app.input_runtime.killRingState(&app.pending_images).delete( app.alloc,