@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.
Files changed (111) hide show
  1. package/lib/browser/monaco-color-registry.js +1 -1
  2. package/lib/browser/monaco-color-registry.js.map +1 -1
  3. package/lib/browser/monaco-command.js +1 -1
  4. package/lib/browser/monaco-command.js.map +1 -1
  5. package/lib/browser/monaco-context-key-service.d.ts +1 -1
  6. package/lib/browser/monaco-context-key-service.d.ts.map +1 -1
  7. package/lib/browser/monaco-context-key-service.js.map +1 -1
  8. package/lib/browser/monaco-diff-editor.js +3 -2
  9. package/lib/browser/monaco-diff-editor.js.map +1 -1
  10. package/lib/browser/monaco-editor-model.js +2 -1
  11. package/lib/browser/monaco-editor-model.js.map +1 -1
  12. package/lib/browser/monaco-editor-overlay-button.js +2 -1
  13. package/lib/browser/monaco-editor-overlay-button.js.map +1 -1
  14. package/lib/browser/monaco-editor-provider.js +2 -2
  15. package/lib/browser/monaco-editor-provider.js.map +1 -1
  16. package/lib/browser/monaco-editor-service.js +1 -1
  17. package/lib/browser/monaco-editor-service.js.map +1 -1
  18. package/lib/browser/monaco-editor-zone-widget.js +2 -1
  19. package/lib/browser/monaco-editor-zone-widget.js.map +1 -1
  20. package/lib/browser/monaco-editor.d.ts +2 -0
  21. package/lib/browser/monaco-editor.d.ts.map +1 -1
  22. package/lib/browser/monaco-editor.js +12 -7
  23. package/lib/browser/monaco-editor.js.map +1 -1
  24. package/lib/browser/monaco-editor.spec.d.ts +2 -0
  25. package/lib/browser/monaco-editor.spec.d.ts.map +1 -0
  26. package/lib/browser/monaco-editor.spec.js +182 -0
  27. package/lib/browser/monaco-editor.spec.js.map +1 -0
  28. package/lib/browser/monaco-frontend-application-contribution.js +1 -1
  29. package/lib/browser/monaco-frontend-application-contribution.js.map +1 -1
  30. package/lib/browser/monaco-frontend-module.js +2 -1
  31. package/lib/browser/monaco-frontend-module.js.map +1 -1
  32. package/lib/browser/monaco-indexed-db.js +1 -1
  33. package/lib/browser/monaco-indexed-db.js.map +1 -1
  34. package/lib/browser/monaco-init.js +1 -1
  35. package/lib/browser/monaco-init.js.map +1 -1
  36. package/lib/browser/monaco-init.spec.js +28 -1
  37. package/lib/browser/monaco-init.spec.js.map +1 -1
  38. package/lib/browser/monaco-keybinding.d.ts +1 -0
  39. package/lib/browser/monaco-keybinding.d.ts.map +1 -1
  40. package/lib/browser/monaco-keybinding.js +10 -3
  41. package/lib/browser/monaco-keybinding.js.map +1 -1
  42. package/lib/browser/monaco-keybinding.spec.d.ts +2 -0
  43. package/lib/browser/monaco-keybinding.spec.d.ts.map +1 -0
  44. package/lib/browser/monaco-keybinding.spec.js +94 -0
  45. package/lib/browser/monaco-keybinding.spec.js.map +1 -0
  46. package/lib/browser/monaco-keycode-map.js +3 -2
  47. package/lib/browser/monaco-keycode-map.js.map +1 -1
  48. package/lib/browser/monaco-languages.js +2 -2
  49. package/lib/browser/monaco-languages.js.map +1 -1
  50. package/lib/browser/monaco-marker-collection.js +2 -1
  51. package/lib/browser/monaco-marker-collection.js.map +1 -1
  52. package/lib/browser/monaco-mime-service.js +1 -1
  53. package/lib/browser/monaco-mime-service.js.map +1 -1
  54. package/lib/browser/monaco-outline-contribution.d.ts +3 -0
  55. package/lib/browser/monaco-outline-contribution.d.ts.map +1 -1
  56. package/lib/browser/monaco-outline-contribution.js +6 -2
  57. package/lib/browser/monaco-outline-contribution.js.map +1 -1
  58. package/lib/browser/monaco-outline-decorator.d.ts.map +1 -1
  59. package/lib/browser/monaco-outline-decorator.js +8 -5
  60. package/lib/browser/monaco-outline-decorator.js.map +1 -1
  61. package/lib/browser/monaco-outline-decorator.spec.d.ts +2 -0
  62. package/lib/browser/monaco-outline-decorator.spec.d.ts.map +1 -0
  63. package/lib/browser/monaco-outline-decorator.spec.js +79 -0
  64. package/lib/browser/monaco-outline-decorator.spec.js.map +1 -0
  65. package/lib/browser/monaco-quick-input-service.d.ts +5 -0
  66. package/lib/browser/monaco-quick-input-service.d.ts.map +1 -1
  67. package/lib/browser/monaco-quick-input-service.js +8 -1
  68. package/lib/browser/monaco-quick-input-service.js.map +1 -1
  69. package/lib/browser/monaco-resolved-keybinding.d.ts.map +1 -1
  70. package/lib/browser/monaco-resolved-keybinding.js +8 -4
  71. package/lib/browser/monaco-resolved-keybinding.js.map +1 -1
  72. package/lib/browser/monaco-snippet-suggest-provider.js +3 -3
  73. package/lib/browser/monaco-snippet-suggest-provider.js.map +1 -1
  74. package/lib/browser/monaco-text-model-service.js +1 -1
  75. package/lib/browser/monaco-text-model-service.js.map +1 -1
  76. package/lib/browser/monaco-theming-service.js +3 -3
  77. package/lib/browser/monaco-theming-service.js.map +1 -1
  78. package/lib/browser/monaco-to-protocol-converter.js +1 -1
  79. package/lib/browser/monaco-to-protocol-converter.js.map +1 -1
  80. package/lib/browser/monaco-workspace.js +2 -2
  81. package/lib/browser/monaco-workspace.js.map +1 -1
  82. package/lib/browser/protocol-to-monaco-converter.js +1 -1
  83. package/lib/browser/protocol-to-monaco-converter.js.map +1 -1
  84. package/lib/browser/simple-monaco-editor.js +2 -1
  85. package/lib/browser/simple-monaco-editor.js.map +1 -1
  86. package/lib/browser/textmate/monaco-textmate-service.js +1 -1
  87. package/lib/browser/textmate/monaco-textmate-service.js.map +1 -1
  88. package/lib/browser/textmate/monaco-theme-registry.js +1 -1
  89. package/lib/browser/textmate/monaco-theme-registry.js.map +1 -1
  90. package/lib/browser/textmate/textmate-contribution.js +2 -1
  91. package/lib/browser/textmate/textmate-contribution.js.map +1 -1
  92. package/lib/browser/textmate/textmate-snippet-completion-provider.js +2 -1
  93. package/lib/browser/textmate/textmate-snippet-completion-provider.js.map +1 -1
  94. package/lib/browser/workspace-symbol-command.js +1 -1
  95. package/lib/browser/workspace-symbol-command.js.map +1 -1
  96. package/lib/package.spec.js +1 -0
  97. package/lib/package.spec.js.map +1 -1
  98. package/package.json +8 -8
  99. package/src/browser/monaco-context-key-service.ts +1 -1
  100. package/src/browser/monaco-diff-editor.ts +1 -1
  101. package/src/browser/monaco-editor-provider.ts +1 -1
  102. package/src/browser/monaco-editor.spec.ts +201 -0
  103. package/src/browser/monaco-editor.ts +11 -5
  104. package/src/browser/monaco-init.spec.ts +28 -1
  105. package/src/browser/monaco-keybinding.spec.ts +117 -0
  106. package/src/browser/monaco-keybinding.ts +13 -3
  107. package/src/browser/monaco-outline-contribution.ts +7 -0
  108. package/src/browser/monaco-outline-decorator.spec.ts +96 -0
  109. package/src/browser/monaco-outline-decorator.ts +8 -5
  110. package/src/browser/monaco-quick-input-service.ts +12 -0
  111. 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 { KeybindingContribution, KeybindingRegistry, KeybindingScope, KeyCode } from '@theia/core/lib/browser';
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: (node.detail || ''),
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 ? keybindingService.acceleratorForKey(keyCode.key) : null;
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.shift,
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]