Skip to content

Commit 1120c2b

Browse files
authored
fix: Upgrade Monaco to ^0.41.0 (#1448)
Fixes #1445, fixes #1191 Fixing Monaco bug by upgrading to latest ^0.41.0 Supports DH-15438 BREAKING CHANGE: Monaco will need to be upgraded to ^0.41.0 in Enterprise to ensure compatibility **Tests Performed** - Console Input - `Cmd+F` does nothing - Intellisense can be closed via `Esc` - Log tab - `Esc` does not close find input - `Esc` does clear selection when focus is in the log content - Code Editor - Verified that newline with leading space no longer crashes the browser tab ``` a a ``` - Wrote some Python code. Intellisense, syntax highlighting, and general typing experience seemed as expected - Execute full code + selected code successfully
1 parent 6d2cb06 commit 1120c2b

13 files changed

Lines changed: 178 additions & 129 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ We use [Playwright](https://playwright.dev/) for end-to-end tests. We test again
100100

101101
You should be able to pass arguments to these commands as if you were running Playwright via CLI directly. For example, to test only `table.spec.ts` you could run `npm run e2e -- ./tests/table.spec.ts`, or to test only `table.spec.ts` in Firefox, you could run `npm run e2e -- --project firefox ./tests/table.spec.ts`. See [Playwright CLI](https://playwright.dev/docs/test-cli) for more details.
102102

103-
Snapshots are used by end-to-end tests to visually verify the output. Snapshots are both OS and broser specific. Sometimes changes are made requiring snapshots to be updated. Update snapshots locally by running `npm run e2e:update-snapshots`.
103+
Snapshots are used by end-to-end tests to visually verify the output. Snapshots are both OS and browser specific. Sometimes changes are made requiring snapshots to be updated. Update snapshots locally by running `npm run e2e:update-snapshots`.
104104

105105
Once you are satisfied with the snapshots and everything is passing locally, you need to use the docker image to update snapshots for CI (unless you are running the same platform as CI (Ubuntu)). Run `npm run e2e:update-ci-snapshots` to update the CI snapshots. The snapshots will be written to your local directories. The Linux snapshots should be committed to git (non-Linux snapshots should be automatically ignored by git).
106106

jest.setup.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import '@testing-library/jest-dom';
2+
import { TextDecoder, TextEncoder } from 'util';
3+
import { performance } from 'perf_hooks';
24
import 'jest-canvas-mock';
35
import './__mocks__/dh-core';
46
import Log from '@deephaven/log';
7+
import { TestUtils } from '@deephaven/utils';
58

69
let logLevel = parseInt(process.env.DH_LOG_LEVEL ?? '', 10);
710
if (!Number.isFinite(logLevel)) {
@@ -30,6 +33,25 @@ Object.defineProperty(window, 'matchMedia', {
3033
})),
3134
});
3235

36+
Object.defineProperty(window, 'performance', {
37+
value: performance,
38+
writable: true,
39+
});
40+
41+
Object.defineProperty(window, 'ResizeObserver', {
42+
value: function () {
43+
return TestUtils.createMockProxy<ResizeObserver>();
44+
},
45+
});
46+
47+
Object.defineProperty(window, 'TextDecoder', {
48+
value: TextDecoder,
49+
});
50+
51+
Object.defineProperty(window, 'TextEncoder', {
52+
value: TextEncoder,
53+
});
54+
3355
Object.defineProperty(document, 'fonts', {
3456
value: {
3557
ready: Promise.resolve(),

package-lock.json

Lines changed: 17 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"@deephaven/redux": "file:../redux",
7070
"@deephaven/stylelint-config": "file:../stylelint-config",
7171
"@deephaven/tsconfig": "file:../tsconfig",
72+
"@deephaven/utils": "file:../utils",
7273
"@fortawesome/fontawesome-common-types": "^6.1.1",
7374
"@playwright/test": "^1.30.0",
7475
"@testing-library/jest-dom": "^5.16.4",

packages/code-studio/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"lodash.throttle": "^4.1.1",
4545
"memoize-one": "^5.1.1",
4646
"memoizee": "^0.4.15",
47-
"monaco-editor": "^0.31.1",
47+
"monaco-editor": "^0.41.0",
4848
"pouchdb-browser": "^7.2.2",
4949
"pouchdb-find": "^7.2.2",
5050
"prop-types": "^15.7.2",

packages/console/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,12 @@
3838
"lodash.throttle": "^4.1.1",
3939
"memoize-one": "^5.1.1",
4040
"memoizee": "^0.4.15",
41-
"monaco-editor": "^0.31.1",
41+
"monaco-editor": "^0.41.0",
4242
"papaparse": "5.3.2",
4343
"popper.js": "^1.16.1",
4444
"prop-types": "^15.7.2",
45-
"shell-quote": "^1.7.2"
45+
"shell-quote": "^1.7.2",
46+
"shortid": "^2.2.16"
4647
},
4748
"peerDependencies": {
4849
"react": "^17.x",

packages/console/src/ConsoleInput.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ export class ConsoleInput extends PureComponent<
187187

188188
const element = this.commandContainer.current;
189189
assertNotNull(element);
190+
190191
this.commandEditor = monaco.editor.create(element, commandSettings);
191192

192193
MonacoUtils.setEOL(this.commandEditor);
@@ -283,13 +284,10 @@ export class ConsoleInput extends PureComponent<
283284
}
284285
});
285286

286-
// Override the Ctrl+F functionality so that the find window doesn't appear
287-
this.commandEditor.addCommand(
287+
// Disable the Ctrl+F functionality so that the find window doesn't appear
288+
MonacoUtils.disableKeyBindings(this.commandEditor, [
288289
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyF, // eslint-disable-line no-bitwise
289-
() => undefined
290-
);
291-
292-
MonacoUtils.removeConflictingKeybindings(this.commandEditor);
290+
]);
293291

294292
MonacoUtils.registerPasteHandler(this.commandEditor);
295293

packages/console/src/log/LogView.tsx

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import ConsoleUtils from '../common/ConsoleUtils';
99
import LogLevel from './LogLevel';
1010
import './LogView.scss';
1111
import LogLevelMenuItem from './LogLevelMenuItem';
12+
import { MonacoUtils } from '../monaco';
1213

1314
interface LogViewProps {
1415
session: IdeSession;
@@ -226,36 +227,30 @@ class LogView extends PureComponent<LogViewProps, LogViewState> {
226227
wordWrap: 'on',
227228
});
228229

229-
// When find widget is open, escape key closes it.
230-
// Instead, capture it and do nothing. Same for shift-escape.
231-
this.editor.addCommand(monaco.KeyCode.Escape, () => undefined);
232-
this.editor.addCommand(
233-
// eslint-disable-next-line no-bitwise
234-
monaco.KeyMod.Shift | monaco.KeyCode.Escape,
235-
() => undefined
236-
);
237-
238-
// Restore regular escape to clear selection, when editorText has focus.
239-
this.editor.addCommand(
240-
monaco.KeyCode.Escape,
241-
() => {
242-
const position = this.editor?.getPosition();
243-
assertNotNull(position);
244-
this.editor?.setPosition(position);
245-
},
246-
'findWidgetVisible && editorTextFocus'
247-
);
248-
249-
this.editor.addCommand(
250-
// eslint-disable-next-line no-bitwise
251-
monaco.KeyMod.Shift | monaco.KeyCode.Escape,
252-
() => {
253-
const position = this.editor?.getPosition();
254-
assertNotNull(position);
255-
this.editor?.setPosition(position);
256-
},
257-
'findWidgetVisible && editorTextFocus'
258-
);
230+
// Override default Monaco keybindings for `escape` and `shift-escape`
231+
[
232+
[monaco.KeyCode.Escape],
233+
[monaco.KeyMod.Shift | monaco.KeyCode.Escape], // eslint-disable-line no-bitwise
234+
].forEach(keybindings => {
235+
assertNotNull(this.editor);
236+
237+
// Monaco default behavior is for escape key to close the find widget.
238+
// Instead, capture it and do nothing. Same for shift-escape.
239+
MonacoUtils.disableKeyBindings(this.editor, keybindings);
240+
241+
// Restore regular escape to clear selection, when editorText has focus.
242+
this.editor.addAction({
243+
id: 'clear-selection-on-escape',
244+
label: '',
245+
keybindings: [monaco.KeyCode.Escape],
246+
keybindingContext: 'findWidgetVisible && editorTextFocus',
247+
run: () => {
248+
const position = this.editor?.getPosition();
249+
assertNotNull(position);
250+
this.editor?.setPosition(position);
251+
},
252+
});
253+
});
259254
}
260255

261256
destroyMonaco(): void {

packages/console/src/monaco/MonacoUtils.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
/* eslint-disable no-bitwise */
22
import * as monaco from 'monaco-editor';
33
import { Shortcut, KEY, MODIFIER } from '@deephaven/components';
4+
import { TestUtils } from '@deephaven/utils';
45
import MonacoUtils from './MonacoUtils';
56

7+
const { asMock, createMockProxy } = TestUtils;
8+
69
const SINGLE_KEY_PARAMS: ConstructorParameters<typeof Shortcut>[0] = {
710
id: 'Single key',
811
name: '',
@@ -45,6 +48,11 @@ const MULTI_MOD_PARAMS: ConstructorParameters<typeof Shortcut>[0] = {
4548
macShortcut: [MODIFIER.CMD, MODIFIER.SHIFT, KEY.B],
4649
};
4750

51+
beforeEach(() => {
52+
jest.clearAllMocks();
53+
expect.hasAssertions();
54+
});
55+
4856
describe('Register worker', () => {
4957
it('Registers the getWorker function', () => {
5058
const getWorker = () => ({}) as Worker;
@@ -151,6 +159,23 @@ describe('Mac shortcuts', () => {
151159
});
152160
});
153161

162+
describe('disableKeyBindings', () => {
163+
const editor = createMockProxy<monaco.editor.IStandaloneCodeEditor>();
164+
165+
it('should disable key bindings for the given editor', () => {
166+
const keybindings = [1, 2, 3];
167+
168+
MonacoUtils.disableKeyBindings(editor, keybindings);
169+
170+
expect(editor.addAction).toHaveBeenCalledWith({
171+
id: expect.stringMatching(/^disable-keybindings-.+/),
172+
label: '',
173+
keybindings,
174+
run: expect.any(Function),
175+
});
176+
});
177+
});
178+
154179
describe('provideLinks', () => {
155180
it('it should get a provideLinks function which should return an object with the links', () => {
156181
const { provideLinks } = MonacoUtils;
@@ -177,3 +202,33 @@ describe('provideLinks', () => {
177202
expect(provideLinks(mockModel)).toEqual(expectedValue);
178203
});
179204
});
205+
206+
describe('removeConflictingKeybindings', () => {
207+
beforeEach(() => {
208+
jest.spyOn(monaco.editor, 'addKeybindingRule');
209+
jest.spyOn(MonacoUtils, 'isMacPlatform');
210+
});
211+
212+
it.each([true, false])(
213+
'should override keybinding rules - isMac:%s',
214+
isMac => {
215+
asMock(MonacoUtils.isMacPlatform).mockReturnValue(isMac);
216+
217+
MonacoUtils.removeConflictingKeybindings();
218+
219+
expect(monaco.editor.addKeybindingRule).toHaveBeenCalledWith({
220+
keybinding: monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyD,
221+
command: null,
222+
});
223+
224+
if (isMac) {
225+
expect(monaco.editor.addKeybindingRule).toHaveBeenCalledTimes(1);
226+
} else {
227+
expect(monaco.editor.addKeybindingRule).toHaveBeenCalledWith({
228+
keybinding: monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyH,
229+
command: null,
230+
});
231+
}
232+
}
233+
);
234+
});

0 commit comments

Comments
 (0)