diff --git a/packages/codemirror/codemirror.mjs b/packages/codemirror/codemirror.mjs index 5886c4769..42aaaae93 100644 --- a/packages/codemirror/codemirror.mjs +++ b/packages/codemirror/codemirror.mjs @@ -24,6 +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 { prettierPlugin } from './prettier.mjs'; const extensions = { isLineWrappingEnabled: (on) => (on ? EditorView.lineWrapping : []), @@ -77,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), diff --git a/packages/codemirror/package.json b/packages/codemirror/package.json index 5ef5e73b0..5c22c1d3d 100644 --- a/packages/codemirror/package.json +++ b/packages/codemirror/package.json @@ -49,7 +49,8 @@ "@strudel/transpiler": "workspace:*", "@uiw/codemirror-themes": "^4.21.21", "@uiw/codemirror-themes-all": "^4.21.21", - "nanostores": "^0.9.5" + "nanostores": "^0.9.5", + "prettier": "^3.3.3" }, "devDependencies": { "vite": "^5.0.10" 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, + }, +]); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a18f06e73..ebcf7a8c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -212,6 +212,9 @@ importers: nanostores: specifier: ^0.9.5 version: 0.9.5 + prettier: + specifier: ^3.3.3 + version: 3.3.3 devDependencies: vite: specifier: ^5.0.10 @@ -7740,6 +7743,7 @@ packages: workbox-google-analytics@7.0.0: resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==} + deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained workbox-navigation-preload@7.0.0: resolution: {integrity: sha512-juWCSrxo/fiMz3RsvDspeSLGmbgC0U9tKqcUPZBCf35s64wlaLXyn2KdHHXVQrb2cqF7I0Hc9siQalainmnXJA==}