Two e2e tests:
- test_blueprint_autocomplete_accept_writes_into_hidden_textarea:
loads /blueprints/1, types 'sv_che', asserts the cm6 autocomplete
popup shows 'sv_cheats', presses Tab to accept, fires a synthetic
submit on the form, and reads the hidden textarea value back.
Exercises both the autocomplete extension and the submit-time copy
bridge in editor.js end-to-end.
- test_copy_preserves_newlines_across_lines: regression gate for
bug class 1 from v1 (Prism+contenteditable collapsed multi-line
selections). cm6 preserves linebreaks in its doc by construction;
we verify via the per-textarea controller's getValue().
editor-entry.js: discovered during the e2e debug that cm6's default
completionKeymap does NOT bind Tab. Added an explicit
`{ key: "Tab", run: acceptCompletion }` ahead of the rest of the
keymap stack so Tab accepts when the popup is open and falls through
to indentWithTab otherwise. Bundle rebuilt + SHA refreshed.
Tests also surfaced a 200ms popup-settle timing race: the popup is
*visible* on the same tick acceptCompletion runs against null
selectedCompletion. A page.wait_for_timeout(200) before pressing
the accept key bridges the gap reliably in CI.
Chromium runs fine in Claude Code's default sandbox — the stale note
in the handoff doc about Mach-port IPC sandbox-blocking is no longer
accurate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the Task 1 stub. Builds an EditorView with:
- history, line numbers, active-line highlight, bracket matching,
close brackets, indent-on-input
- default + custom HighlightStyle
- light/dark theme via matchMedia-driven Compartment with a
prefers-color-scheme change listener
- language via Compartment (swappable for the files-modal dropdown)
- autocomplete via Compartment (only if vocab is provided)
- keymap stack: closeBrackets, default, history, completion, indentWithTab
Mounts the EditorView immediately before the textarea, hides the
textarea. Exposes window.__editor.mount(textarea, opts) returning a
controller with getValue / setContent / setLanguage / destroy.
bash language comes via @codemirror/legacy-modes/mode/shell wrapped
in StreamLanguage.define — same mechanism as srccfg.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CompletionSource over the srccfg-vocab.json shape. Word fragment
matched via /[A-Za-z0-9_]{2,}/ at the caret; ranking is
prefix-match-first (shorter prefixes preferred) then substring;
cap 50 candidates, top 8 rendered. Each option carries the kind
('cvar'/'command') as cm6's autocomplete `type` so the popup
shows the appropriate icon.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
themes.js exports four extensions:
- editorLightTheme / editorDarkTheme: EditorView.theme() variants
keyed to the --cm-* CSS variables defined in tokens.css (light) and
its prefers-color-scheme: dark block.
- editorHighlightStyle: HighlightStyle bound to Lezer tags
(comment, string, number, keyword, variableName).
- editorHighlighting: syntaxHighlighting(editorHighlightStyle) ready
to drop into the EditorState extensions array.
@lezer/highlight comes in transitively via @codemirror/language;
no new package.json dependency needed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
~30 LOC StreamLanguage definition for Source-engine .cfg syntax.
Tokens: line comment (//…), string, number, keyword (exec/alias/bind/
unbindall/wait), identifier. Linewise, no nesting — matches the
shape we authored as a Prism regex grammar in the v1 attempt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>