@theia/monaco 1.77.0-next.49 → 1.77.0-next.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/monaco-color-registry.js +1 -1
- package/lib/browser/monaco-color-registry.js.map +1 -1
- package/lib/browser/monaco-command.js +1 -1
- package/lib/browser/monaco-command.js.map +1 -1
- package/lib/browser/monaco-context-key-service.d.ts +1 -1
- package/lib/browser/monaco-context-key-service.d.ts.map +1 -1
- package/lib/browser/monaco-context-key-service.js.map +1 -1
- package/lib/browser/monaco-diff-editor.js +3 -2
- package/lib/browser/monaco-diff-editor.js.map +1 -1
- package/lib/browser/monaco-editor-model.js +2 -1
- package/lib/browser/monaco-editor-model.js.map +1 -1
- package/lib/browser/monaco-editor-overlay-button.js +2 -1
- package/lib/browser/monaco-editor-overlay-button.js.map +1 -1
- package/lib/browser/monaco-editor-provider.js +2 -2
- package/lib/browser/monaco-editor-provider.js.map +1 -1
- package/lib/browser/monaco-editor-service.js +1 -1
- package/lib/browser/monaco-editor-service.js.map +1 -1
- package/lib/browser/monaco-editor-zone-widget.js +2 -1
- package/lib/browser/monaco-editor-zone-widget.js.map +1 -1
- package/lib/browser/monaco-editor.d.ts +2 -0
- package/lib/browser/monaco-editor.d.ts.map +1 -1
- package/lib/browser/monaco-editor.js +12 -7
- package/lib/browser/monaco-editor.js.map +1 -1
- package/lib/browser/monaco-editor.spec.d.ts +2 -0
- package/lib/browser/monaco-editor.spec.d.ts.map +1 -0
- package/lib/browser/monaco-editor.spec.js +182 -0
- package/lib/browser/monaco-editor.spec.js.map +1 -0
- package/lib/browser/monaco-frontend-application-contribution.js +1 -1
- package/lib/browser/monaco-frontend-application-contribution.js.map +1 -1
- package/lib/browser/monaco-frontend-module.js +2 -1
- package/lib/browser/monaco-frontend-module.js.map +1 -1
- package/lib/browser/monaco-indexed-db.js +1 -1
- package/lib/browser/monaco-indexed-db.js.map +1 -1
- package/lib/browser/monaco-init.js +1 -1
- package/lib/browser/monaco-init.js.map +1 -1
- package/lib/browser/monaco-init.spec.js +28 -1
- package/lib/browser/monaco-init.spec.js.map +1 -1
- package/lib/browser/monaco-keybinding.d.ts +1 -0
- package/lib/browser/monaco-keybinding.d.ts.map +1 -1
- package/lib/browser/monaco-keybinding.js +10 -3
- package/lib/browser/monaco-keybinding.js.map +1 -1
- package/lib/browser/monaco-keybinding.spec.d.ts +2 -0
- package/lib/browser/monaco-keybinding.spec.d.ts.map +1 -0
- package/lib/browser/monaco-keybinding.spec.js +94 -0
- package/lib/browser/monaco-keybinding.spec.js.map +1 -0
- package/lib/browser/monaco-keycode-map.js +3 -2
- package/lib/browser/monaco-keycode-map.js.map +1 -1
- package/lib/browser/monaco-languages.js +2 -2
- package/lib/browser/monaco-languages.js.map +1 -1
- package/lib/browser/monaco-marker-collection.js +2 -1
- package/lib/browser/monaco-marker-collection.js.map +1 -1
- package/lib/browser/monaco-mime-service.js +1 -1
- package/lib/browser/monaco-mime-service.js.map +1 -1
- package/lib/browser/monaco-outline-contribution.d.ts +3 -0
- package/lib/browser/monaco-outline-contribution.d.ts.map +1 -1
- package/lib/browser/monaco-outline-contribution.js +6 -2
- package/lib/browser/monaco-outline-contribution.js.map +1 -1
- package/lib/browser/monaco-outline-decorator.d.ts.map +1 -1
- package/lib/browser/monaco-outline-decorator.js +8 -5
- package/lib/browser/monaco-outline-decorator.js.map +1 -1
- package/lib/browser/monaco-outline-decorator.spec.d.ts +2 -0
- package/lib/browser/monaco-outline-decorator.spec.d.ts.map +1 -0
- package/lib/browser/monaco-outline-decorator.spec.js +79 -0
- package/lib/browser/monaco-outline-decorator.spec.js.map +1 -0
- package/lib/browser/monaco-quick-input-service.d.ts +5 -0
- package/lib/browser/monaco-quick-input-service.d.ts.map +1 -1
- package/lib/browser/monaco-quick-input-service.js +8 -1
- package/lib/browser/monaco-quick-input-service.js.map +1 -1
- package/lib/browser/monaco-resolved-keybinding.d.ts.map +1 -1
- package/lib/browser/monaco-resolved-keybinding.js +8 -4
- package/lib/browser/monaco-resolved-keybinding.js.map +1 -1
- package/lib/browser/monaco-snippet-suggest-provider.js +3 -3
- package/lib/browser/monaco-snippet-suggest-provider.js.map +1 -1
- package/lib/browser/monaco-text-model-service.js +1 -1
- package/lib/browser/monaco-text-model-service.js.map +1 -1
- package/lib/browser/monaco-theming-service.js +3 -3
- package/lib/browser/monaco-theming-service.js.map +1 -1
- package/lib/browser/monaco-to-protocol-converter.js +1 -1
- package/lib/browser/monaco-to-protocol-converter.js.map +1 -1
- package/lib/browser/monaco-workspace.js +2 -2
- package/lib/browser/monaco-workspace.js.map +1 -1
- package/lib/browser/protocol-to-monaco-converter.js +1 -1
- package/lib/browser/protocol-to-monaco-converter.js.map +1 -1
- package/lib/browser/simple-monaco-editor.js +2 -1
- package/lib/browser/simple-monaco-editor.js.map +1 -1
- package/lib/browser/textmate/monaco-textmate-service.js +1 -1
- package/lib/browser/textmate/monaco-textmate-service.js.map +1 -1
- package/lib/browser/textmate/monaco-theme-registry.js +1 -1
- package/lib/browser/textmate/monaco-theme-registry.js.map +1 -1
- package/lib/browser/textmate/textmate-contribution.js +2 -1
- package/lib/browser/textmate/textmate-contribution.js.map +1 -1
- package/lib/browser/textmate/textmate-snippet-completion-provider.js +2 -1
- package/lib/browser/textmate/textmate-snippet-completion-provider.js.map +1 -1
- package/lib/browser/workspace-symbol-command.js +1 -1
- package/lib/browser/workspace-symbol-command.js.map +1 -1
- package/lib/package.spec.js +1 -0
- package/lib/package.spec.js.map +1 -1
- package/package.json +8 -8
- package/src/browser/monaco-context-key-service.ts +1 -1
- package/src/browser/monaco-diff-editor.ts +1 -1
- package/src/browser/monaco-editor-provider.ts +1 -1
- package/src/browser/monaco-editor.spec.ts +201 -0
- package/src/browser/monaco-editor.ts +11 -5
- package/src/browser/monaco-init.spec.ts +28 -1
- package/src/browser/monaco-keybinding.spec.ts +117 -0
- package/src/browser/monaco-keybinding.ts +13 -3
- package/src/browser/monaco-outline-contribution.ts +7 -0
- package/src/browser/monaco-outline-decorator.spec.ts +96 -0
- package/src/browser/monaco-outline-decorator.ts +8 -5
- package/src/browser/monaco-quick-input-service.ts +12 -0
- package/src/browser/monaco-resolved-keybinding.ts +6 -3
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
9
|
+
// *****************************************************************************
|
|
10
|
+
|
|
11
|
+
import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
|
|
12
|
+
let disableJSDOM = enableJSDOM();
|
|
13
|
+
|
|
14
|
+
import { expect } from 'chai';
|
|
15
|
+
import { Key, KeybindingRegistry, KeyCode } from '@theia/core/lib/browser';
|
|
16
|
+
import * as os from '@theia/core/lib/common/os';
|
|
17
|
+
import * as monaco from '@theia/monaco-editor-core';
|
|
18
|
+
import * as MonacoPlatform from '@theia/monaco-editor-core/esm/vs/base/common/platform';
|
|
19
|
+
import { KeyCode as MonacoKeyCode } from '@theia/monaco-editor-core/esm/vs/base/common/keyCodes';
|
|
20
|
+
import { KeyCodeChord } from '@theia/monaco-editor-core/esm/vs/base/common/keybindings';
|
|
21
|
+
import { USLayoutResolvedKeybinding } from '@theia/monaco-editor-core/esm/vs/platform/keybinding/common/usLayoutResolvedKeybinding';
|
|
22
|
+
import * as sinon from 'sinon';
|
|
23
|
+
import { MonacoKeybindingContribution } from './monaco-keybinding';
|
|
24
|
+
import { MonacoResolvedKeybinding } from './monaco-resolved-keybinding';
|
|
25
|
+
|
|
26
|
+
class TestMonacoKeybindingContribution extends MonacoKeybindingContribution {
|
|
27
|
+
encode(code: KeyCode): number {
|
|
28
|
+
return this.toSingleMonacoKeybindingNumber(code);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
representable(codes: KeyCode[]): boolean {
|
|
32
|
+
return this.isMonacoRepresentable(codes);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
disableJSDOM();
|
|
37
|
+
|
|
38
|
+
describe('Monaco keybinding adapter', () => {
|
|
39
|
+
let contribution: TestMonacoKeybindingContribution;
|
|
40
|
+
|
|
41
|
+
before(() => disableJSDOM = enableJSDOM());
|
|
42
|
+
after(() => disableJSDOM());
|
|
43
|
+
|
|
44
|
+
beforeEach(() => contribution = new TestMonacoKeybindingContribution());
|
|
45
|
+
|
|
46
|
+
afterEach(() => sinon.restore());
|
|
47
|
+
|
|
48
|
+
it('encodes non-macOS Ctrl as Monaco CtrlCmd', () => {
|
|
49
|
+
sinon.stub(os, 'isOSX').value(false);
|
|
50
|
+
|
|
51
|
+
const encoded = contribution.encode(new KeyCode({ key: Key.KEY_A, ctrl: true }));
|
|
52
|
+
|
|
53
|
+
expect(encoded & monaco.KeyMod.CtrlCmd).to.equal(monaco.KeyMod.CtrlCmd);
|
|
54
|
+
expect(encoded & monaco.KeyMod.WinCtrl).to.equal(0);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('preserves macOS Ctrl and Command encoding', () => {
|
|
58
|
+
sinon.stub(os, 'isOSX').value(true);
|
|
59
|
+
|
|
60
|
+
const encoded = contribution.encode(new KeyCode({ key: Key.KEY_A, ctrl: true, meta: true }));
|
|
61
|
+
|
|
62
|
+
expect(encoded & monaco.KeyMod.WinCtrl).to.equal(monaco.KeyMod.WinCtrl);
|
|
63
|
+
expect(encoded & monaco.KeyMod.CtrlCmd).to.equal(monaco.KeyMod.CtrlCmd);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('accepts layout Shift but rejects layout AltGraph and unmapped keys', () => {
|
|
67
|
+
expect(contribution.representable([
|
|
68
|
+
new KeyCode({ key: Key.DIGIT7, layoutModifiers: 'shift' })
|
|
69
|
+
])).to.be.true;
|
|
70
|
+
expect(contribution.representable([
|
|
71
|
+
new KeyCode({ key: Key.DIGIT8, layoutModifiers: 'altGraph' })
|
|
72
|
+
])).to.be.false;
|
|
73
|
+
expect(contribution.representable([new KeyCode({ key: Key.F20 })])).to.be.false;
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('uses formatted logical characters in resolved labels', () => {
|
|
77
|
+
const registry = Object.create(KeybindingRegistry.prototype) as KeybindingRegistry;
|
|
78
|
+
const bracket = new MonacoResolvedKeybinding([
|
|
79
|
+
new KeyCode({ key: Key.DIGIT8, ctrl: true, character: '[', layoutModifiers: 'altGraph' })
|
|
80
|
+
], registry);
|
|
81
|
+
const letter = new MonacoResolvedKeybinding([
|
|
82
|
+
new KeyCode({ key: Key.KEY_P, ctrl: true, character: 'p' })
|
|
83
|
+
], registry);
|
|
84
|
+
|
|
85
|
+
const controlLabel = MonacoPlatform.OS === MonacoPlatform.OperatingSystem.Macintosh ? '⌃' : 'Ctrl+';
|
|
86
|
+
expect(bracket.getLabel()).to.equal(`${controlLabel}[`);
|
|
87
|
+
expect(letter.getLabel()).to.equal(`${controlLabel}P`);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('includes layout Shift in dispatch chords but not in labels', () => {
|
|
91
|
+
const registry = Object.create(KeybindingRegistry.prototype) as KeybindingRegistry;
|
|
92
|
+
const resolved = new MonacoResolvedKeybinding([
|
|
93
|
+
new KeyCode({ key: Key.DIGIT7, ctrl: true, character: '/', layoutModifiers: 'shift' })
|
|
94
|
+
], registry);
|
|
95
|
+
const expectedDispatch = USLayoutResolvedKeybinding.getDispatchStr(
|
|
96
|
+
new KeyCodeChord(true, true, false, false, MonacoKeyCode.Digit7)
|
|
97
|
+
);
|
|
98
|
+
const controlLabel = MonacoPlatform.OS === MonacoPlatform.OperatingSystem.Macintosh ? '⌃' : 'Ctrl+';
|
|
99
|
+
|
|
100
|
+
expect(resolved.getDispatchChords()).to.deep.equal([expectedDispatch]);
|
|
101
|
+
expect(resolved.getLabel()).to.equal(`${controlLabel}/`);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('shows layout Shift in labels when it produces an uppercase letter', () => {
|
|
105
|
+
const registry = Object.create(KeybindingRegistry.prototype) as KeybindingRegistry;
|
|
106
|
+
const resolved = new MonacoResolvedKeybinding([
|
|
107
|
+
new KeyCode({ key: Key.KEY_P, ctrl: true, character: 'P', layoutModifiers: 'shift' })
|
|
108
|
+
], registry);
|
|
109
|
+
const expectedDispatch = USLayoutResolvedKeybinding.getDispatchStr(
|
|
110
|
+
new KeyCodeChord(true, true, false, false, MonacoKeyCode.KeyP)
|
|
111
|
+
);
|
|
112
|
+
const isMac = MonacoPlatform.OS === MonacoPlatform.OperatingSystem.Macintosh;
|
|
113
|
+
|
|
114
|
+
expect(resolved.getDispatchChords()).to.deep.equal([expectedDispatch]);
|
|
115
|
+
expect(resolved.getLabel()).to.equal(isMac ? '⌃⇧P' : 'Ctrl+Shift+P');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import { injectable, inject, postConstruct, named } from '@theia/core/shared/inversify';
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
KeybindingContribution, KeybindingRegistry, KeybindingScope, KeyCode, layoutModifiersIncludeAltGraph, layoutModifiersIncludeShift
|
|
20
|
+
} from '@theia/core/lib/browser';
|
|
19
21
|
import { MonacoCommands } from './monaco-command';
|
|
20
22
|
import { MonacoCommandRegistry } from './monaco-command-registry';
|
|
21
23
|
import { CommandRegistry, DisposableCollection, environment, isOSX, ILogger } from '@theia/core';
|
|
@@ -68,6 +70,9 @@ export class MonacoKeybindingContribution implements KeybindingContribution {
|
|
|
68
70
|
this.toDisposeOnKeybindingChange.dispose();
|
|
69
71
|
for (const binding of this.keybindings.getKeybindingsByScope(KeybindingScope.USER).concat(this.keybindings.getKeybindingsByScope(KeybindingScope.WORKSPACE))) {
|
|
70
72
|
const resolved = this.keybindings.resolveKeybinding(binding);
|
|
73
|
+
if (this.keybindings.isKeybindingInactive(binding) || !this.isMonacoRepresentable(resolved)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
71
76
|
const command = binding.command;
|
|
72
77
|
const when = binding.when
|
|
73
78
|
? this.contextKeyService.parse(binding.when)
|
|
@@ -84,6 +89,11 @@ export class MonacoKeybindingContribution implements KeybindingContribution {
|
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
91
|
|
|
92
|
+
protected isMonacoRepresentable(codes: KeyCode[]): boolean {
|
|
93
|
+
return codes.length <= 2 && codes.every(code => code.key && KEY_CODE_MAP[code.key.keyCode] !== undefined
|
|
94
|
+
&& !layoutModifiersIncludeAltGraph(code.layoutModifiers));
|
|
95
|
+
}
|
|
96
|
+
|
|
87
97
|
protected toMonacoKeybindingNumber(codes: KeyCode[]): number {
|
|
88
98
|
const [firstPart, secondPart] = codes;
|
|
89
99
|
if (codes.length > 2) {
|
|
@@ -100,11 +110,11 @@ export class MonacoKeybindingContribution implements KeybindingContribution {
|
|
|
100
110
|
if (code.alt) {
|
|
101
111
|
encoded |= monaco.KeyMod.Alt;
|
|
102
112
|
}
|
|
103
|
-
if (code.shift) {
|
|
113
|
+
if (code.shift || layoutModifiersIncludeShift(code.layoutModifiers)) {
|
|
104
114
|
encoded |= monaco.KeyMod.Shift;
|
|
105
115
|
}
|
|
106
116
|
if (code.ctrl) {
|
|
107
|
-
encoded |= monaco.KeyMod.WinCtrl;
|
|
117
|
+
encoded |= isOSX ? monaco.KeyMod.WinCtrl : monaco.KeyMod.CtrlCmd;
|
|
108
118
|
}
|
|
109
119
|
if (code.meta && isOSX) {
|
|
110
120
|
encoded |= monaco.KeyMod.CtrlCmd;
|
|
@@ -301,6 +301,7 @@ export class MonacoOutlineContribution implements FrontendApplicationContributio
|
|
|
301
301
|
iconClass: monaco.languages.SymbolKind[symbol.kind].toString().toLowerCase(),
|
|
302
302
|
name: this.getName(symbol),
|
|
303
303
|
detail: this.getDetail(symbol),
|
|
304
|
+
deprecated: this.isDeprecated(symbol),
|
|
304
305
|
parent,
|
|
305
306
|
uri,
|
|
306
307
|
range: this.getNameRange(symbol),
|
|
@@ -324,6 +325,10 @@ export class MonacoOutlineContribution implements FrontendApplicationContributio
|
|
|
324
325
|
return symbol.detail;
|
|
325
326
|
}
|
|
326
327
|
|
|
328
|
+
protected isDeprecated(symbol: monaco.languages.DocumentSymbol): boolean {
|
|
329
|
+
return !!symbol.tags?.includes(monaco.languages.SymbolTag.Deprecated);
|
|
330
|
+
}
|
|
331
|
+
|
|
327
332
|
protected createId(name: string, ids: Map<string, number>): string {
|
|
328
333
|
const counter = ids.get(name);
|
|
329
334
|
const index = typeof counter === 'number' ? counter + 1 : 0;
|
|
@@ -370,6 +375,8 @@ export interface MonacoOutlineSymbolInformationNode extends OutlineSymbolInforma
|
|
|
370
375
|
range: Range;
|
|
371
376
|
fullRange: Range;
|
|
372
377
|
detail?: string;
|
|
378
|
+
/** Whether the symbol is tagged as deprecated. */
|
|
379
|
+
deprecated?: boolean;
|
|
373
380
|
parent: MonacoOutlineSymbolInformationNode | undefined;
|
|
374
381
|
children: MonacoOutlineSymbolInformationNode[];
|
|
375
382
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 Vinay Kaushal and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
|
|
18
|
+
import { expect } from 'chai';
|
|
19
|
+
import URI from '@theia/core/lib/common/uri';
|
|
20
|
+
import type { CompositeTreeNode, Tree } from '@theia/core/lib/browser/tree';
|
|
21
|
+
import type { TreeDecoration } from '@theia/core/lib/browser/tree/tree-decorator';
|
|
22
|
+
import type * as monaco from '@theia/monaco-editor-core';
|
|
23
|
+
import type { MonacoOutlineSymbolInformationNode } from './monaco-outline-contribution';
|
|
24
|
+
|
|
25
|
+
describe('MonacoOutlineDecorator', () => {
|
|
26
|
+
|
|
27
|
+
// The outline code uses the full monaco API at runtime. Load it only once this suite runs: loading it while
|
|
28
|
+
// the spec files are collected registers monaco's editor contributions before monaco-init.spec initializes
|
|
29
|
+
// the standalone services, which then need browser APIs that JSDOM does not provide.
|
|
30
|
+
let monacoApi: typeof monaco;
|
|
31
|
+
let outline: typeof import('./monaco-outline-contribution');
|
|
32
|
+
let decorator: typeof import('./monaco-outline-decorator');
|
|
33
|
+
let disableJSDOM: () => void;
|
|
34
|
+
|
|
35
|
+
before(async () => {
|
|
36
|
+
disableJSDOM = enableJSDOM();
|
|
37
|
+
// @lumino/dragdrop (pulled in transitively) extends the DragEvent DOM global at
|
|
38
|
+
// module load, which JSDOM does not provide; stub it so the import succeeds.
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
40
|
+
if (!(global as any).DragEvent) {
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
(global as any).DragEvent = class DragEvent extends (global as any).Event { };
|
|
43
|
+
}
|
|
44
|
+
monacoApi = await import('@theia/monaco-editor-core');
|
|
45
|
+
outline = await import('./monaco-outline-contribution');
|
|
46
|
+
decorator = await import('./monaco-outline-decorator');
|
|
47
|
+
});
|
|
48
|
+
after(() => disableJSDOM());
|
|
49
|
+
|
|
50
|
+
const range: monaco.IRange = { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 10 };
|
|
51
|
+
|
|
52
|
+
function symbol(name: string, detail: string, deprecated = false): monaco.languages.DocumentSymbol {
|
|
53
|
+
const tags = deprecated ? [monacoApi.languages.SymbolTag.Deprecated] : [];
|
|
54
|
+
return { name, detail, kind: monacoApi.languages.SymbolKind.Method, tags, range, selectionRange: range };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function createNode(documentSymbol: monaco.languages.DocumentSymbol): MonacoOutlineSymbolInformationNode {
|
|
58
|
+
return new outline.MonacoOutlineContribution()['createNode'](new URI('file:///test.ts'), documentSymbol, new Map());
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function decorate(...nodes: MonacoOutlineSymbolInformationNode[]): Promise<Map<string, TreeDecoration.Data>> {
|
|
62
|
+
const root: CompositeTreeNode = { id: 'root', name: 'root', parent: undefined, children: nodes };
|
|
63
|
+
return new decorator.MonacoOutlineDecorator().decorations({ root } as unknown as Tree);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
it('marks a symbol tagged as deprecated', () => {
|
|
67
|
+
expect(createNode(symbol('old', '', true)).deprecated).to.equal(true);
|
|
68
|
+
expect(createNode(symbol('current', '')).deprecated).to.equal(false);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('strikes through a deprecated symbol', async () => {
|
|
72
|
+
const node = createNode(symbol('old', '', true));
|
|
73
|
+
|
|
74
|
+
const decorations = await decorate(node);
|
|
75
|
+
|
|
76
|
+
expect(decorations.get(node.id)?.fontData).to.deep.equal({ style: 'line-through' });
|
|
77
|
+
expect(decorations.get(node.id)?.captionSuffixes).to.equal(undefined);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('keeps the detail suffix of a deprecated symbol', async () => {
|
|
81
|
+
const node = createNode(symbol('old', '(): void', true));
|
|
82
|
+
|
|
83
|
+
const decorations = await decorate(node);
|
|
84
|
+
|
|
85
|
+
expect(decorations.get(node.id)?.fontData).to.deep.equal({ style: 'line-through' });
|
|
86
|
+
expect(decorations.get(node.id)?.captionSuffixes?.map(suffix => suffix.data)).to.deep.equal(['(): void']);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('does not decorate a symbol that is neither deprecated nor has a detail', async () => {
|
|
90
|
+
const node = createNode(symbol('current', ''));
|
|
91
|
+
|
|
92
|
+
const decorations = await decorate(node);
|
|
93
|
+
|
|
94
|
+
expect(decorations.has(node.id)).to.equal(false);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -43,7 +43,7 @@ export class MonacoOutlineDecorator implements TreeDecorator {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
for (const treeNode of new DepthFirstTreeIterator(tree.root)) {
|
|
46
|
-
if (MonacoOutlineSymbolInformationNode.is(treeNode) && treeNode.detail) {
|
|
46
|
+
if (MonacoOutlineSymbolInformationNode.is(treeNode) && (treeNode.detail || treeNode.deprecated)) {
|
|
47
47
|
result.set(treeNode.id, this.toDecoration(treeNode));
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -52,15 +52,18 @@ export class MonacoOutlineDecorator implements TreeDecorator {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
protected toDecoration(node: MonacoOutlineSymbolInformationNode): TreeDecoration.Data {
|
|
55
|
-
const captionSuffixes: TreeDecoration.CaptionAffix[] = [{
|
|
56
|
-
data:
|
|
55
|
+
const captionSuffixes: TreeDecoration.CaptionAffix[] | undefined = node.detail ? [{
|
|
56
|
+
data: node.detail,
|
|
57
57
|
fontData: {
|
|
58
58
|
color: 'var(--theia-descriptionForeground)',
|
|
59
59
|
}
|
|
60
|
-
}];
|
|
60
|
+
}] : undefined;
|
|
61
|
+
// Like VS Code, strike through the names of deprecated symbols.
|
|
62
|
+
const fontData: TreeDecoration.FontData | undefined = node.deprecated ? { style: 'line-through' } : undefined;
|
|
61
63
|
|
|
62
64
|
return {
|
|
63
|
-
captionSuffixes
|
|
65
|
+
captionSuffixes,
|
|
66
|
+
fontData
|
|
64
67
|
};
|
|
65
68
|
}
|
|
66
69
|
}
|
|
@@ -114,6 +114,11 @@ export class MonacoQuickInputImplementation implements IQuickInputService {
|
|
|
114
114
|
|
|
115
115
|
protected container: HTMLElement;
|
|
116
116
|
|
|
117
|
+
/**
|
|
118
|
+
* The element that had focus when the quick input was shown. Cleared when the quick input is hidden.
|
|
119
|
+
*/
|
|
120
|
+
previousFocusElement: HTMLElement | undefined;
|
|
121
|
+
|
|
117
122
|
protected inQuickOpen: IContextKey<boolean>;
|
|
118
123
|
|
|
119
124
|
/**
|
|
@@ -144,11 +149,17 @@ export class MonacoQuickInputImplementation implements IQuickInputService {
|
|
|
144
149
|
this.scopedInQuickOpen = this.scopedContextKeyService.createKey<boolean>('inQuickOpen', false);
|
|
145
150
|
|
|
146
151
|
this.controller.onShow(() => {
|
|
152
|
+
// `onShow` fires before focus moves into the quick input, and again whenever it switches to another picker.
|
|
153
|
+
const activeElement = document.activeElement;
|
|
154
|
+
if (activeElement instanceof HTMLElement && !this.container.contains(activeElement)) {
|
|
155
|
+
this.previousFocusElement = activeElement;
|
|
156
|
+
}
|
|
147
157
|
this.container.style.top = this.shell.mainPanel.node.getBoundingClientRect().top + 'px';
|
|
148
158
|
this.inQuickOpen.set(true);
|
|
149
159
|
this.scopedInQuickOpen.set(true);
|
|
150
160
|
});
|
|
151
161
|
this.controller.onHide(() => {
|
|
162
|
+
this.previousFocusElement = undefined;
|
|
152
163
|
this.inQuickOpen.set(false);
|
|
153
164
|
this.scopedInQuickOpen.set(false);
|
|
154
165
|
});
|
|
@@ -407,6 +418,7 @@ export class MonacoQuickInputService implements QuickInputService {
|
|
|
407
418
|
|
|
408
419
|
get onShow(): Event<void> { return this.monacoService.onShow; }
|
|
409
420
|
get onHide(): Event<void> { return this.monacoService.onHide; }
|
|
421
|
+
get previousFocusElement(): HTMLElement | undefined { return this.monacoService.previousFocusElement; }
|
|
410
422
|
|
|
411
423
|
open(filter: string): void {
|
|
412
424
|
this.monacoService.open(filter);
|
|
@@ -23,6 +23,7 @@ import { USLayoutResolvedKeybinding } from '@theia/monaco-editor-core/esm/vs/pla
|
|
|
23
23
|
import * as MonacoPlatform from '@theia/monaco-editor-core/esm/vs/base/common/platform';
|
|
24
24
|
import { KeybindingRegistry } from '@theia/core/lib/browser/keybinding';
|
|
25
25
|
import { KeyCode, KeySequence, Keystroke, Key, KeyModifier } from '@theia/core/lib/browser/keys';
|
|
26
|
+
import { layoutModifiersIncludeShift } from '@theia/core/lib/common/keys';
|
|
26
27
|
import { isOSX } from '@theia/core/lib/common/os';
|
|
27
28
|
import { KEY_CODE_MAP } from './monaco-keycode-map';
|
|
28
29
|
|
|
@@ -33,12 +34,14 @@ export class MonacoResolvedKeybinding extends ResolvedKeybinding {
|
|
|
33
34
|
constructor(protected readonly keySequence: KeySequence, keybindingService: KeybindingRegistry) {
|
|
34
35
|
super();
|
|
35
36
|
this.chords = keySequence.map(keyCode => {
|
|
37
|
+
const components = keybindingService.componentsForKeyCode(keyCode);
|
|
36
38
|
// eslint-disable-next-line no-null/no-null
|
|
37
|
-
const keyLabel = keyCode.key ?
|
|
39
|
+
const keyLabel = keyCode.key ? components[components.length - 1] : null;
|
|
38
40
|
const keyAriaLabel = keyLabel;
|
|
41
|
+
// The label uses the logical character, so layout Shift only appears when it produced an uppercase letter.
|
|
39
42
|
return new ResolvedChord(
|
|
40
43
|
keyCode.ctrl,
|
|
41
|
-
keyCode
|
|
44
|
+
keybindingService.displaysShift(keyCode),
|
|
42
45
|
keyCode.alt,
|
|
43
46
|
keyCode.meta,
|
|
44
47
|
keyLabel,
|
|
@@ -106,7 +109,7 @@ export class MonacoResolvedKeybinding extends ResolvedKeybinding {
|
|
|
106
109
|
private toKeybinding(keyCode: KeyCode): KeyCodeChord {
|
|
107
110
|
return new KeyCodeChord(
|
|
108
111
|
keyCode.ctrl,
|
|
109
|
-
keyCode.shift,
|
|
112
|
+
keyCode.shift || layoutModifiersIncludeShift(keyCode.layoutModifiers),
|
|
110
113
|
keyCode.alt,
|
|
111
114
|
keyCode.meta,
|
|
112
115
|
KEY_CODE_MAP[keyCode.key!.keyCode]
|