From 9bc560b17f5131a6f143530d76d64d62237238ed Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 13 Feb 2026 09:37:34 +0100 Subject: [PATCH] fix: cleanup keybinding events --- packages/codemirror/codemirror.mjs | 9 +++++ packages/codemirror/index.mjs | 2 +- packages/codemirror/keybindings.mjs | 37 +++++-------------- .../src/repl/components/panel/SettingsTab.jsx | 7 +++- website/src/repl/prebakeCodeMirror.mjs | 3 +- 5 files changed, 25 insertions(+), 33 deletions(-) diff --git a/packages/codemirror/codemirror.mjs b/packages/codemirror/codemirror.mjs index 6014b9b0a..072752420 100644 --- a/packages/codemirror/codemirror.mjs +++ b/packages/codemirror/codemirror.mjs @@ -293,6 +293,9 @@ export class StrudelMirror { // Handle global evaluation requests (e.g., from Vim :w) this.onEvaluateRequest = (e) => { try { + if (e.detail.view !== this.editor) { + return; // ignore events from other editors + } // Evaluate current editor on repl-evaluate logger('[repl] evaluate via event'); this.evaluate(); @@ -307,6 +310,9 @@ export class StrudelMirror { // Toggle comments requested from Vim (gc) this.onToggleComment = (e) => { try { + if (e.detail.view !== this.editor) { + return; // ignore events from other editors + } // Honor selections; toggleLineComment handles both selections and // single line toggleLineComment(this.editor); @@ -347,6 +353,9 @@ export class StrudelMirror { // Listen for global stop requests (e.g., from Vim :q) onStopRequest = (e) => { try { + if (e.detail.view !== this.editor) { + return; // ignore events from other editors + } this.stop(); e?.cancelable && e.preventDefault?.(); } catch (err) { diff --git a/packages/codemirror/index.mjs b/packages/codemirror/index.mjs index ba1ae525f..31de6accb 100644 --- a/packages/codemirror/index.mjs +++ b/packages/codemirror/index.mjs @@ -4,5 +4,5 @@ export * from './flash.mjs'; export * from './slider.mjs'; export * from './themes.mjs'; export * from './widget.mjs'; +export { Vim } from './keybindings.mjs'; export * from './basicSetup.mjs'; -export { Vim, prebakeField } from './keybindings.mjs'; diff --git a/packages/codemirror/keybindings.mjs b/packages/codemirror/keybindings.mjs index 674216fb1..d8e888b8c 100644 --- a/packages/codemirror/keybindings.mjs +++ b/packages/codemirror/keybindings.mjs @@ -9,15 +9,6 @@ import { vscodeKeymap } from '@replit/codemirror-vscode-keymap'; import { helix, commands } from 'codemirror-helix'; import { logger } from '@strudel/core'; -export const prebakeField = StateField.define({ - create() { - return 'PrebakeEditor'; - }, - update(value, _tr) { - return value; - }, -}); - const vscodePlugin = ViewPlugin.fromClass( class { constructor() {} @@ -35,7 +26,10 @@ function replEval(view) { // Dispatch a dedicated evaluate event first let handled = false; try { - const ev = new CustomEvent('repl-evaluate', { detail: { source: 'vim', view }, cancelable: true }); + const ev = new CustomEvent('repl-evaluate', { + detail: { source: 'vim', view }, + cancelable: true, + }); handled = document.dispatchEvent(ev) === false; // false means preventDefault was called } catch (e) { console.error('Error dispatching repl-evaluate event', e); @@ -105,13 +99,11 @@ try { // internal actions and works with current selections/visual mode. try { Vim.defineAction('strudelToggleComment', (cm) => { - const view = cm?.view || cm; try { - const toggleEventName = - view?.cm6?.state?.field(prebakeField, false) !== undefined - ? 'prebake-toggle-comment' - : 'repl-toggle-comment'; - const ev = new CustomEvent(toggleEventName, { detail: { source: 'vim', view }, cancelable: true }); + const ev = new CustomEvent('repl-toggle-comment', { + detail: { source: 'vim', view: cm.cm6 }, + cancelable: true, + }); document.dispatchEvent(ev); } catch (e) { console.error('strudelToggleComment dispatch failed', e); @@ -132,17 +124,6 @@ try { // :w to evaluate Vim.defineEx('write', 'w', (cm) => { const view = cm?.view || cm; // CM6 Vim passes either an object with view or the view itself - const isPrebake = view?.cm6?.state?.field(prebakeField, false) !== undefined; - if (isPrebake) { - let prebakeEventHandled = false; - try { - const ev = new CustomEvent('prebake-evaluate', { detail: { source: 'vim', view }, cancelable: true }); - prebakeEventHandled = document.dispatchEvent(ev) === false; // false means preventDefault was called - return; - } catch (e) { - console.error('Error dispatching repl-evaluate event', e); - } - } try { view?.focus?.(); // Let the app know this came from Vim :w @@ -151,7 +132,7 @@ try { } catch (e) { console.error('Error logging Vim :w evaluation', e); } - replEval(view); + replEval(cm.cm6); } catch (e) { console.error('Error dispatching :w evaluation event', e); } diff --git a/website/src/repl/components/panel/SettingsTab.jsx b/website/src/repl/components/panel/SettingsTab.jsx index 8254a2e82..f640cd8c0 100644 --- a/website/src/repl/components/panel/SettingsTab.jsx +++ b/website/src/repl/components/panel/SettingsTab.jsx @@ -379,6 +379,9 @@ function PrebakeSettingsContent() { e?.cancelable && e.preventDefault?.(); }; const handleToggleComment = (e) => { + if (e.detail.view !== editorRef.current.view) { + return; // ignore events from other editors + } editorRef.current?.toggleComment(); e?.cancelable && e.preventDefault?.(); }; @@ -386,8 +389,8 @@ function PrebakeSettingsContent() { editorRef.current?.setCode(code); }; useEffect(() => { - document.addEventListener('prebake-evaluate', handleSaveEvent); - document.addEventListener('prebake-toggle-comment', handleToggleComment); + document.addEventListener('repl-evaluate', handleSaveEvent); + document.addEventListener('repl-toggle-comment', handleToggleComment); return () => { document.removeEventListener('prebake-evaluate', handleSaveEvent); document.removeEventListener('prebake-toggle-comment', handleToggleComment); diff --git a/website/src/repl/prebakeCodeMirror.mjs b/website/src/repl/prebakeCodeMirror.mjs index ddaf8708a..1423c1d33 100644 --- a/website/src/repl/prebakeCodeMirror.mjs +++ b/website/src/repl/prebakeCodeMirror.mjs @@ -4,7 +4,7 @@ import { defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language' import { Compartment, EditorState, Prec } from '@codemirror/state'; import { drawSelection, EditorView, keymap } from '@codemirror/view'; import { logger } from '@strudel/core'; -import { basicSetup, flash, prebakeField, initTheme, extensions, parseBooleans } from '@strudel/codemirror'; +import { basicSetup, flash, initTheme, extensions, parseBooleans } from '@strudel/codemirror'; export class PrebakeCodeMirror { constructor(initialCode, storePrebake, containerRef, editorRef, settings) { @@ -53,7 +53,6 @@ export class PrebakeCodeMirror { }, ]), ), - prebakeField, ], }); editorRef.current = state;