diff --git a/client/modules/IDE/components/Editor/stateUtils.js b/client/modules/IDE/components/Editor/stateUtils.js index 0605dd1b01..8d9e2eac7c 100644 --- a/client/modules/IDE/components/Editor/stateUtils.js +++ b/client/modules/IDE/components/Editor/stateUtils.js @@ -389,14 +389,22 @@ export function createNewFileState(filename, document, settings) { const autocompleteCpt = new Compartment(); // Depending on the file mode, we have a different tidier function. + // Keep this binding local to each file state so modes don't accumulate + // across files via a shared module-level array. const mode = getFileMode(filename); - extraKeymaps.push({ - key: `Shift-Mod-F`, - run: (cmView) => tidyCodeWithPrettier(cmView, mode) - }); + const fileTidyKeymap = [ + { + key: 'Shift-Mod-F', + run: (cmView) => { + tidyCodeWithPrettier(cmView, mode); + return true; + } + } + ]; const keymaps = [ extraKeymaps, + fileTidyKeymap, closeBracketsKeymap, defaultKeymap, historyKeymap, diff --git a/client/modules/IDE/components/Editor/stateUtils.test.js b/client/modules/IDE/components/Editor/stateUtils.test.js new file mode 100644 index 0000000000..e5d1aef5cb --- /dev/null +++ b/client/modules/IDE/components/Editor/stateUtils.test.js @@ -0,0 +1,62 @@ +/** + * @jest-environment jsdom + */ +import { EditorView, runScopeHandlers } from '@codemirror/view'; +import { createNewFileState } from './stateUtils'; + +const defaultSettings = { + linewrap: false, + lineNumbers: false, + autocomplete: false, + autocloseBracketsQuotes: false, + onUpdateLinting: () => {}, + onViewUpdate: () => {}, + referenceBaseUrl: 'https://p5js.org' +}; + +function mountFile(filename, doc) { + const { cmState } = createNewFileState(filename, doc, defaultSettings); + const parent = document.createElement('div'); + document.body.appendChild(parent); + const view = new EditorView({ state: cmState, parent }); + return view; +} + +function pressTidyShortcut(view) { + const event = new KeyboardEvent('keydown', { + key: 'F', + code: 'KeyF', + shiftKey: true, + ctrlKey: true + }); + runScopeHandlers(view, event, 'editor'); +} + +describe('createNewFileState — Tidy keyboard shortcut', () => { + afterEach(() => { + document.body.innerHTML = ''; + }); + + // Regression test for https://github.com/processing/p5.js-web-editor/issues/4093 + // Each file's Shift-Mod-F binding must only tidy with its own mode, regardless + // of the order in which the file states were created. + it('tidies each file with its own mode regardless of creation order', () => { + const jsView = mountFile('sketch.js', `function foo(){console.log("hi")}`); + const cssView = mountFile('style.css', `body{margin:0;padding:0;}`); + const htmlView = mountFile('index.html', `hello`); + + pressTidyShortcut(jsView); + pressTidyShortcut(cssView); + pressTidyShortcut(htmlView); + + expect(jsView.state.doc.toString()).toBe( + 'function foo() {\n console.log("hi");\n}\n' + ); + expect(cssView.state.doc.toString()).toBe( + 'body {\n margin: 0;\n padding: 0;\n}\n' + ); + expect(htmlView.state.doc.toString()).toBe( + '\n \n hello\n \n\n' + ); + }); +});