Conversation
There was a problem hiding this comment.
Pull request overview
Adds initial semantic-token-based highlighting support (aimed at Lean) and makes static syntax highlighting optional so it can be disabled for languages that rely on LSP tokens.
Changes:
- Add editor APIs to set/clear semantic tokens and distribute them to embedded CodeMirror code blocks.
- Introduce a CodeMirror extension that stores semantic tokens and renders them via decorations + a semantic token theme.
- Update CodeBlockView theme handling (base theme compartment) and make
LanguageConfigurationhighlight styles optional.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
src/mapping/mapping.ts |
Tightens offset→ProseMirror mapping by rejecting offsets outside block content regions. |
src/editor.ts |
Adds semantic token entry points and routes tokens into the correct code block nodeviews. |
src/codeview/semantic-highlighting.ts |
New CodeMirror StateField/ViewPlugin to render semantic token decorations and a theme. |
src/codeview/nodeview.ts |
Integrates semantic-highlighting extension into code blocks; refactors theme handling with compartments. |
src/codeview/color-scheme.ts |
Makes the base CodeMirror theme depend on light/dark mode via a factory function. |
src/api/types.ts |
Makes static highlight styles optional and adds semantic token types/interfaces to the public API. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| public setSemanticTokens(tokens: OffsetSemanticToken[]) { | ||
| const mapping = this._mapping; | ||
| if (!mapping || !this._view) return; | ||
|
|
||
| const nodeViews = CODE_PLUGIN_KEY.getState(this._view.state)?.activeNodeViews; | ||
| if (!nodeViews) return; | ||
|
|
||
| const blocks = Array.from(nodeViews).flatMap(nodeView => { | ||
| const pos = nodeView._getPos(); | ||
| if (pos === undefined) return []; | ||
|
|
||
| // + 1 to get the position after the opening node, where the content starts | ||
| const start = pos + 1; | ||
| const end = start + nodeView.documentLength; | ||
| return [{ nodeView, start, end }]; | ||
| }); | ||
|
|
||
| const buckets = new Map(blocks.map(block => [block.nodeView, [] as OffsetSemanticToken[]])); | ||
|
|
||
| const mappedTokens = tokens.flatMap(token => { | ||
| try { | ||
| return [{ | ||
| token, | ||
| from: mapping.textOffsetToPmIndex(token.startOffset), | ||
| to: mapping.textOffsetToPmIndex(token.endOffset) | ||
| }]; | ||
| } catch { return []; } // token outside any mapped region, skip | ||
| }) | ||
|
|
||
| for (const { token, from, to } of mappedTokens) { | ||
| const block = blocks.find(b => from >= b.start && to <= b.end); | ||
| if (!block) continue; // token outside any block, skip | ||
|
|
||
| buckets.get(block.nodeView)!.push({ | ||
| startOffset: from - block.start, | ||
| endOffset: to - block.start, | ||
| type: token.type, | ||
| }); | ||
| } | ||
|
|
||
| for (const [nodeView, localTokens] of buckets) { | ||
| nodeView.updateSemanticTokens(localTokens); | ||
| } | ||
| } |
There was a problem hiding this comment.
This PR introduces a new public surface (setSemanticTokens / clearSemanticTokens) and non-trivial mapping/bucketing logic, but there are currently no tests covering token distribution into CodeMirror nodeviews and decoration updates. Adding Jest coverage (similar to existing diagnostics/nodeview tests) would help prevent regressions (e.g. off-by-one mapping, tokens leaking across blocks, clearing behavior on doc edits).
Description
Implements the basics of semantic highlighting and removes static syntax highlighting for lean.
Testing this PR
Use the waterproof-genre repository to test it. But currently a specific version is required.
Related to: impermeable/waterproof-vscode#330