import { useMemo, useState, type JSX } from "react"; import { translate } from "../../../../../i18n/index"; import { workspaceFilePathBasename } from "../../../../../actions/workspaceFilePathCandidate"; import { AgentPathTailLabel } from "../AgentPathTailLabel"; const MAX_VISIBLE_LINES = 120; export function AgentCodeBlock({ path, content, language, showHeader = true, collapsible = false, flat = false }: { path?: string | null; content: string; language?: string | null; showHeader?: boolean; collapsible?: boolean; flat?: boolean; }): JSX.Element { "use memo"; const [expanded, setExpanded] = useState(false); const normalized = content.trimEnd(); const isEmpty = !normalized; const emptyPlaceholder = translate( "agentHost.agentGui.codeBlockEmptyContent" ); const lines = useMemo( () => (isEmpty ? [] : normalized.split("\n")), [isEmpty, normalized] ); const lineCount = lines.length; const truncated = collapsible && !expanded && lineCount > MAX_VISIBLE_LINES; const visibleContent = truncated ? lines.slice(0, MAX_VISIBLE_LINES).join("\n") : isEmpty ? emptyPlaceholder : normalized; const visibleLines = useMemo( () => (truncated ? lines.slice(0, MAX_VISIBLE_LINES) : lines).map( (line, lineIndex) => ({ key: `${lineIndex + 1}:${line}`, line, lineNumber: lineIndex + 1 }) ), [lines, truncated] ); const addedCount = lineCount; const fileLabel = fileNameFromPath(path) ?? path ?? "Code"; const disclosureButton = collapsible && lineCount > MAX_VISIBLE_LINES ? ( ) : null; return (
{emptyPlaceholder}
) : (
<>
{visibleLines.map((line) => (
{line.line || " "}
{visibleContent}
{disclosureButton}
>
)}