feat: render LaTeX, custom HTML and diagrams in the transcript #19

Merged
adrianbonpin merged 1 commits from feat/transcript-rendering into prod 2026-10-07 07:26:41 +00:00
1 Commits
Author SHA1 Message Date
adrianbonpin 6c9183f7de feat: render LaTeX, custom HTML and diagrams in the transcript
The transcript rendered whatever the model wrote as markdown, and three
things a model writes are not markdown the renderer draws.

LaTeX. Vicinae has no maths block, so `$x^2$` reached the pane as
literal TeX. `latex.ts` converts the subset models actually write into
inline markup the pane can draw: `sup`, `sub`, `b` and `i` are available
because `MdParagraph.qml` is a rich text `TextEdit` and
`markdown-model.cpp` passes `CMARK_NODE_HTML_INLINE` through untouched.
It is a linearisation rather than a typesetter, because the pane is a
launcher-width column: `\frac{a}{b}` becomes `a/b` and `\sqrt{x+1}`
becomes `√(x+1)`, with a Unicode script wherever one exists. A lone `$`
pair only counts when the inside looks like maths, so `$5 and $10` and
`cd $A; echo $B` are left as written.

Custom HTML. Raw HTML is the only route past GFM, and it is also a hole,
so `html.ts` filters it: the tags and style declarations the renderer
acts on are kept, `script` and `style` go with their content, an event
handler, a `url()` in a style value and a `javascript:` destination are
dropped, and a tag that is not on the list is shown as text rather than
swallowed. An `<a href>` becomes a markdown link, the only form Vicinae
makes clickable. A well-formed HTML block is moved into a paragraph,
because the block path keeps only the words of one.

Everything else. `code.ts` now fences a paragraph drawn with box
characters, since a paragraph wraps and a diagram that reflows says
nothing, and renames a fence label KSyntaxHighlighting would print but
never resolve.

The pass lives in `render.ts`, is plain TypeScript with no Vicinae
imports, and the default system prompt now says what the window draws.
2026-10-07 15:26:19 +08:00