diff --git a/packages/codemirror/codemirror.mjs b/packages/codemirror/codemirror.mjs index 22335a12b..42aaaae93 100644 --- a/packages/codemirror/codemirror.mjs +++ b/packages/codemirror/codemirror.mjs @@ -24,10 +24,7 @@ import { initTheme, activateTheme, theme } from './themes.mjs'; import { sliderPlugin, updateSliderWidgets } from './slider.mjs'; import { widgetPlugin, updateWidgets } from './widget.mjs'; import { persistentAtom } from '@nanostores/persistent'; -import * as prettier from 'prettier/standalone'; -import typescriptPlugin from 'prettier/plugins/typescript'; -import estreePlugin from 'prettier/plugins/estree'; -import { EditorSelection } from '@codemirror/state'; +import { prettierPlugin } from './prettier.mjs'; const extensions = { isLineWrappingEnabled: (on) => (on ? EditorView.lineWrapping : []), @@ -81,6 +78,7 @@ export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, roo javascript(), sliderPlugin, widgetPlugin, + prettierPlugin, // indentOnInput(), // works without. already brought with javascript extension? // bracketMatching(), // does not do anything syntaxHighlighting(defaultHighlightStyle), @@ -106,42 +104,6 @@ export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, roo preventDefault: true, run: () => onStop?.(), }, - { - key: 'Ctrl-\\', - preventDefault: true, - run: async (editorView) => { - const currentState = editorView.state.doc.toString(); - - // Prettier insists on consistent quotes, but in Strudel double quotes are interpreted - // as patterns and single quotes are for everything else, so a consistent setting won't work. - // It's a great formatter though, so as a workaround it works to put "// prettier-ignore" comments - // before the single quoted stuff to preserve it, but this is a pain to make users to, so an extra - // hack is to take the preformatted code, insert these comments behind the scenes, format, then - // remove them before setting the editor state. - const preFormat = currentState - .split('\n') - .map((line) => (line.match(/\'.*\'/) != null ? '// prettier-ignore\n' + line : line)) - .join('\n'); - console.log(preFormat); - const formattedState = ( - await prettier.format(preFormat, { - parser: 'typescript', - plugins: [typescriptPlugin, estreePlugin], - semi: false, - }) - ).replace(/.*\/\/ prettier-ignore.*\n/g, ''); - - editorView.dispatch({ - changes: { from: 0, to: editorView.state.doc.length, insert: formattedState }, - selection: EditorSelection.single( - // keep cursor close to the original position, but also keep it within the bounds - // of the formatted document - Math.min(editorView.state.selection.main.to, formattedState.length), - ), - scrollIntoView: true, - }); - }, - }, /* { key: 'Ctrl-Shift-.', run: () => (onPanic ? onPanic() : onStop?.()), diff --git a/packages/codemirror/prettier.mjs b/packages/codemirror/prettier.mjs new file mode 100644 index 000000000..081ee0624 --- /dev/null +++ b/packages/codemirror/prettier.mjs @@ -0,0 +1,55 @@ +import { EditorSelection } from '@codemirror/state'; +import * as prettier from 'prettier/standalone'; +import typescriptPlugin from 'prettier/plugins/typescript'; +import estreePlugin from 'prettier/plugins/estree'; +import { keymap } from '@codemirror/view'; + +export async function runPrettier(editorView) { + const currentState = editorView.state.doc.toString(); + // Prettier insists on consistent quotes, but in Strudel double quotes are interpreted + // as patterns and single quotes are for everything else, so a consistent setting won't work. + // It's a great formatter though, so as a workaround it works to put "// prettier-ignore" comments + // before the single quoted stuff to preserve it, but this is a pain to make users to, so an extra + // hack is to take the preformatted code, insert these comments behind the scenes, format, then + // remove them before setting the editor state. + const preFormat = currentState + .split('\n') + .map((line) => (line.match(/'.*'/) != null ? '// prettier-ignore\n' + line : line)) + .join('\n'); + console.log(preFormat); + const formattedState = ( + await prettier.format(preFormat, { + parser: 'typescript', + plugins: [typescriptPlugin, estreePlugin], + semi: false, + }) + ).replace(/.*\/\/ prettier-ignore.*\n/g, ''); + + editorView.dispatch({ + changes: { from: 0, to: editorView.state.doc.length, insert: formattedState }, + selection: EditorSelection.single( + // keep cursor close to the original position, but also keep it within the bounds + // of the formatted document + Math.min(editorView.state.selection.main.to, formattedState.length), + ), + scrollIntoView: true, + }); +} + +export const prettierPlugin = keymap.of([ + { + key: 'Alt-,', + preventDefault: true, + run: runPrettier, + }, + { + key: 'Ctrl-,', + preventDefault: true, + run: runPrettier, + }, + { + key: 'Alt-Shift-f', + preventDefault: true, + run: runPrettier, + }, +]);