Repository navigation
feat(editor): add experimental canvas renderer - #2988
Merged
Merged
Conversation
Resolve canvas-view's imports (and their types) from Acode's own node_modules, so CodeMirror's state and view stay single instances.
Renderer: DOM (default) or Canvas (experimental), applied on reload.
With editorRenderer set to canvas, editors are @acode/canvas-view CanvasViews. Settings that the DOM editor applies through extensions (line numbers, folding, guides, rainbow brackets, whitespace, wrapping, scroll past end, RTL) become canvas options, kept in sync on changes. Themes map to a CanvasThemeSpec (config colors + the theme's HighlightStyle). The selection menu is driven by the view's touch selection hooks, reusing the existing menu UI.
…erer The canvas renderer draws its own fold markers, but foldGutter() was still in the state, and its markers plugin rebuilt (unused) markers for the viewport on every update and tab switch. Canvas views now get only the folding state (codeFolding) with indentation folding.
isViewEditable read contentDOM's contenteditable and aria-readonly attributes. A canvas view's contentDOM is its hidden input element, which has neither, so taps on color chips (regex and LSP document colors) were swallowed as if the editor were read-only. Read the state's editable and readOnly facets instead, which is what the DOM editor's attributes reflect. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Acode's read-only setup works around the DOM editor on mobile: it makes the content non-editable, blurs on every focus so no keyboard opens, and shows CodeMirror's cursor layer with CSS. A canvas view handles read-only documents itself: it ignores typing, cut, paste and drops, takes focus with inputmode="none" (so its cursor blinks and hardware shortcuts work, without a keyboard), and drops focus when it becomes read-only. For canvas views the extension is now only EditorState.readOnly plus the filter for Acode's own editing commands, and blurEditorIfReadOnly / focusEditorIfEditable leave them focused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the canvas renderer: - highlightSelectionMatches is on (it's off by default for the DOM editor), drawn with the theme's selectionMatch color, or its selection color, as the themes' CSS does; - indent guides highlight the block around the cursor (one rect per frame on the canvas); - the base extensions leave out drawSelection, dropCursor, highlightActiveLine (and its gutter) and highlightSpecialChars, which the canvas draws itself. The canvas view only skipped their plugins; the active line gutter still rebuilt its markers on every selection change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On touch devices the LSP linter drops every in-text mark (markerFilter), so only the lint gutter showed an error. Canvas views draw the wavy underlines and lint points natively, without the DOM editor's layout cost, so they keep them; hover tooltips stay filtered on touch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ColorChipWidget gets toCanvas(): the same box toDOM styles (0.9em, 2px margins, rounded, a faint border), in cells of the view's font. Canvas views then make no element per chip; they call toDOM only when a chip is tapped, so the color picker still opens. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The font theme set `lineHeight` on the editor element, but CodeMirror's base theme sets `line-height: 1.4` on `.cm-scroller`, so the setting never reached the lines or gutters: the DOM editor was always 1.4 while canvas views used the setting, and the two renderers didn't match. Set it on `.cm-scroller`, so both renderers use it (canvas-view measures it like CodeMirror, to the DOM's exact value). The default becomes 1.4, what the editor always showed, and stored values of the old default (2), which nobody ever saw, are migrated once so editors don't change size.
Two settings for the canvas renderer, next to "Renderer": - "Canvas backend": Auto (WebGL2), WebGL2 or WebGPU (falls back to WebGL2 where unavailable). Views are created with it, so a change asks to reload when the canvas renderer is on. - "Sticky scroll": keeps the header lines of the scopes around the top line pinned while scrolling. Applies live to canvas views.
canvas-view is now published as @acode.app/canvas-view, so depend on it instead of a local `bun link` checkout and drop the rspack and tsconfig workarounds that kept the linked copy on Acode's CodeMirror packages. Raise @codemirror/view, state, language and @lezer/common to the versions canvas-view requires, in dependencies and overrides, so a single copy of each is installed. The newer view flushes on every selectionchange, and happy-dom fires that event synchronously from Selection methods, which re-entered EditorView.update in the read-only cursor test. Queue it there like a browser does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bajrangCoder
force-pushed
the
feat/canvas-renderer
branch
from
October 25, 2026 04:53
02b324d to
69265c8
Compare
# Conflicts: # bun.lock # package-lock.json # package.json
Contributor
[Medium impact] The PR appears safe to merge; no new actionable issues were established. SummaryAdds an opt-in canvas editor while keeping DOM as the default.
Diagram%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Saved renderer setting] --> B{Canvas selected and supported?}
B -->|No| C[Create DOM editor]
B -->|Yes| D[Create canvas editor]
D --> E{Construction succeeds?}
E -->|Yes| F[Sync themes, fonts and display options]
E -->|No| G[Rebuild DOM state]
G --> C
Reviews (3) · Last reviewed commit: "feat(settings): more canvas renderer set..." · Reviewed by Greptile |
- Flush pending cache writes and save the session before the reload that applies a renderer or canvas backend change, as the pause handler does, so recent edits aren't lost. - Include the renderer in the editor state signature, and give the DOM fallback pane a fresh empty state, so states built for canvas views (without fold controls and the active line) aren't reused by DOM ones. - Declare the canvas backend and sticky scroll strings in LangStrings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This comment was marked as outdated.
This comment was marked as outdated.
bajrangCoder
force-pushed
the
feat/canvas-renderer
branch
from
October 25, 2026 05:08
32ea647 to
e25e4ef
Compare
- Cursor blink rate, sticky scroll max lines and gutter marker layout (shared column, column per gutter, over line numbers), mapped to the matching canvas-view options and applied live. - Bring back the scroll speed setting, which canvas views use. - Canvas-only settings (backend, sticky scroll, its max lines, gutter markers, cursor blink rate, scroll speed) are listed only while the canvas renderer is selected, and follow renderer changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bajrangCoder
force-pushed
the
feat/canvas-renderer
branch
from
October 25, 2026 05:09
e25e4ef to
2b26422
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
@codemirror/view,stateandlanguageto the versions canvas-view requires, so a single copy of each is installed.