Documentation
¶
Overview ¶
Package markdown renders Markdown as ui/el elements, built for AI chat: text that streams in a few characters at a time.
doc := markdown.New("")
doc.SetStreaming(true)
go func() {
for tok := range tokens {
core.Update(func() { doc.Append(tok) })
}
core.Update(func() { doc.SetStreaming(false) })
}()
... el.Div().Child(doc.Render(cx)) ...
Streaming stays cheap and steady:
- The source is split into top-level chunks at blank lines outside code and display-math fences. Each chunk is parsed once and kept; an append only reparses the chunks it changed, normally just the last one.
- While streaming, unfinished inline syntax at the end (**bold, `code, ~~strike, [link](url) is closed provisionally, so text does not flash between raw markers and formatting as tokens arrive.
- A caret marks where text is arriving.
Supported: paragraphs, headings, emphasis, strikethrough, inline code, links, autolinks, fenced code with syntax highlighting and a copy button, block quotes, ordered, unordered and task lists, GFM tables, rules, and a native subset of TeX mathematics. Images show as their alt text.
Index ¶
- Variables
- func DecodeImage(ctx context.Context, source string) (image.Image, error)
- type CodeBlockContext
- type Doc
- func (d *Doc) Append(s string)
- func (d *Doc) CodeBlockActions(fn func(*el.Context, CodeBlockContext) el.Element) *Doc
- func (d *Doc) CodeBlockRenderer(language string, fn func(*el.Context, CodeBlockContext) el.Element) *Doc
- func (d *Doc) FrontMatter() string
- func (d *Doc) ImageLoader(loader ImageLoader) *Doc
- func (d *Doc) IsClamped() bool
- func (d *Doc) MaxLines(n int) *Doc
- func (d *Doc) Meta() map[string]string
- func (d *Doc) OnLink(fn func(url string)) *Doc
- func (d *Doc) Plugins(plugins ...Plugin) *Doc
- func (d *Doc) Render(cx *el.Context) el.Element
- func (d *Doc) RenderedText() string
- func (d *Doc) RevealRange(r TextRange) bool
- func (d *Doc) SetRangeHighlights(items []RangeHighlight) bool
- func (d *Doc) SetSource(src string)
- func (d *Doc) SetStreaming(on bool)
- func (d *Doc) ShowFrontMatter(on bool) *Doc
- func (d *Doc) Source() string
- func (d *Doc) StreamFade(enabled bool) *Doc
- func (d *Doc) StreamFadeDuration(duration time.Duration) *Doc
- func (d *Doc) Streaming() bool
- type ImageLoader
- type InlineObject
- type Plugin
- type RangeHighlight
- type TextRange
Constants ¶
This section is empty.
Variables ¶
var ( CodeBg color.NRGBA CodeBorder color.NRGBA CodeHover color.NRGBA InlineCode color.NRGBA InlineCodeBg color.NRGBA CodeStyle = "" // a chroma style name MonoFace = theme.MonoFace )
Colors and fonts of rendered Markdown. Change them before rendering.
var SelectionBg = color.NRGBA{R: 0xb4, G: 0xd5, B: 0xfe, A: 0xff}
SelectionBg is the color behind selected text.
Functions ¶
Types ¶
type CodeBlockContext ¶
CodeBlockContext is a snapshot of a fenced or indented code block. Text is the original code, without the Markdown fence. ID remains stable while the parser preserves the block's presentation state.
type Doc ¶
type Doc struct {
// contains filtered or unexported fields
}
Doc is a Markdown document, rendered as an el element. Change it only under the UI lock: from callbacks, or from other goroutines through core.Update.
func (*Doc) CodeBlockActions ¶
CodeBlockActions appends controls to the default code header. It is called each render, including for code in lists/quotes. Nil removes the extension. Handlers may change application state; rendering must not mutate the document.
func (*Doc) CodeBlockRenderer ¶
func (d *Doc) CodeBlockRenderer(language string, fn func(*el.Context, CodeBlockContext) el.Element) *Doc
CodeBlockRenderer replaces code cards for one language (case insensitive). Return nil to retain highlighting and standard actions. An empty language targets unlabelled code. Passing nil unregisters the renderer. Custom views own their controls and text selection; the source is never executed by Doc.
func (*Doc) FrontMatter ¶
FrontMatter returns the YAML of the document's front matter, without the --- lines, or "" if it has none.
func (*Doc) ImageLoader ¶
func (d *Doc) ImageLoader(loader ImageLoader) *Doc
ImageLoader sets how local or remote image sources are read. Configure it before the first Render. A nil loader uses DecodeImage.
func (*Doc) IsClamped ¶
IsClamped reports whether the most recently painted frame hid content because of MaxLines. It is false before the first frame and after removing the limit.
func (*Doc) MaxLines ¶
MaxLines limits the document to n body-line heights, including block spacing. Zero or a negative value removes the limit. Taller headings can consume more than one line of this budget. It does not add an ellipsis or expand button.
func (*Doc) Meta ¶
Meta reads the front matter's top-level "key: value" lines, with quotes around a value removed. Nested and list values are kept as written; use FrontMatter with a YAML parser for those.
func (*Doc) Plugins ¶
Plugins replaces this document's plugins and reparses its source. Configure once, not every Render. Empty input restores the built-in parser. Registered documents parse as a whole so custom block syntax can cross blank lines. Factories may run again on each edit; reuse widgets/views in application code when their interactive state must survive reparsing. Render runs every frame.
func (*Doc) RenderedText ¶
RenderedText returns the selectable text from the most recently painted document. It is empty before the first frame. Block separators are included; decorations and custom code renderers are excluded. After changing source, wait for the next frame before using its offsets in the range APIs.
func (*Doc) RevealRange ¶
RevealRange requests minimum vertical scrolling to expose the line containing the range start in the nearest enclosing ScrollY. Empty ranges are allowed. True means the request was accepted, not that an ancestor can scroll. Only the latest request survives; source changes cancel it and it expires in 1s.
func (*Doc) SetRangeHighlights ¶
func (d *Doc) SetRangeHighlights(items []RangeHighlight) bool
SetRangeHighlights replaces all highlights, returning false without changing them if any range is invalid or the source has not yet been painted. Empty input always clears them. Changes preserve highlights wholly within the unchanged prefix or suffix; highlights touching replaced text are dropped.
func (*Doc) SetSource ¶
SetSource replaces the document. Unchanged leading chunks keep their parse. If the source changes, the selection is cleared; Append preserves it.
func (*Doc) SetStreaming ¶
SetStreaming marks whether text is still arriving: while it is, unfinished syntax at the end is closed provisionally and a caret shows. Set it to false when the answer is complete.
func (*Doc) ShowFrontMatter ¶
ShowFrontMatter shows the front matter as a table of its keys at the top of the document instead of hiding it.
func (*Doc) StreamFade ¶
StreamFade opts in to fading newly appended text over 350ms with cubic ease-out. Replacing content shows it immediately. Existing text, selection, search highlights and card controls do not fade. Reduced motion disables it.
func (*Doc) StreamFadeDuration ¶
StreamFadeDuration sets a duration from zero (instant) through ten seconds. Values outside that range are ignored. The default is 350ms.
type ImageLoader ¶
ImageLoader reads an image source off the UI thread.
type InlineObject ¶
InlineObject is an indivisible inline widget. Text supplies its selectable and copied representation and must be nonempty. The widget receives the remaining line width and wraps as a whole when it does not fit. Its bottom aligns with the text baseline. Keep application state in the widget itself.
type Plugin ¶
type Plugin struct {
Extensions []goldmark.Extender
Blocks map[ast.NodeKind]func(ast.Node, []byte) el.View
Inlines map[ast.NodeKind]func(ast.Node, []byte) InlineObject
}
Plugin extends one document's Goldmark parser and maps AST nodes to native views. Factories run during parsing, under the UI lock; treat node/source as read-only and do not mutate Doc. A nil block view or nil inline widget falls back to the built-in conversion. Later plugins win for duplicate node kinds. HTML conversion and fenced code contents are not passed through these maps.
type RangeHighlight ¶
RangeHighlight paints a background under text and beneath the selection. Later entries paint over earlier entries where their ranges overlap.