Contexts
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.
kind | Example (‸ is the cursor) | Offers |
|---|---|---|
block | /‸, /tab‸, empty line + Ctrl+Space | components, 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 component | slots of the innermost component |
props-key / props-value | inside --- under an opener | props as YAML keys, their values |
frontmatter-key / frontmatter-value | inside the leading --- | keys and values from frontmatterSchema |
fence-lang / fence-meta | ```‸, ```` ```ts | ```` |
fence-body | inside ```mermaid | the fence language's own items (mermaid, twoslash) |
emoji | :+1‸ | shortcodes with glyphs |
link-url | [x](‸, [x](#‸, , attributes, the closing tag |
math | $\fr‸, inside $$ | KaTeX commands |
inline | mid-line + Ctrl+Space | marks, 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.