CodeMirror
@mudomi/onykia-codemirror
are the CodeMirror 6 bindings for the engine.
CodeMirror 6 is a peer dependency - install the modules you use
(@codemirror/view, @codemirror/state, @codemirror/commands,
@codemirror/lint, @codemirror/language, @codemirror/autocomplete,
@lezer/highlight).
Setup
typstExtensions(core, path) assembles the full feature set for one file and
returns { extensions }. It is async because syntax highlighting fetches the
compiler's tag table once.
typstExtensions includes a forwardEdits extension, so every keystroke is
turned into a core.edit() delta automatically - you do not diff the document
yourself. The engine recompiles and emits fresh pages/diagnostics.
What typstExtensions enables
Each feature can be toggled via the options argument; all default to on.
For definition you can pass handlers instead of true to control how
cross-file or URL jumps are resolved:
Folding
folding supplies fold ranges for code blocks and heading sections. To show the
controls, add CodeMirror's own gutter:
Diagnostics
Diagnostics are deliberately left out of typstExtensions so the editor owns
them explicitly. Two entry points:
diagnosticsSubscription(core, view, path)- subscribes toonDiagnosticsand applies them; returns an unsubscribe function.applyDiagnostics(view, diagnostics, path)- apply one batch yourself if you already manage the subscription.
Both convert the engine's byte offsets to CodeMirror positions and drop
diagnostics that belong to package dependencies or other files. To stop
diagnostics flickering over a region the user just edited, add
modificationTracker(path) to your extensions; tune the window with
{ suppressEditedWithinMs } (default 250).
Collaborative editing (Yjs / Automerge)
Keep forwardEdits on when CodeMirror is the source of truth. With a CRDT,
it depends on how changes are applied:
- If the CRDT binding applies local and remote changes as CodeMirror
transactions (the usual Yjs setup),
forwardEditsstill sees every mutation - leave it on. - Otherwise, disable
forwardEditsand drivepushEditToCorefrom the CRDT, so engine state follows the CRDT rather than the editor.
pushEditToCore and forwardEdits share one per-path queue, so
pendingEdit(path) resolves once in-flight edits have applied.
Composing extensions individually
If you don't want the bundle, import the pieces:
highlightExtension(core, path, options) is async (it loads the tag table);
the rest are synchronous and take (core, path).
Extras
- Spellcheck -
spellcheckExtension(...)pluswireCoreSpellcheck(core, ...)delegate spell checking to a JSSpellCheckeryou provide (the engine ships no built-in dictionary). - Collaborative cursors -
awarenessCursorExtension({ ... })renders remote cursors from an awareness transport (e.g. a CRDT presence channel). - Drag & drop -
dropFileExtension({ ... })resolves dropped files and writes them into the VFS via yourDropResolver.