import { extname } from 'path' import React, { Suspense, use, useMemo } from 'react' import { Ansi, Text } from '@anthropic/ink' import { LRUCache } from 'lru-cache' import { getCliHighlightPromise } from '../../utils/cliHighlight.js' import { logForDebugging } from '../../utils/debug.js' import { convertLeadingTabsToSpaces } from '../../utils/file.js' import { hashPair } from '../../utils/hash.js' type Props = { code: string filePath: string dim?: boolean skipColoring?: boolean } // Module-level highlight cache — hl.highlight() is the hot cost on virtual- // scroll remounts. useMemo doesn't survive unmount→remount. Keyed by hash // of code+language to avoid retaining full source strings (#24180 RSS fix). const hlCache = new LRUCache({ max: 500 }) function cachedHighlight( hl: NonNullable>>, code: string, language: string, ): string { const key = hashPair(language, code) const hit = hlCache.get(key) if (hit !== undefined) return hit const out = hl.highlight(code, { language }) hlCache.set(key, out) return out } export function HighlightedCodeFallback({ code, filePath, dim = false, skipColoring = false, }: Props): React.ReactElement { const codeWithSpaces = convertLeadingTabsToSpaces(code) if (skipColoring) { return ( {codeWithSpaces} ) } const language = extname(filePath).slice(1) return ( {codeWithSpaces}}> ) } function Highlighted({ codeWithSpaces, language, }: { codeWithSpaces: string language: string }): React.ReactElement { const hl = use(getCliHighlightPromise()) const out = useMemo(() => { if (!hl) return codeWithSpaces let highlightLang = 'markdown' if (language) { if (hl.supportsLanguage(language)) { highlightLang = language } else { logForDebugging( `Language not supported while highlighting code, falling back to markdown: ${language}`, ) } } try { return cachedHighlight(hl, codeWithSpaces, highlightLang) } catch (e) { if (e instanceof Error && e.message.includes('Unknown language')) { logForDebugging( `Language not supported while highlighting code, falling back to markdown: ${e}`, ) return cachedHighlight(hl, codeWithSpaces, 'markdown') } return codeWithSpaces } }, [codeWithSpaces, language, hl]) return {out} }