@theia/plugin-ext 1.61.0 → 1.62.0

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 (85) hide show
  1. package/lib/common/plugin-api-rpc-model.d.ts +2 -2
  2. package/lib/common/plugin-api-rpc-model.d.ts.map +1 -1
  3. package/lib/common/plugin-api-rpc.d.ts +3 -2
  4. package/lib/common/plugin-api-rpc.d.ts.map +1 -1
  5. package/lib/common/plugin-api-rpc.js.map +1 -1
  6. package/lib/main/browser/comments/comment-thread-widget.d.ts +64 -15
  7. package/lib/main/browser/comments/comment-thread-widget.d.ts.map +1 -1
  8. package/lib/main/browser/comments/comment-thread-widget.js +93 -49
  9. package/lib/main/browser/comments/comment-thread-widget.js.map +1 -1
  10. package/lib/main/browser/comments/{comments-context-key-service.d.ts → comments-context.d.ts} +2 -7
  11. package/lib/main/browser/comments/comments-context.d.ts.map +1 -0
  12. package/lib/main/browser/comments/{comments-context-key-service.js → comments-context.js} +8 -25
  13. package/lib/main/browser/comments/comments-context.js.map +1 -0
  14. package/lib/main/browser/comments/comments-contribution.d.ts +2 -2
  15. package/lib/main/browser/comments/comments-contribution.d.ts.map +1 -1
  16. package/lib/main/browser/comments/comments-contribution.js +8 -8
  17. package/lib/main/browser/comments/comments-contribution.js.map +1 -1
  18. package/lib/main/browser/comments/comments-main.d.ts +28 -3
  19. package/lib/main/browser/comments/comments-main.d.ts.map +1 -1
  20. package/lib/main/browser/comments/comments-main.js.map +1 -1
  21. package/lib/main/browser/custom-editors/custom-editor-opener.d.ts.map +1 -1
  22. package/lib/main/browser/custom-editors/custom-editor-opener.js +6 -1
  23. package/lib/main/browser/custom-editors/custom-editor-opener.js.map +1 -1
  24. package/lib/main/browser/documents-main.d.ts +2 -1
  25. package/lib/main/browser/documents-main.d.ts.map +1 -1
  26. package/lib/main/browser/documents-main.js +13 -9
  27. package/lib/main/browser/documents-main.js.map +1 -1
  28. package/lib/main/browser/main-context.d.ts.map +1 -1
  29. package/lib/main/browser/main-context.js +3 -1
  30. package/lib/main/browser/main-context.js.map +1 -1
  31. package/lib/main/browser/menus/menus-contribution-handler.d.ts +7 -13
  32. package/lib/main/browser/menus/menus-contribution-handler.d.ts.map +1 -1
  33. package/lib/main/browser/menus/menus-contribution-handler.js +64 -51
  34. package/lib/main/browser/menus/menus-contribution-handler.js.map +1 -1
  35. package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts +5 -30
  36. package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts.map +1 -1
  37. package/lib/main/browser/menus/plugin-menu-command-adapter.js +7 -110
  38. package/lib/main/browser/menus/plugin-menu-command-adapter.js.map +1 -1
  39. package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts +4 -4
  40. package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts.map +1 -1
  41. package/lib/main/browser/menus/vscode-theia-menu-mappings.js +7 -10
  42. package/lib/main/browser/menus/vscode-theia-menu-mappings.js.map +1 -1
  43. package/lib/main/browser/plugin-ext-frontend-module.d.ts.map +1 -1
  44. package/lib/main/browser/plugin-ext-frontend-module.js +2 -4
  45. package/lib/main/browser/plugin-ext-frontend-module.js.map +1 -1
  46. package/lib/main/browser/terminal-main.d.ts.map +1 -1
  47. package/lib/main/browser/terminal-main.js +4 -1
  48. package/lib/main/browser/terminal-main.js.map +1 -1
  49. package/lib/main/browser/text-editor-model-service.d.ts +1 -3
  50. package/lib/main/browser/text-editor-model-service.d.ts.map +1 -1
  51. package/lib/main/browser/text-editor-model-service.js +0 -5
  52. package/lib/main/browser/text-editor-model-service.js.map +1 -1
  53. package/lib/main/browser/view/tree-view-widget.d.ts +2 -2
  54. package/lib/main/browser/view/tree-view-widget.d.ts.map +1 -1
  55. package/lib/main/browser/view/tree-view-widget.js +5 -4
  56. package/lib/main/browser/view/tree-view-widget.js.map +1 -1
  57. package/lib/plugin/comments.d.ts +2 -2
  58. package/lib/plugin/comments.d.ts.map +1 -1
  59. package/lib/plugin/comments.js.map +1 -1
  60. package/lib/plugin/terminal-ext.d.ts +2 -1
  61. package/lib/plugin/terminal-ext.d.ts.map +1 -1
  62. package/lib/plugin/terminal-ext.js +13 -3
  63. package/lib/plugin/terminal-ext.js.map +1 -1
  64. package/package.json +29 -29
  65. package/src/common/plugin-api-rpc-model.ts +2 -2
  66. package/src/common/plugin-api-rpc.ts +3 -2
  67. package/src/main/browser/comments/comment-thread-widget.tsx +177 -85
  68. package/src/main/browser/comments/{comments-context-key-service.ts → comments-context.ts} +1 -20
  69. package/src/main/browser/comments/comments-contribution.ts +5 -5
  70. package/src/main/browser/comments/comments-main.ts +5 -4
  71. package/src/main/browser/custom-editors/custom-editor-opener.tsx +5 -1
  72. package/src/main/browser/documents-main.ts +19 -10
  73. package/src/main/browser/main-context.ts +3 -1
  74. package/src/main/browser/menus/menus-contribution-handler.ts +68 -49
  75. package/src/main/browser/menus/plugin-menu-command-adapter.ts +13 -120
  76. package/src/main/browser/menus/vscode-theia-menu-mappings.ts +4 -6
  77. package/src/main/browser/plugin-ext-frontend-module.ts +2 -4
  78. package/src/main/browser/style/comments.css +9 -1
  79. package/src/main/browser/terminal-main.ts +4 -1
  80. package/src/main/browser/text-editor-model-service.ts +1 -6
  81. package/src/main/browser/view/tree-view-widget.tsx +7 -6
  82. package/src/plugin/comments.ts +4 -4
  83. package/src/plugin/terminal-ext.ts +14 -3
  84. package/lib/main/browser/comments/comments-context-key-service.d.ts.map +0 -1
  85. package/lib/main/browser/comments/comments-context-key-service.js.map +0 -1
@@ -16,14 +16,14 @@
16
16
  import { DocumentsMain, MAIN_RPC_CONTEXT, DocumentsExt } from '../../common/plugin-api-rpc';
17
17
  import { UriComponents } from '../../common/uri-components';
18
18
  import { EditorsAndDocumentsMain } from './editors-and-documents-main';
19
- import { DisposableCollection, Disposable, UntitledResourceResolver } from '@theia/core';
19
+ import { DisposableCollection, Disposable, UntitledResourceResolver, CancellationToken } from '@theia/core';
20
20
  import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model';
21
21
  import { RPCProtocol } from '../../common/rpc-protocol';
22
22
  import { EditorModelService } from './text-editor-model-service';
23
23
  import { EditorOpenerOptions } from '@theia/editor/lib/browser';
24
24
  import URI from '@theia/core/lib/common/uri';
25
25
  import { URI as CodeURI } from '@theia/core/shared/vscode-uri';
26
- import { ApplicationShell } from '@theia/core/lib/browser';
26
+ import { ApplicationShell, SaveOptions, SaveReason } from '@theia/core/lib/browser';
27
27
  import { TextDocumentShowOptions } from '../../common/plugin-api-rpc-model';
28
28
  import { Range } from '@theia/core/shared/vscode-languageserver-protocol';
29
29
  import { OpenerService } from '@theia/core/lib/browser/opener-service';
@@ -33,6 +33,8 @@ import { MonacoLanguages } from '@theia/monaco/lib/browser/monaco-languages';
33
33
  import * as monaco from '@theia/monaco-editor-core';
34
34
  import { TextDocumentChangeReason } from '../../plugin/types-impl';
35
35
  import { NotebookDocumentsMainImpl } from './notebooks/notebook-documents-main';
36
+ import { MonacoEditorProvider, SAVE_PARTICIPANT_DEFAULT_ORDER } from '@theia/monaco/lib/browser/monaco-editor-provider';
37
+ import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor';
36
38
 
37
39
  /*---------------------------------------------------------------------------------------------
38
40
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -98,6 +100,7 @@ export class DocumentsMainImpl implements DocumentsMain, Disposable {
98
100
  private shell: ApplicationShell,
99
101
  private untitledResourceResolver: UntitledResourceResolver,
100
102
  private languageService: MonacoLanguages,
103
+ monacoEditorProvider: MonacoEditorProvider
101
104
  ) {
102
105
  this.proxy = rpc.getProxy(MAIN_RPC_CONTEXT.DOCUMENTS_EXT);
103
106
 
@@ -111,10 +114,16 @@ export class DocumentsMainImpl implements DocumentsMain, Disposable {
111
114
  this.toDispose.push(modelService.onModelSaved(m => {
112
115
  this.proxy.$acceptModelSaved(m.textEditorModel.uri);
113
116
  }));
114
- this.toDispose.push(modelService.onModelWillSave(onWillSaveModelEvent => {
115
- onWillSaveModelEvent.waitUntil(new Promise<monaco.editor.IIdentifiedSingleEditOperation[]>(async (resolve, reject) => {
116
- setTimeout(() => reject(new Error(`Aborted onWillSaveTextDocument-event after ${this.saveTimeout}ms`)), this.saveTimeout);
117
- const edits = await this.proxy.$acceptModelWillSave(onWillSaveModelEvent.model.textEditorModel.uri, onWillSaveModelEvent.reason, this.saveTimeout);
117
+ this.toDispose.push(monacoEditorProvider.registerSaveParticipant(({
118
+ order: SAVE_PARTICIPANT_DEFAULT_ORDER,
119
+ applyChangesOnSave: async (
120
+ editor: MonacoEditor,
121
+ cancellationToken: CancellationToken,
122
+ options: SaveOptions): Promise<void> => {
123
+
124
+ const saveReason = options.saveReason ?? SaveReason.Manual;
125
+
126
+ const edits = await this.proxy.$acceptModelWillSave(editor.uri.toComponents(), saveReason.valueOf(), this.saveTimeout);
118
127
  const editOperations: monaco.editor.IIdentifiedSingleEditOperation[] = [];
119
128
  for (const edit of edits) {
120
129
  const { range, text } = edit;
@@ -126,15 +135,15 @@ export class DocumentsMainImpl implements DocumentsMain, Disposable {
126
135
  }
127
136
 
128
137
  editOperations.push({
129
- range: range ? monaco.Range.lift(range) : onWillSaveModelEvent.model.textEditorModel.getFullModelRange(),
138
+ range: range ? monaco.Range.lift(range) : editor.document.textEditorModel.getFullModelRange(),
130
139
  /* eslint-disable-next-line no-null/no-null */
131
140
  text: text || null,
132
141
  forceMoveMarkers: edit.forceMoveMarkers
133
142
  });
134
143
  }
135
- resolve(editOperations);
136
- }));
137
- }));
144
+ editor.document.textEditorModel.applyEdits(editOperations);
145
+ }
146
+ })));
138
147
  this.toDispose.push(modelService.onModelDirtyChanged(m => {
139
148
  this.proxy.$acceptDirtyStateChanged(m.textEditorModel.uri, m.dirty);
140
149
  }));
@@ -66,6 +66,7 @@ import { NotebooksAndEditorsMain } from './notebooks/notebook-documents-and-edit
66
66
  import { TestingMainImpl } from './test-main';
67
67
  import { UriMainImpl } from './uri-main';
68
68
  import { LoggerMainImpl } from './logger-main';
69
+ import { MonacoEditorProvider } from '@theia/monaco/lib/browser/monaco-editor-provider';
69
70
 
70
71
  export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container): void {
71
72
  const loggerMain = new LoggerMainImpl(container);
@@ -105,8 +106,9 @@ export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container
105
106
  const shell = container.get(ApplicationShell);
106
107
  const untitledResourceResolver = container.get(UntitledResourceResolver);
107
108
  const languageService = container.get(MonacoLanguages);
109
+ const monacoEditorProvider = container.get(MonacoEditorProvider);
108
110
  const documentsMain = new DocumentsMainImpl(editorsAndDocuments, notebookDocumentsMain, modelService, rpc,
109
- openerService, shell, untitledResourceResolver, languageService);
111
+ openerService, shell, untitledResourceResolver, languageService, monacoEditorProvider);
110
112
  rpc.set(PLUGIN_RPC_CONTEXT.DOCUMENTS_MAIN, documentsMain);
111
113
 
112
114
  rpc.set(PLUGIN_RPC_CONTEXT.NOTEBOOKS_MAIN, new NotebooksMainImpl(rpc, container, commandRegistryMain));
@@ -17,18 +17,17 @@
17
17
  /* eslint-disable @typescript-eslint/no-explicit-any */
18
18
 
19
19
  import { inject, injectable, optional } from '@theia/core/shared/inversify';
20
- import { MenuPath, CommandRegistry, Disposable, DisposableCollection, ActionMenuNode, MenuCommandAdapterRegistry, Emitter, nls } from '@theia/core';
20
+ import { MenuPath, CommandRegistry, Disposable, DisposableCollection, nls, CommandMenu, AcceleratorSource, ContextExpressionMatcher } from '@theia/core';
21
21
  import { MenuModelRegistry } from '@theia/core/lib/common';
22
22
  import { TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
23
23
  import { DeployedPlugin, IconUrl, Menu } from '../../../common';
24
24
  import { ScmWidget } from '@theia/scm/lib/browser/scm-widget';
25
- import { QuickCommandService } from '@theia/core/lib/browser';
25
+ import { KeybindingRegistry, QuickCommandService } from '@theia/core/lib/browser';
26
26
  import {
27
27
  CodeEditorWidgetUtil, codeToTheiaMappings, ContributionPoint,
28
28
  PLUGIN_EDITOR_TITLE_MENU, PLUGIN_EDITOR_TITLE_RUN_MENU, PLUGIN_SCM_TITLE_MENU, PLUGIN_VIEW_TITLE_MENU
29
29
  } from './vscode-theia-menu-mappings';
30
- import { PluginMenuCommandAdapter, ReferenceCountingSet } from './plugin-menu-command-adapter';
31
- import { ContextKeyExpr } from '@theia/monaco-editor-core/esm/vs/platform/contextkey/common/contextkey';
30
+ import { PluginMenuCommandAdapter } from './plugin-menu-command-adapter';
32
31
  import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
33
32
  import { PluginSharedStyle } from '../plugin-shared-style';
34
33
  import { ThemeIcon } from '@theia/monaco-editor-core/esm/vs/base/common/themables';
@@ -37,40 +36,35 @@ import { ThemeIcon } from '@theia/monaco-editor-core/esm/vs/base/common/themable
37
36
  export class MenusContributionPointHandler {
38
37
 
39
38
  @inject(MenuModelRegistry) private readonly menuRegistry: MenuModelRegistry;
40
- @inject(CommandRegistry) private readonly commands: CommandRegistry;
39
+ @inject(CommandRegistry) private readonly commandRegistry: CommandRegistry;
41
40
  @inject(TabBarToolbarRegistry) private readonly tabBarToolbar: TabBarToolbarRegistry;
42
- @inject(CodeEditorWidgetUtil) private readonly codeEditorWidgetUtil: CodeEditorWidgetUtil;
43
- @inject(PluginMenuCommandAdapter) protected readonly commandAdapter: PluginMenuCommandAdapter;
44
- @inject(MenuCommandAdapterRegistry) protected readonly commandAdapterRegistry: MenuCommandAdapterRegistry;
41
+ @inject(PluginMenuCommandAdapter) pluginMenuCommandAdapter: PluginMenuCommandAdapter;
45
42
  @inject(ContextKeyService) protected readonly contextKeyService: ContextKeyService;
46
43
  @inject(PluginSharedStyle) protected readonly style: PluginSharedStyle;
44
+ @inject(KeybindingRegistry) keybindingRegistry: KeybindingRegistry;
45
+
47
46
  @inject(QuickCommandService) @optional()
48
47
  private readonly quickCommandService: QuickCommandService;
49
48
 
50
- protected readonly titleContributionContextKeys = new ReferenceCountingSet();
51
- protected readonly onDidChangeTitleContributionEmitter = new Emitter<void>();
52
-
53
49
  private initialized = false;
54
50
  private initialize(): void {
55
51
  this.initialized = true;
56
- this.commandAdapterRegistry.registerAdapter(this.commandAdapter);
57
- this.tabBarToolbar.registerMenuDelegate(PLUGIN_EDITOR_TITLE_MENU, widget => this.codeEditorWidgetUtil.is(widget));
52
+ this.tabBarToolbar.registerMenuDelegate(PLUGIN_EDITOR_TITLE_MENU, widget => CodeEditorWidgetUtil.is(widget));
53
+ this.menuRegistry.registerSubmenu(PLUGIN_EDITOR_TITLE_RUN_MENU, 'EditorTitleRunMenu');
58
54
  this.tabBarToolbar.registerItem({
59
- id: this.tabBarToolbar.toElementId(PLUGIN_EDITOR_TITLE_RUN_MENU), menuPath: PLUGIN_EDITOR_TITLE_RUN_MENU,
60
- icon: 'debug-alt', text: nls.localizeByDefault('Run or Debug...'),
61
- command: '', group: 'navigation', isVisible: widget => this.codeEditorWidgetUtil.is(widget)
55
+ id: this.tabBarToolbar.toElementId(PLUGIN_EDITOR_TITLE_RUN_MENU),
56
+ menuPath: PLUGIN_EDITOR_TITLE_RUN_MENU,
57
+ icon: 'debug-alt',
58
+ text: nls.localizeByDefault('Run or Debug...'),
59
+ command: '',
60
+ group: 'navigation',
61
+ isVisible: widget => CodeEditorWidgetUtil.is(widget)
62
62
  });
63
63
  this.tabBarToolbar.registerMenuDelegate(PLUGIN_SCM_TITLE_MENU, widget => widget instanceof ScmWidget);
64
- this.tabBarToolbar.registerMenuDelegate(PLUGIN_VIEW_TITLE_MENU, widget => !this.codeEditorWidgetUtil.is(widget));
65
- this.tabBarToolbar.registerItem({ id: 'plugin-menu-contribution-title-contribution', command: '_never_', onDidChange: this.onDidChangeTitleContributionEmitter.event });
66
- this.contextKeyService.onDidChange(event => {
67
- if (event.affects(this.titleContributionContextKeys)) {
68
- this.onDidChangeTitleContributionEmitter.fire();
69
- }
70
- });
64
+ this.tabBarToolbar.registerMenuDelegate(PLUGIN_VIEW_TITLE_MENU, widget => !CodeEditorWidgetUtil.is(widget));
71
65
  }
72
66
 
73
- private getMatchingMenu(contributionPoint: ContributionPoint): MenuPath[] | undefined {
67
+ private getMatchingTheiaMenuPaths(contributionPoint: string): MenuPath[] | undefined {
74
68
  return codeToTheiaMappings.get(contributionPoint);
75
69
  }
76
70
 
@@ -86,7 +80,7 @@ export class MenusContributionPointHandler {
86
80
  const submenus = plugin.contributes?.submenus ?? [];
87
81
  for (const submenu of submenus) {
88
82
  const iconClass = submenu.icon && this.toIconClass(submenu.icon, toDispose);
89
- this.menuRegistry.registerIndependentSubmenu(submenu.id, submenu.label, iconClass ? { iconClass } : undefined);
83
+ this.menuRegistry.registerSubmenu([submenu.id], submenu.label, { icon: iconClass });
90
84
  }
91
85
 
92
86
  for (const [contributionPoint, items] of Object.entries(allMenus)) {
@@ -95,8 +89,10 @@ export class MenusContributionPointHandler {
95
89
  if (contributionPoint === 'commandPalette') {
96
90
  toDispose.push(this.registerCommandPaletteAction(item));
97
91
  } else {
98
- this.checkTitleContribution(contributionPoint, item, toDispose);
99
- const targets = this.getMatchingMenu(contributionPoint as ContributionPoint) ?? [contributionPoint];
92
+ let targets = this.getMatchingTheiaMenuPaths(contributionPoint as ContributionPoint);
93
+ if (!targets) {
94
+ targets = [[contributionPoint]];
95
+ }
100
96
  const { group, order } = this.parseGroup(item.group);
101
97
  const { submenu, command } = item;
102
98
  if (submenu && command) {
@@ -105,19 +101,55 @@ export class MenusContributionPointHandler {
105
101
  );
106
102
  }
107
103
  if (command) {
108
- toDispose.push(this.commandAdapter.addCommand(command));
104
+
109
105
  targets.forEach(target => {
106
+ const menuPath = group ? [...target, group] : target;
110
107
 
111
- const node = new ActionMenuNode({
112
- commandId: command,
113
- when: item.when,
114
- order
115
- }, this.commands);
116
- const parent = this.menuRegistry.getMenuNode(target, group);
117
- toDispose.push(parent.addNode(node));
108
+ const cmd = this.commandRegistry.getCommand(command);
109
+ if (!cmd) {
110
+ console.debug(`No label for action menu node: No command "${command}" exists.`);
111
+ return;
112
+ }
113
+ const label = cmd.label || cmd.id;
114
+ const icon = cmd.iconClass;
115
+ const action: CommandMenu & AcceleratorSource = {
116
+ id: command,
117
+ sortString: order || '',
118
+ isVisible: <T>(effectiveMenuPath: MenuPath, contextMatcher: ContextExpressionMatcher<T>, context: T | undefined, ...args: any[]): boolean => {
119
+ if (item.when && !contextMatcher.match(item.when, context)) {
120
+ return false;
121
+ }
122
+
123
+ return this.commandRegistry.isVisible(command, ...this.pluginMenuCommandAdapter.getArgumentAdapter(contributionPoint)(...args));
124
+ },
125
+ icon: icon,
126
+ label: label,
127
+ isEnabled: (effeciveMenuPath: MenuPath, ...args: any[]): boolean =>
128
+ this.commandRegistry.isEnabled(command, ...this.pluginMenuCommandAdapter.getArgumentAdapter(contributionPoint)(...args)),
129
+ run: (effeciveMenuPath: MenuPath, ...args: any[]): Promise<void> =>
130
+ this.commandRegistry.executeCommand(command, ...this.pluginMenuCommandAdapter.getArgumentAdapter(contributionPoint)(...args)),
131
+ isToggled: (effectiveMenuPath: MenuPath) => false,
132
+ getAccelerator: (context: HTMLElement | undefined): string[] => {
133
+ const bindings = this.keybindingRegistry.getKeybindingsForCommand(command);
134
+ // Only consider the first active keybinding.
135
+ if (bindings.length) {
136
+ const binding = bindings.find(b => this.keybindingRegistry.isEnabledInScope(b, context));
137
+ if (binding) {
138
+ return this.keybindingRegistry.acceleratorFor(binding, '+', true);
139
+ }
140
+ }
141
+ return [];
142
+ }
143
+ };
144
+ toDispose.push(this.menuRegistry.registerCommandMenu(menuPath, action));
118
145
  });
119
146
  } else if (submenu) {
120
- targets.forEach(target => toDispose.push(this.menuRegistry.linkSubmenu(target, submenu!, { order, when: item.when }, group)));
147
+ targets.forEach(target => toDispose.push(this.menuRegistry.linkCompoundMenuNode({
148
+ newParentPath: group ? [...target, group] : target,
149
+ submenuPath: [submenu!],
150
+ order: order,
151
+ when: item.when
152
+ })));
121
153
  }
122
154
  }
123
155
  } catch (error) {
@@ -146,19 +178,6 @@ export class MenusContributionPointHandler {
146
178
  return Disposable.NULL;
147
179
  }
148
180
 
149
- protected checkTitleContribution(contributionPoint: ContributionPoint | string, contribution: { when?: string }, toDispose: DisposableCollection): void {
150
- if (contribution.when && contributionPoint.endsWith('title')) {
151
- const expression = ContextKeyExpr.deserialize(contribution.when);
152
- if (expression) {
153
- for (const key of expression.keys()) {
154
- this.titleContributionContextKeys.add(key);
155
- toDispose.push(Disposable.create(() => this.titleContributionContextKeys.delete(key)));
156
- }
157
- toDispose.push(Disposable.create(() => this.onDidChangeTitleContributionEmitter.fire()));
158
- }
159
- }
160
- }
161
-
162
181
  protected toIconClass(url: IconUrl, toDispose: DisposableCollection): string | undefined {
163
182
  if (typeof url === 'string') {
164
183
  const asThemeIcon = ThemeIcon.fromString(url);
@@ -14,7 +14,7 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { CommandRegistry, Disposable, MenuCommandAdapter, MenuPath, SelectionService, UriSelection } from '@theia/core';
17
+ import { SelectionService, UriSelection } from '@theia/core';
18
18
  import { ResourceContextKey } from '@theia/core/lib/browser/resource-context-key';
19
19
  import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
20
20
  import { URI as CodeUri } from '@theia/core/shared/vscode-uri';
@@ -29,57 +29,20 @@ import { ScmCommandArg, TimelineCommandArg, TreeViewItemReference } from '../../
29
29
  import { TestItemReference, TestMessageArg } from '../../../common/test-types';
30
30
  import { PluginScmProvider, PluginScmResource, PluginScmResourceGroup } from '../scm-main';
31
31
  import { TreeViewWidget } from '../view/tree-view-widget';
32
- import { CodeEditorWidgetUtil, codeToTheiaMappings, ContributionPoint } from './vscode-theia-menu-mappings';
33
- import { TAB_BAR_TOOLBAR_CONTEXT_MENU } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
32
+ import { CodeEditorWidgetUtil, ContributionPoint } from './vscode-theia-menu-mappings';
34
33
  import { TestItem, TestMessage } from '@theia/test/lib/browser/test-service';
35
34
 
36
35
  export type ArgumentAdapter = (...args: unknown[]) => unknown[];
37
-
38
- export class ReferenceCountingSet<T> {
39
- protected readonly references: Map<T, number>;
40
- constructor(initialMembers?: Iterable<T>) {
41
- this.references = new Map();
42
- if (initialMembers) {
43
- for (const member of initialMembers) {
44
- this.add(member);
45
- }
46
- }
47
- }
48
-
49
- add(newMember: T): ReferenceCountingSet<T> {
50
- const value = this.references.get(newMember) ?? 0;
51
- this.references.set(newMember, value + 1);
52
- return this;
53
- }
54
-
55
- /** @returns true if the deletion results in the removal of the element from the set */
56
- delete(member: T): boolean {
57
- const value = this.references.get(member);
58
- if (value === undefined) { } else if (value <= 1) {
59
- this.references.delete(member);
60
- return true;
61
- } else {
62
- this.references.set(member, value - 1);
63
- }
64
- return false;
65
- }
66
-
67
- has(maybeMember: T): boolean {
68
- return this.references.has(maybeMember);
69
- }
36
+ function identity(...args: unknown[]): unknown[] {
37
+ return args;
70
38
  }
71
-
72
39
  @injectable()
73
- export class PluginMenuCommandAdapter implements MenuCommandAdapter {
74
- @inject(CommandRegistry) protected readonly commandRegistry: CommandRegistry;
75
- @inject(CodeEditorWidgetUtil) protected readonly codeEditorUtil: CodeEditorWidgetUtil;
76
- @inject(ScmService) protected readonly scmService: ScmService;
77
- @inject(SelectionService) protected readonly selectionService: SelectionService;
78
- @inject(ResourceContextKey) protected readonly resourceContextKey: ResourceContextKey;
40
+ export class PluginMenuCommandAdapter {
41
+ @inject(ScmService) private readonly scmService: ScmService;
42
+ @inject(SelectionService) private readonly selectionService: SelectionService;
43
+ @inject(ResourceContextKey) private readonly resourceContextKey: ResourceContextKey;
79
44
 
80
- protected readonly commands = new ReferenceCountingSet<string>();
81
45
  protected readonly argumentAdapters = new Map<string, ArgumentAdapter>();
82
- protected readonly separator = ':)(:';
83
46
 
84
47
  @postConstruct()
85
48
  protected init(): void {
@@ -89,8 +52,8 @@ export class PluginMenuCommandAdapter implements MenuCommandAdapter {
89
52
  const noArgs: ArgumentAdapter = () => [];
90
53
  const toScmArgs: ArgumentAdapter = (...args) => this.toScmArgs(...args);
91
54
  const selectedResource = () => this.getSelectedResources();
92
- const widgetURI: ArgumentAdapter = widget => this.codeEditorUtil.is(widget) ? [this.codeEditorUtil.getResourceUri(widget)] : [];
93
- (<Array<[ContributionPoint, ArgumentAdapter | undefined]>>[
55
+ const widgetURI: ArgumentAdapter = widget => CodeEditorWidgetUtil.is(widget) ? [CodeEditorWidgetUtil.getResourceUri(widget)] : [];
56
+ (<Array<[ContributionPoint, ArgumentAdapter]>>[
94
57
  ['comments/comment/context', toCommentArgs],
95
58
  ['comments/comment/title', toCommentArgs],
96
59
  ['comments/commentThread/context', toCommentArgs],
@@ -117,82 +80,12 @@ export class PluginMenuCommandAdapter implements MenuCommandAdapter {
117
80
  ['terminal/context', noArgs],
118
81
  ['terminal/title/context', noArgs],
119
82
  ]).forEach(([contributionPoint, adapter]) => {
120
- if (adapter) {
121
- const paths = codeToTheiaMappings.get(contributionPoint);
122
- if (paths) {
123
- paths.forEach(path => this.addArgumentAdapter(path, adapter));
124
- }
125
- }
83
+ this.argumentAdapters.set(contributionPoint, adapter);
126
84
  });
127
- this.addArgumentAdapter(TAB_BAR_TOOLBAR_CONTEXT_MENU, widgetURI);
128
- }
129
-
130
- canHandle(menuPath: MenuPath, command: string, ...commandArgs: unknown[]): number {
131
- if (this.commands.has(command) && this.getArgumentAdapterForMenu(menuPath)) {
132
- return 500;
133
- }
134
- return -1;
135
- }
136
-
137
- executeCommand(menuPath: MenuPath, command: string, ...commandArgs: unknown[]): Promise<unknown> {
138
- const argumentAdapter = this.getAdapterOrThrow(menuPath);
139
- return this.commandRegistry.executeCommand(command, ...argumentAdapter(...commandArgs));
140
- }
141
-
142
- isVisible(menuPath: MenuPath, command: string, ...commandArgs: unknown[]): boolean {
143
- const argumentAdapter = this.getAdapterOrThrow(menuPath);
144
- return this.commandRegistry.isVisible(command, ...argumentAdapter(...commandArgs));
145
- }
146
-
147
- isEnabled(menuPath: MenuPath, command: string, ...commandArgs: unknown[]): boolean {
148
- const argumentAdapter = this.getAdapterOrThrow(menuPath);
149
- return this.commandRegistry.isEnabled(command, ...argumentAdapter(...commandArgs));
150
- }
151
-
152
- isToggled(menuPath: MenuPath, command: string, ...commandArgs: unknown[]): boolean {
153
- const argumentAdapter = this.getAdapterOrThrow(menuPath);
154
- return this.commandRegistry.isToggled(command, ...argumentAdapter(...commandArgs));
155
- }
156
-
157
- protected getAdapterOrThrow(menuPath: MenuPath): ArgumentAdapter {
158
- const argumentAdapter = this.getArgumentAdapterForMenu(menuPath);
159
- if (!argumentAdapter) {
160
- throw new Error('PluginMenuCommandAdapter attempted to execute command for unregistered menu: ' + JSON.stringify(menuPath));
161
- }
162
- return argumentAdapter;
163
- }
164
-
165
- addCommand(commandId: string): Disposable {
166
- this.commands.add(commandId);
167
- return Disposable.create(() => this.commands.delete(commandId));
168
- }
169
-
170
- protected getArgumentAdapterForMenu(menuPath: MenuPath): ArgumentAdapter | undefined {
171
- let result;
172
- let length = 0;
173
- for (const [key, value] of this.argumentAdapters.entries()) {
174
- const candidate = key.split(this.separator);
175
- if (this.isPrefixOf(candidate, menuPath) && candidate.length > length) {
176
- result = value;
177
- length = candidate.length;
178
- }
179
- }
180
- return result;
181
- }
182
- isPrefixOf(candidate: string[], menuPath: MenuPath): boolean {
183
- if (candidate.length > menuPath.length) {
184
- return false;
185
- }
186
- for (let i = 0; i < candidate.length; i++) {
187
- if (candidate[i] !== menuPath[i]) {
188
- return false;
189
- }
190
- }
191
- return true;
192
85
  }
193
86
 
194
- protected addArgumentAdapter(menuPath: MenuPath, adapter: ArgumentAdapter): void {
195
- this.argumentAdapters.set(menuPath.join(this.separator), adapter);
87
+ getArgumentAdapter(contributionPoint: string): ArgumentAdapter {
88
+ return this.argumentAdapters.get(contributionPoint) || identity;
196
89
  }
197
90
 
198
91
  /* eslint-disable @typescript-eslint/no-explicit-any */
@@ -17,7 +17,6 @@
17
17
  import { MenuPath } from '@theia/core';
18
18
  import { SHELL_TABBAR_CONTEXT_MENU } from '@theia/core/lib/browser';
19
19
  import { Navigatable } from '@theia/core/lib/browser/navigatable';
20
- import { injectable } from '@theia/core/shared/inversify';
21
20
  import { URI as CodeUri } from '@theia/core/shared/vscode-uri';
22
21
  import { DebugStackFramesWidget } from '@theia/debug/lib/browser/view/debug-stack-frames-widget';
23
22
  import { DebugThreadsWidget } from '@theia/debug/lib/browser/view/debug-threads-widget';
@@ -74,7 +73,7 @@ export const implementedVSCodeContributionPoints = [
74
73
  export type ContributionPoint = (typeof implementedVSCodeContributionPoints)[number];
75
74
 
76
75
  /** The values are menu paths to which the VSCode contribution points correspond */
77
- export const codeToTheiaMappings = new Map<ContributionPoint, MenuPath[]>([
76
+ export const codeToTheiaMappings = new Map<string, MenuPath[]>([
78
77
  ['comments/comment/context', [COMMENT_CONTEXT]],
79
78
  ['comments/comment/title', [COMMENT_TITLE]],
80
79
  ['comments/commentThread/context', [COMMENT_THREAD_CONTEXT]],
@@ -106,12 +105,11 @@ export const codeToTheiaMappings = new Map<ContributionPoint, MenuPath[]>([
106
105
  ]);
107
106
 
108
107
  type CodeEditorWidget = EditorWidget | WebviewWidget;
109
- @injectable()
110
- export class CodeEditorWidgetUtil {
111
- is(arg: unknown): arg is CodeEditorWidget {
108
+ export namespace CodeEditorWidgetUtil {
109
+ export function is(arg: unknown): arg is CodeEditorWidget {
112
110
  return arg instanceof EditorWidget || arg instanceof WebviewWidget;
113
111
  }
114
- getResourceUri(editor: CodeEditorWidget): CodeUri | undefined {
112
+ export function getResourceUri(editor: CodeEditorWidget): CodeUri | undefined {
115
113
  const resourceUri = Navigatable.is(editor) && editor.getResourceUri();
116
114
  return resourceUri ? resourceUri['codeUri'] : undefined;
117
115
  }
@@ -68,7 +68,7 @@ import { WebviewWidgetFactory } from './webview/webview-widget-factory';
68
68
  import { CommentsService, PluginCommentService } from './comments/comments-service';
69
69
  import { CommentingRangeDecorator } from './comments/comments-decorator';
70
70
  import { CommentsContribution } from './comments/comments-contribution';
71
- import { CommentsContextKeyService } from './comments/comments-context-key-service';
71
+ import { CommentsContext } from './comments/comments-context';
72
72
  import { PluginCustomEditorRegistry } from './custom-editors/plugin-custom-editor-registry';
73
73
  import { CustomEditorWidgetFactory } from '../browser/custom-editors/custom-editor-widget-factory';
74
74
  import { CustomEditorWidget } from './custom-editors/custom-editor-widget';
@@ -77,7 +77,6 @@ import { WebviewFrontendSecurityWarnings } from './webview/webview-frontend-secu
77
77
  import { PluginAuthenticationServiceImpl } from './plugin-authentication-service';
78
78
  import { AuthenticationService } from '@theia/core/lib/browser/authentication-service';
79
79
  import { bindTreeViewDecoratorUtilities, TreeViewDecoratorService } from './view/tree-view-decorator-service';
80
- import { CodeEditorWidgetUtil } from './menus/vscode-theia-menu-mappings';
81
80
  import { PluginMenuCommandAdapter } from './menus/plugin-menu-command-adapter';
82
81
  import './theme-icon-override';
83
82
  import { PluginIconService } from './plugin-icon-service';
@@ -250,7 +249,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
250
249
 
251
250
  bind(MenusContributionPointHandler).toSelf().inSingletonScope();
252
251
  bind(PluginMenuCommandAdapter).toSelf().inSingletonScope();
253
- bind(CodeEditorWidgetUtil).toSelf().inSingletonScope();
254
252
  bind(KeybindingsContributionPointHandler).toSelf().inSingletonScope();
255
253
  bind(PluginContributionHandler).toSelf().inSingletonScope();
256
254
 
@@ -266,7 +264,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
266
264
  bind(CommentsService).to(PluginCommentService).inSingletonScope();
267
265
  bind(CommentingRangeDecorator).toSelf().inSingletonScope();
268
266
  bind(CommentsContribution).toSelf().inSingletonScope();
269
- bind(CommentsContextKeyService).toSelf().inSingletonScope();
267
+ bind(CommentsContext).toSelf().inSingletonScope();
270
268
 
271
269
  bind(WebviewFrontendSecurityWarnings).toSelf().inSingletonScope();
272
270
  bind(FrontendApplicationContribution).toService(WebviewFrontendSecurityWarnings);
@@ -8,6 +8,7 @@
8
8
  margin-left: 5px;
9
9
  cursor: pointer;
10
10
  }
11
+
11
12
  .comment-range-glyph:before {
12
13
  position: absolute;
13
14
  content: '';
@@ -36,6 +37,7 @@
36
37
  border-left: 3px solid var(--theia-editorGutter-commentRangeForeground);
37
38
  transition: opacity 0.5s;
38
39
  }
40
+
39
41
  .monaco-editor .comment-diff-added:before {
40
42
  background: var(--theia-editorGutter-commentRangeForeground);
41
43
  }
@@ -123,6 +125,7 @@
123
125
  }
124
126
 
125
127
  .monaco-editor .review-widget .body .review-comment .avatar-container {
128
+ margin-right: 8px !important;
126
129
  margin-top: 4px !important;
127
130
  }
128
131
 
@@ -138,7 +141,6 @@
138
141
  }
139
142
 
140
143
  .monaco-editor .review-widget .body .review-comment .review-comment-contents {
141
- padding-left: 20px;
142
144
  user-select: text;
143
145
  -webkit-user-select: text;
144
146
  width: 100%;
@@ -255,6 +257,12 @@
255
257
  max-width: 100%;
256
258
  }
257
259
 
260
+ .monaco-editor .review-widget .body .comment-form {
261
+ flex: 1;
262
+ margin: 0px;
263
+ /* Reset margin as it's handled by container */
264
+ }
265
+
258
266
  .monaco-editor .review-widget .body .comment-form .form-actions {
259
267
  display: none;
260
268
  }
@@ -130,9 +130,12 @@ export class TerminalServiceMainImpl implements TerminalServiceMain, TerminalLin
130
130
  }));
131
131
  this.toDispose.push(terminal.onData(data => {
132
132
  this.extProxy.$terminalOnInput(terminal.id, data);
133
- this.extProxy.$terminalStateChanged(terminal.id);
133
+ this.extProxy.$terminalOnInteraction(terminal.id);
134
134
  }));
135
135
 
136
+ this.toDispose.push(terminal.onShellTypeChanged(shellType => {
137
+ this.extProxy.$terminalShellTypeChanged(terminal.id, shellType);
138
+ }));
136
139
  this.observers.forEach((observer, id) => this.observeTerminal(id, terminal, observer));
137
140
  }
138
141
 
@@ -14,7 +14,7 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
  import { Event, Emitter } from '@theia/core';
17
- import { MonacoEditorModel, WillSaveMonacoModelEvent } from '@theia/monaco/lib/browser/monaco-editor-model';
17
+ import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model';
18
18
  import { injectable, inject } from '@theia/core/shared/inversify';
19
19
  import { MonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
20
20
  import { MonacoWorkspace } from '@theia/monaco/lib/browser/monaco-workspace';
@@ -30,13 +30,11 @@ export class EditorModelService {
30
30
  private onModelRemovedEmitter = new Emitter<MonacoEditorModel>();
31
31
  private modelDirtyEmitter = new Emitter<MonacoEditorModel>();
32
32
  private modelSavedEmitter = new Emitter<MonacoEditorModel>();
33
- private onModelWillSavedEmitter = new Emitter<WillSaveMonacoModelEvent>();
34
33
 
35
34
  readonly onModelDirtyChanged = this.modelDirtyEmitter.event;
36
35
  readonly onModelSaved = this.modelSavedEmitter.event;
37
36
  readonly onModelModeChanged = this.modelModeChangedEmitter.event;
38
37
  readonly onModelRemoved = this.onModelRemovedEmitter.event;
39
- readonly onModelWillSave = this.onModelWillSavedEmitter.event;
40
38
 
41
39
  constructor(@inject(MonacoTextModelService) monacoModelService: MonacoTextModelService,
42
40
  @inject(MonacoWorkspace) monacoWorkspace: MonacoWorkspace) {
@@ -63,9 +61,6 @@ export class EditorModelService {
63
61
  model.onDirtyChanged(_ => {
64
62
  this.modelDirtyEmitter.fire(model);
65
63
  });
66
- model.onWillSaveModel(willSaveModelEvent => {
67
- this.onModelWillSavedEmitter.fire(willSaveModelEvent);
68
- });
69
64
  }
70
65
 
71
66
  get onModelAdded(): Event<MonacoEditorModel> {