Reference: the overlay API
NOTE
The ingest and protocol modules live in sparkles:twoslash-protocol (libs/twoslash-protocol), which depends only on sparkles:wired; sparkles.twoslash re-exports both.
Ingest (sparkles.twoslash.ingest)
| Symbol | Signature | Notes |
|---|---|---|
parseTwoslash | JsonResult!TwoslashReturn parseTwoslash(scope const(char)[] json) | parse + decode a JSON string |
loadTwoslashFile | JsonResult!TwoslashReturn loadTwoslashFile(string path) | read + parse + decode a file |
fromTwoslashJson | JsonResult!TwoslashReturn fromTwoslashJson(JSONValue root) | decode a pre-parsed object |
Errors are returned (never thrown). Not @nogc (std.json + wired allocate).
Protocol (sparkles.twoslash.protocol)
enum NodeType : ubyte { hover, query, completion, error, highlight, tag }— lowercase members map the wiretypeverbatim.struct Node— flat POD:type,start,length,line,character, plus the@WireOptionalpayload fields (text,docs,tags,level,code,id,completions,completionsPrefix,name,signature).tagsisstring[][](each inner[name, text?]— hover/query JSDoc tags);signatureis aSignatureLayout(break points, collapsible runs, effects, contracts).end() => start + length.struct Completion { string name; string kind; }struct TwoslashReturn { string code; Node[] nodes; string language; string offsetEncoding; }—effectiveLanguage()islanguage, or"typescript"when it is empty.offsetEncoding: "utf-8"marks byte offsets (D producers); anything else is converted from UTF-16 on ingest.
Overlay planner (sparkles.twoslash.overlay)
TwoslashPlan planTwoslash(in TwoslashReturn tw)— partition intoinlineDecorations(sorted outer-first) andbelowBlocks(sorted by line). Drops the inlinehoveron a token that also has aquery(the query supersedes it).hasInlineDecoration(NodeType)/hasBelowBlock(NodeType)— classification.highlightSignature(ref TsConfigCache, language, sig, ref sink)— reentrant popup re-highlight (degrades to plain text on a missing grammar).@system.withoutQuickinfoPrefix(sig)— strips a leading TS quickinfo kind prefix ((property), …); a real leading paren ((a: number) => void) is preserved.
Renderers
renderTwoslashHtml(in TwoslashReturn tw, const(HighlightEvent)[] events, in ResolvedTheme theme, ref TsConfigCache cache, ref Writer w, in TwoslashHtmlOptions = …)— content-only HTML overlay.@system.renderTwoslashAnsi(… , in TwoslashAnsiOptions = …)— terminal overlay (TwoslashAnsiOptions { ColorDepth depth; bool italics, emitBackground, hovers; }).@system.
TwoslashHtmlOptions controls the HTML fidelity/chrome:
| Field | Default | Effect |
|---|---|---|
classPrefix | "syn-" | class prefix for the inner syntax spans |
completionIcons | IconStyle.svg | completion-kind icon set (svg | glyph | none) |
customCompletionIcon | null | per-kind icon override delegate (non-empty return wins) |
tagIcons | IconStyle.svg | // @tag line icon set (svg | glyph | none) |
stripQuickinfoPrefix | false | strip (property) etc. from popup signatures |
renderDocsMarkdown | true | render docs (block) + @tag values (inline) as markdown |
The svg icon sets are the reference @shikijs/twoslash icons, string-imported from views/icons/{completions,tags}/*.svg by sparkles.twoslash.icons.
With renderDocsMarkdown (default on), hover/query docs render as block markdown and each @tag value as inline markdown, via the MdDoc → HTML emitter in sparkles:syntax (renderMarkdownHtml / renderMarkdownInlineHtml, Shiki's renderMarkdown/renderMarkdownInline seam). It degrades to escaped text automatically when the markdown grammars are unavailable, so no grammar bundle is required for correct — if plainer — output.
The 15-markdown-docs fixture is the showcase: hue --twoslash --html fixtures/15-markdown-docs.twoslash.json, then hover the answer token. To exercise that same MdDoc → HTML emitter without twoslash, hue --markdown <file.md> renders any Markdown file straight through extractMarkdown + renderMarkdownHtml.
Both take the snippet already highlighted into events (over tw.code) and the cache used to re-highlight popup signatures. Neither is @nogc.
Stylesheet (sparkles.twoslash.style)
enum twoslashStyleCss— the portedstyle-rich.css, compiled in.writeTwoslashStyles(ref Writer w)— write it (no<style>wrapper). Styles only the.twoslash-*chrome; syntax token colors come fromwriteThemeStylesheet(.syn-*).
Widget view (sparkles.twoslash.render_widgets)
The overlay as sparkles:ui widgets, which hue's GUI and interactive terminal lay out and paint:
viewTwoslashDocument/viewTwoslashDocumentInto— the whole document: code rows, fused inline decorations, and interleaved below-line blocks.decorateCodeRow— layers one line's inline decorations onto a row the caller built (hue's diff view uses it per side).viewTwoslash/viewBelowBlock— the below-line blocks alone.viewHoverPopup— the hover/query popup; the overload taking aGrammarRegistryrendersdocsas markdown.HoverViewOptionscarries the width, the syntax-coloredsignatureSpans, and the expanded signature runs.
hue --gui --twoslash <nodes.json> opens the payload as a document: sparkles:doc-view builds it with viewTwoslashDocumentInto, and gui.drawPopup paints viewHoverPopup on mouse-over (version(HueGui)).