// MdText — render a markdown string into chat-friendly terminal JSX. // Line-level parsing comes from md-render.ts; this file is the JSX mapping. import { palette } from "../theme.ts"; import { parseMarkdown, highlightCode, CodeTok } from "../md-render.ts"; const ui = palette("loom"); // Code colors come straight from the active theme's TextMate syntax scopes // (keyword/string/comment/number/call) — same source VS Code uses, so fenced // blocks look right for whichever theme is picked. const CODE_COLORS: Record string> = { kw: () => ui.syntax.kw, str: () => ui.syntax.str, com: () => ui.syntax.com, num: () => ui.syntax.num, call: () => ui.syntax.call, plain: () => ui.syntax.plain, }; function CodeLine(props: { toks: CodeTok[]; k: string }) { return ( {props.toks.map((t, j) => ( // @ts-ignore OpenTUI text nodes take fg via the style prop (TextNodeOptions), not as a direct prop {t.text} ))} ); } function spansToNodes(spans: any[], keyPrefix: string) { if (!spans.length) return " "; return spans.map((s, i) => { const key = keyPrefix + "-" + i; if (s.code) { // Inline code: accent color + panel background to read as a chip. // @ts-ignore OpenTUI text nodes take fg/bg via the style prop (TextNodeOptions), not as direct props return {s.text}; } if (s.link) { // @ts-ignore OpenTUI text nodes take fg/underline via the style prop; href is a direct prop return {s.text}; } if (s.bold && s.italic) { // @ts-ignore OpenTUI text nodes take fg via the style prop (TextNodeOptions) return {s.text}; } // @ts-ignore OpenTUI text nodes take fg via the style prop (TextNodeOptions) if (s.bold) return {s.text}; // @ts-ignore OpenTUI text nodes take fg via the style prop (TextNodeOptions) if (s.italic) return {s.text}; return {s.text}; }); } function HeadingText(props: { level: 1 | 2 | 3; spans: any[]; keyPrefix: string }) { const marker = props.level === 1 ? "# " : props.level === 2 ? "## " : "### "; return {marker}{spansToNodes(props.spans, props.keyPrefix)}; } export function MdText(props: { md: string; wrap?: boolean }) { const lines = parseMarkdown(props.md); return ( {lines.map((ln, i) => { const kp = "mdl-" + i; switch (ln.kind) { case "heading": return ; case "bullet": return ( {// @ts-ignore OpenTUI text nodes take fg via the style prop (TextNodeOptions) {"• "}} {spansToNodes(ln.spans, kp)} ); case "quote": return ( {// @ts-ignore OpenTUI text nodes take fg via the style prop (TextNodeOptions) {"│ "}} {spansToNodes(ln.spans, kp)} ); case "rule": return {"────────"}; case "code": { const lines = highlightCode(ln.code, ln.lang); return ( {lines.map((toks, j) => ( ))} ); } default: return {spansToNodes(ln.spans, kp)}; } })} ); }