Skip to content

Commit bd83142

Browse files
committed
fix: scope CM6 Tidy keymap per file state (#4093)
createNewFileState mutated a module-scoped extraKeymaps array by pushing a Shift-Mod-F binding that closed over the current file's mode. Because the array was shared across every file's state, later-created files accumulated multiple tidy handlers — Cmd+Shift+F on a CSS/HTML file ran prettier with the JS parser first, either throwing or mangling output. Move the tidy binding into a per-state local array and return true from the handler so CM6 consumes the shortcut. Add a regression test that creates JS/CSS/HTML states in order and verifies each tidies with its own mode.
1 parent 4cdace3 commit bd83142

2 files changed

Lines changed: 74 additions & 4 deletions

File tree

client/modules/IDE/components/Editor/stateUtils.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -389,14 +389,22 @@ export function createNewFileState(filename, document, settings) {
389389
const autocompleteCpt = new Compartment();
390390

391391
// Depending on the file mode, we have a different tidier function.
392+
// Keep this binding local to each file state so modes don't accumulate
393+
// across files via a shared module-level array.
392394
const mode = getFileMode(filename);
393-
extraKeymaps.push({
394-
key: `Shift-Mod-F`,
395-
run: (cmView) => tidyCodeWithPrettier(cmView, mode)
396-
});
395+
const fileTidyKeymap = [
396+
{
397+
key: 'Shift-Mod-F',
398+
run: (cmView) => {
399+
tidyCodeWithPrettier(cmView, mode);
400+
return true;
401+
}
402+
}
403+
];
397404

398405
const keymaps = [
399406
extraKeymaps,
407+
fileTidyKeymap,
400408
closeBracketsKeymap,
401409
defaultKeymap,
402410
historyKeymap,
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* @jest-environment jsdom
3+
*/
4+
import { EditorView, runScopeHandlers } from '@codemirror/view';
5+
import { createNewFileState } from './stateUtils';
6+
7+
const defaultSettings = {
8+
linewrap: false,
9+
lineNumbers: false,
10+
autocomplete: false,
11+
autocloseBracketsQuotes: false,
12+
onUpdateLinting: () => {},
13+
onViewUpdate: () => {},
14+
referenceBaseUrl: 'https://p5js.org'
15+
};
16+
17+
function mountFile(filename, doc) {
18+
const { cmState } = createNewFileState(filename, doc, defaultSettings);
19+
const parent = document.createElement('div');
20+
document.body.appendChild(parent);
21+
const view = new EditorView({ state: cmState, parent });
22+
return view;
23+
}
24+
25+
function pressTidyShortcut(view) {
26+
const event = new KeyboardEvent('keydown', {
27+
key: 'F',
28+
code: 'KeyF',
29+
shiftKey: true,
30+
ctrlKey: true
31+
});
32+
runScopeHandlers(view, event, 'editor');
33+
}
34+
35+
describe('createNewFileState — Tidy keyboard shortcut', () => {
36+
afterEach(() => {
37+
document.body.innerHTML = '';
38+
});
39+
40+
// Regression test for https://github.com/processing/p5.js-web-editor/issues/4093
41+
// Each file's Shift-Mod-F binding must only tidy with its own mode, regardless
42+
// of the order in which the file states were created.
43+
it('tidies each file with its own mode regardless of creation order', () => {
44+
const jsView = mountFile('sketch.js', `function foo(){console.log("hi")}`);
45+
const cssView = mountFile('style.css', `body{margin:0;padding:0;}`);
46+
const htmlView = mountFile('index.html', `<html><body>hello</body></html>`);
47+
48+
pressTidyShortcut(jsView);
49+
pressTidyShortcut(cssView);
50+
pressTidyShortcut(htmlView);
51+
52+
expect(jsView.state.doc.toString()).toBe(
53+
'function foo() {\n console.log("hi");\n}\n'
54+
);
55+
expect(cssView.state.doc.toString()).toBe(
56+
'body {\n margin: 0;\n padding: 0;\n}\n'
57+
);
58+
expect(htmlView.state.doc.toString()).toBe(
59+
'<html>\n <body>\n hello\n </body>\n</html>\n'
60+
);
61+
});
62+
});

0 commit comments

Comments
 (0)