/** `debug` — DAP debugger sessions: launch/attach, breakpoints, stepping, evaluate. */ import type { ReactNode } from "react"; import { Badge, CodeBlock, Kv, KvGrid, PathText, ResultText } from "../parts"; import type { ToolRenderer, ToolRenderProps } from "../types"; import { detailsRecord, display, isRecord, normalizeWs, num, str, truncate } from "../util"; /** Session snapshot the TUI renders as its "Session" section (details.snapshot). */ interface SessionSnapshot { id: string | null; adapter: string | null; status: string | null; program: string | null; stopReason: string | null; frameName: string | null; sourcePath: string | null; line: number | null; column: number | null; exitCode: number | null; needsConfigurationDone: boolean; } function snapshotOf(result: ToolRenderProps["result"]): SessionSnapshot | null { const rec = detailsRecord(result); if (!rec || !isRecord(rec.snapshot)) return null; const snap = rec.snapshot; const source = isRecord(snap.source) ? snap.source : null; return { id: str(snap.id) ?? (num(snap.id) !== null ? String(snap.id) : null), adapter: str(snap.adapter), status: str(snap.status), program: str(snap.program), stopReason: str(snap.stopReason), frameName: str(snap.frameName), sourcePath: source ? str(source.path) : null, line: num(snap.line), column: num(snap.column), exitCode: num(snap.exitCode), needsConfigurationDone: snap.needsConfigurationDone === true, }; } function actionOf(props: ToolRenderProps): string { const action = str(props.args.action) ?? str(detailsRecord(props.result)?.action); return action ? action.replace(/_/g, " ") : "request"; } /** Mirrors the TUI's summarizeDebugCall target priority. */ function targetTextOf(args: Record): string | null { return ( str(args.function) ?? str(args.expression) ?? str(args.command) ?? str(args.memory_reference) ?? str(args.instruction_reference) ?? str(args.data_id) ?? str(args.name) ); } function Summary(props: ToolRenderProps): ReactNode { const { args } = props; const program = str(args.program); const file = str(args.file); const line = num(args.line); const target = targetTextOf(args); return ( <> {actionOf(props)} {program !== null ? ( ) : file !== null ? ( ) : target !== null ? ( {truncate(normalizeWs(target), 80)} ) : null} ); } /** Scalar args worth a KvGrid row, in display order (program/file/expression are special-cased). */ const SCALAR_ARGS: ReadonlyArray = [ ["adapter", "adapter"], ["cwd", "cwd"], ["function", "function"], ["name", "name"], ["condition", "condition"], ["hit_condition", "hit condition"], ["context", "context"], ["frame_id", "frame id"], ["scope_id", "scope id"], ["variable_ref", "variable ref"], ["pid", "pid"], ["host", "host"], ["port", "port"], ["levels", "levels"], ["memory_reference", "memory ref"], ["instruction_reference", "instruction ref"], ["instruction_count", "instruction count"], ["instruction_offset", "instruction offset"], ["offset", "offset"], ["count", "count"], ["data", "data"], ["data_id", "data id"], ["access_type", "access"], ["command", "command"], ["resolve_symbols", "resolve symbols"], ["allow_partial", "allow partial"], ["start_module", "start module"], ["module_count", "module count"], ["timeout", "timeout"], ]; function Body(props: ToolRenderProps): ReactNode { const { args, result } = props; const program = str(args.program); const file = str(args.file); const line = num(args.line); const expression = str(args.expression); const programArgs = Array.isArray(args.args) ? args.args.filter(a => typeof a === "string") : []; const argRows: ReactNode[] = []; if (program !== null) { argRows.push( , ); } if (programArgs.length > 0) { argRows.push( {truncate(programArgs.join(" "), 160)} , ); } if (file !== null) { argRows.push( , ); } else if (line !== null) { argRows.push( {line} , ); } for (const [key, label] of SCALAR_ARGS) { const value = args[key]; if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") continue; argRows.push( {truncate(display(value), 120)} , ); } let customArgsJson = ""; if (isRecord(args.arguments)) { try { customArgsJson = JSON.stringify(args.arguments, null, 2) ?? ""; } catch { customArgsJson = ""; } } const snapshot = snapshotOf(result); return ( <> {argRows.length > 0 && {argRows}} {expression !== null && } {customArgsJson && } {snapshot && ( {snapshot.id !== null && {snapshot.id}} {snapshot.adapter !== null && {snapshot.adapter}} {snapshot.status !== null && ( {snapshot.status} )} {snapshot.program !== null && ( )} {snapshot.stopReason !== null && {snapshot.stopReason}} {snapshot.frameName !== null && {snapshot.frameName}} {snapshot.sourcePath !== null && snapshot.line !== null && ( )} {snapshot.exitCode !== null && {snapshot.exitCode}} {snapshot.needsConfigurationDone && ( pending configurationDone — set breakpoints, then continue )} )} ); } export const debugRenderer: ToolRenderer = { Summary, Body };