From a60a54147cb9fe18731d94d66590395216da572b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Bj=C3=B6rk?= Date: Sat, 7 Feb 2026 23:15:12 +0100 Subject: [PATCH] Moved PrebakeCodeMirror to its own file --- packages/codemirror/codemirror.mjs | 86 +----------------- packages/codemirror/index.mjs | 1 + .../src/repl/components/panel/SettingsTab.jsx | 6 +- website/src/repl/prebakeCodeMirror.mjs | 91 +++++++++++++++++++ 4 files changed, 96 insertions(+), 88 deletions(-) create mode 100644 website/src/repl/prebakeCodeMirror.mjs diff --git a/packages/codemirror/codemirror.mjs b/packages/codemirror/codemirror.mjs index 558cf7710..5ce99ba12 100644 --- a/packages/codemirror/codemirror.mjs +++ b/packages/codemirror/codemirror.mjs @@ -19,7 +19,7 @@ import { basicSetup } from './basicSetup.mjs'; import { evalBlock } from './block_utilities.mjs'; import { flash, isFlashEnabled } from './flash.mjs'; import { highlightMiniLocations, isPatternHighlightingEnabled, updateMiniLocations } from './highlight.mjs'; -import { keybindings, prebakeField } from './keybindings.mjs'; +import { keybindings } from './keybindings.mjs'; import { jumpToCharacter } from './labelJump.mjs'; import { getSliderWidgets, sliderPlugin, updateSliderWidgets } from './slider.mjs'; import { activateTheme, initTheme, theme } from './themes.mjs'; @@ -476,90 +476,6 @@ export class StrudelMirror { } } -export class PrebakeCodeMirror { - constructor(initialCode, storePrebake, containerRef, editorRef, settings) { - this.storePrebake = storePrebake; - const compartments = Object.fromEntries(Object.keys(extensions).map((key) => [key, new Compartment()])); - const initialSettings = Object.keys(compartments).map((key) => - compartments[key].of(extensions[key](parseBooleans(settings[key]))), - ); - initTheme(settings.theme); - let state = EditorState.create({ - doc: initialCode, - extensions: [ - ...initialSettings, - basicSetup, - javascript(), - javascriptLanguage.data.of({ - closeBrackets: { brackets: ['(', '[', '{', "'", '"', '<'] }, - bracketMatching: { brackets: ['(', '[', '{', "'", '"', '<'] }, - }), - syntaxHighlighting(defaultHighlightStyle), - EditorView.updateListener.of((v) => { - if (v.docChanged) { - this.code = v.state.doc.toString(); - } - }), - drawSelection({ cursorBlinkRate: 0 }), - Prec.highest( - keymap.of([ - { - mac: 'Meta-Enter', - run: () => { - this.savePrebake(); - }, - }, - { - key: 'Ctrl-Enter', - run: () => { - this.savePrebake(); - }, - }, - { - key: 'Alt-Enter', - run: () => { - this.savePrebake(); - }, - }, - ]), - ), - prebakeField, - ], - }); - editorRef.current = state; - this.code = initialCode; - this.view = new EditorView({ - state, - parent: containerRef.current, - }); - } - - async savePrebake() { - flash(this.view); - this.storePrebake(this.code); - logger('[prebake] prebake saved'); - } - - toggleComment() { - try { - // Honor selections; toggleLineComment handles both selections and - // single line - toggleLineComment(this.view); - } catch (err) { - console.error('Error handling repl-toggle-comment event', err); - } - } - - setCode(code) { - const changes = { - from: 0, - to: this.view.state.doc.length, - insert: code, - }; - this.view.dispatch({ changes }); - } -} - export function parseBooleans(value) { return { true: true, false: false }[value] ?? value; } diff --git a/packages/codemirror/index.mjs b/packages/codemirror/index.mjs index ea78f8221..ba1ae525f 100644 --- a/packages/codemirror/index.mjs +++ b/packages/codemirror/index.mjs @@ -4,4 +4,5 @@ export * from './flash.mjs'; export * from './slider.mjs'; export * from './themes.mjs'; export * from './widget.mjs'; +export * from './basicSetup.mjs'; export { Vim, prebakeField } from './keybindings.mjs'; diff --git a/website/src/repl/components/panel/SettingsTab.jsx b/website/src/repl/components/panel/SettingsTab.jsx index ccc7bc71f..8254a2e82 100644 --- a/website/src/repl/components/panel/SettingsTab.jsx +++ b/website/src/repl/components/panel/SettingsTab.jsx @@ -1,16 +1,16 @@ import { defaultSettings, settingsMap, useSettings, storePrebakeScript, setSettingsTab } from '../../../settings.mjs'; -import { themes, codemirrorSettings, PrebakeCodeMirror } from '@strudel/codemirror'; +import { themes, codemirrorSettings } from '@strudel/codemirror'; +import { PrebakeCodeMirror } from '../../../repl/prebakeCodeMirror.mjs'; import { confirmAndReloadPage, isUdels } from '../../util.mjs'; import { ButtonGroup } from './Forms.jsx'; import { AudioDeviceSelector } from './AudioDeviceSelector.jsx'; import { AudioEngineTargetSelector } from './AudioEngineTargetSelector.jsx'; import { confirmDialog } from '../../util.mjs'; import { DEFAULT_MAX_POLYPHONY, setMaxPolyphony, setMultiChannelOrbits } from '@strudel/webaudio'; -import { ActionButton, IconButton, SpecialActionButton } from '../button/action-button.jsx'; +import { ActionButton, SpecialActionButton } from '../button/action-button.jsx'; import { exportScript, ImportPrebakeScriptButton } from './ImportPrebakeScriptButton.jsx'; import { useCallback, useEffect, useRef } from 'react'; import { Code } from '../Code.jsx'; -import { DocumentArrowUpIcon, DocumentCheckIcon } from '@heroicons/react/16/solid'; function cx(...classes) { // : Array diff --git a/website/src/repl/prebakeCodeMirror.mjs b/website/src/repl/prebakeCodeMirror.mjs new file mode 100644 index 000000000..e40aaae90 --- /dev/null +++ b/website/src/repl/prebakeCodeMirror.mjs @@ -0,0 +1,91 @@ +import { toggleLineComment } from '@codemirror/commands'; +import { javascript, javascriptLanguage } from '@codemirror/lang-javascript'; +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 } from '@strudel/codemirror'; + +export class PrebakeCodeMirror { + constructor(initialCode, storePrebake, containerRef, editorRef, settings) { + this.storePrebake = storePrebake; + const compartments = Object.fromEntries(Object.keys(extensions).map((key) => [key, new Compartment()])); + const initialSettings = Object.keys(compartments).map((key) => + compartments[key].of(extensions[key](parseBooleans(settings[key]))), + ); + initTheme(settings.theme); + let state = EditorState.create({ + doc: initialCode, + extensions: [ + ...initialSettings, + basicSetup, + javascript(), + javascriptLanguage.data.of({ + closeBrackets: { brackets: ['(', '[', '{', "'", '"', '<'] }, + bracketMatching: { brackets: ['(', '[', '{', "'", '"', '<'] }, + }), + syntaxHighlighting(defaultHighlightStyle), + EditorView.updateListener.of((v) => { + if (v.docChanged) { + this.code = v.state.doc.toString(); + } + }), + drawSelection({ cursorBlinkRate: 0 }), + Prec.highest( + keymap.of([ + { + mac: 'Meta-Enter', + run: () => { + this.savePrebake(); + }, + }, + { + key: 'Ctrl-Enter', + run: () => { + this.savePrebake(); + }, + }, + { + key: 'Alt-Enter', + run: () => { + this.savePrebake(); + }, + }, + ]), + ), + prebakeField, + ], + }); + editorRef.current = state; + this.code = initialCode; + this.view = new EditorView({ + state, + parent: containerRef.current, + }); + } + + async savePrebake() { + flash(this.view); + this.storePrebake(this.code); + logger('[prebake] prebake saved'); + } + + toggleComment() { + try { + // Honor selections; toggleLineComment handles both selections and + // single line + toggleLineComment(this.view); + } catch (err) { + console.error('Error handling repl-toggle-comment event', err); + } + } + + setCode(code) { + const changes = { + from: 0, + to: this.view.state.doc.length, + insert: code, + }; + this.view.dispatch({ changes }); + } +}