Autocomplete

Contexts

Every place the editor completes, and how coverage is measured.

resolveContext(state, pos) decides what the cursor is on. It reads the document index (frontmatter, props blocks, fences, math, the component stack) and the syntax tree (code spans, comments), then scans the line prefix — which works on incomplete input like ::card{ti. Completion, hover, lint fixes and agents all use it.

kindExample (‸ is the cursor)Offers
block/‸, /tab‸, empty line + Ctrl+Spacecomponents, slots of the current component, structure, callouts, code, plugin snippets
component-name::ca‸, :::‸, Hello :ba‸block or inline components, closer of the open component, names used in the document
attr-key::card{‸}, #footer{‸}, [text]{‸}props (:/:: switch to bound and model props), .class, #id, style, owner-specific attributes
attr-value::card{variant="‸"}enum values, booleans, the default, values used elsewhere
attr-class / attr-id{.‸}, {#‸}classes used in the document, heading ids
binding-path{{ ‸, :title="frontmatter.‸"roots, then keys of the shape at the path
binding-default{{ path ‸`
slot#‸ in a componentslots of the innermost component
props-key / props-valueinside --- under an openerprops as YAML keys, their values
frontmatter-key / frontmatter-valueinside the leading ---keys and values from frontmatterSchema
fence-lang / fence-meta```‸, ```` ```ts````
fence-bodyinside ```mermaidthe fence language's own items (mermaid, twoslash)
emoji:+1‸shortcodes with glyphs
link-url[x](‸, [x](#‸, ![x](‸pages, heading anchors, assets
footnote[^‸defined ids, or a new footnote
alert> [!‸alert types
task- [‸[ ], [x]
html-tag / html-attr<‸, <a ‸tags (minus blocked ones), attributes, the closing tag
math$\fr‸, inside $$KaTeX commands
inlinemid-line + Ctrl+Spacemarks, link, image, span, binding, math

The context type is exported (CursorContext, ContextKind), and plugins register providers by kind.

Measured coverage

"Autocomplete everything" is a test. For every completable token in comark's own SPEC fixtures — component names, props, values, slots, YAML prop keys, binding segments, emoji, alert types, fence languages, task boxes — the test puts the cursor where the token starts and asks complete(). The real token must be in the menu. Each fixture runs with a manifest derived from what it uses, the way a host's manifest would describe its components.

Current result: 399 of 399 tokens. A second test completes at 1,500 random positions across all fixtures and must never throw.

The same fixtures check the grammar: all 228 parse, and every block comark reports ends where the editor's syntax tree and outline end a block.

Copyright © 2026