@theia/core 1.65.0-next.55 → 1.65.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 (73) hide show
  1. package/README.md +6 -6
  2. package/i18n/nls.cs.json +117 -15
  3. package/i18n/nls.de.json +117 -15
  4. package/i18n/nls.es.json +117 -15
  5. package/i18n/nls.fr.json +117 -15
  6. package/i18n/nls.hu.json +117 -15
  7. package/i18n/nls.it.json +117 -15
  8. package/i18n/nls.ja.json +117 -15
  9. package/i18n/nls.json +121 -19
  10. package/i18n/nls.ko.json +117 -15
  11. package/i18n/nls.pl.json +117 -15
  12. package/i18n/nls.pt-br.json +117 -15
  13. package/i18n/nls.ru.json +117 -15
  14. package/i18n/nls.tr.json +117 -15
  15. package/i18n/nls.zh-cn.json +117 -15
  16. package/i18n/nls.zh-tw.json +117 -15
  17. package/lib/browser/catalog.json +15 -1
  18. package/lib/browser/dialogs/react-dialog.d.ts.map +1 -1
  19. package/lib/browser/dialogs/react-dialog.js +1 -0
  20. package/lib/browser/dialogs/react-dialog.js.map +1 -1
  21. package/lib/browser/json-schema-store.d.ts +2 -0
  22. package/lib/browser/json-schema-store.d.ts.map +1 -1
  23. package/lib/browser/json-schema-store.js +10 -3
  24. package/lib/browser/json-schema-store.js.map +1 -1
  25. package/lib/browser/menu/browser-menu-plugin.d.ts +1 -1
  26. package/lib/browser/menu/browser-menu-plugin.d.ts.map +1 -1
  27. package/lib/browser/menu/browser-menu-plugin.js +2 -2
  28. package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
  29. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.d.ts +30 -16
  30. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.d.ts.map +1 -1
  31. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js +115 -33
  32. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js.map +1 -1
  33. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.d.ts.map +1 -1
  34. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js +8 -3
  35. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js.map +1 -1
  36. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js +1 -1
  37. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js.map +1 -1
  38. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.d.ts +2 -2
  39. package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.d.ts.map +1 -1
  40. package/lib/browser/shell/theia-dock-panel.d.ts +1 -0
  41. package/lib/browser/shell/theia-dock-panel.d.ts.map +1 -1
  42. package/lib/browser/shell/theia-dock-panel.js +6 -0
  43. package/lib/browser/shell/theia-dock-panel.js.map +1 -1
  44. package/lib/browser/tree/tree-widget.d.ts.map +1 -1
  45. package/lib/browser/tree/tree-widget.js +2 -1
  46. package/lib/browser/tree/tree-widget.js.map +1 -1
  47. package/lib/browser/view-container.d.ts.map +1 -1
  48. package/lib/browser/view-container.js +2 -2
  49. package/lib/browser/view-container.js.map +1 -1
  50. package/lib/common/menu/menu-types.d.ts +1 -0
  51. package/lib/common/menu/menu-types.d.ts.map +1 -1
  52. package/lib/common/menu/menu-types.js.map +1 -1
  53. package/lib/common/stream.d.ts +9 -0
  54. package/lib/common/stream.d.ts.map +1 -1
  55. package/lib/common/stream.js +93 -2
  56. package/lib/common/stream.js.map +1 -1
  57. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
  58. package/lib/electron-browser/menu/electron-main-menu-factory.js +10 -9
  59. package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
  60. package/package.json +6 -6
  61. package/src/browser/dialogs/react-dialog.tsx +1 -0
  62. package/src/browser/json-schema-store.ts +9 -1
  63. package/src/browser/menu/browser-menu-plugin.ts +3 -3
  64. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.tsx +134 -35
  65. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.ts +12 -6
  66. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.tsx +2 -2
  67. package/src/browser/shell/tab-bar-toolbar/tab-toolbar-item.tsx +2 -2
  68. package/src/browser/shell/theia-dock-panel.ts +7 -0
  69. package/src/browser/tree/tree-widget.tsx +2 -1
  70. package/src/browser/view-container.ts +5 -5
  71. package/src/common/menu/menu-types.ts +2 -0
  72. package/src/common/stream.ts +102 -1
  73. package/src/electron-browser/menu/electron-main-menu-factory.ts +11 -9
@@ -23,37 +23,36 @@ import { ACTION_ITEM, codicon } from '../../widgets';
23
23
  import { ContextMenuRenderer } from '../../context-menu-renderer';
24
24
  import { TabBarToolbarItem } from './tab-toolbar-item';
25
25
  import { ContextKeyService, ContextMatcher } from '../../context-key-service';
26
- import { CommandMenu, CompoundMenuNode, MenuModelRegistry, MenuNode, MenuPath, RenderedMenuNode } from '../../../common/menu';
26
+ import { CommandMenu, CompoundMenuNode, ContextExpressionMatcher, Group, MenuModelRegistry, MenuNode, MenuPath, RenderedMenuNode, Submenu } from '../../../common/menu';
27
27
 
28
28
  export const TOOLBAR_WRAPPER_ID_SUFFIX = '-as-tabbar-toolbar-item';
29
29
 
30
30
  abstract class AbstractToolbarMenuWrapper {
31
31
 
32
32
  constructor(
33
- protected readonly effectiveMenuPath: MenuPath,
33
+ readonly effectiveMenuPath: MenuPath,
34
34
  protected readonly commandRegistry: CommandRegistry,
35
35
  protected readonly menuRegistry: MenuModelRegistry,
36
36
  protected readonly contextKeyService: ContextKeyService,
37
37
  protected readonly contextMenuRenderer: ContextMenuRenderer) {
38
38
  }
39
39
 
40
- protected abstract menuPath?: MenuPath;
41
- protected abstract menuNode?: MenuNode;
40
+ protected abstract menuNode: MenuNode | undefined;
42
41
  protected abstract id: string;
43
42
  protected abstract icon: string | undefined;
44
43
  protected abstract tooltip: string | undefined;
45
44
  protected abstract text: string | undefined;
46
- protected abstract executeCommand(e: React.MouseEvent<HTMLDivElement, MouseEvent>): void;
45
+ protected abstract executeCommand(widget: Widget, e: React.MouseEvent<HTMLDivElement, MouseEvent>): void;
47
46
 
48
- isEnabled(): boolean {
47
+ isEnabled(widget: Widget): boolean {
49
48
  if (CommandMenu.is(this.menuNode)) {
50
- return this.menuNode.isEnabled(this.effectiveMenuPath);
49
+ return this.menuNode.isEnabled(this.effectiveMenuPath, widget);
51
50
  }
52
51
  return true;
53
52
  }
54
- isToggled(): boolean {
53
+ isToggled(widget: Widget): boolean {
55
54
  if (CommandMenu.is(this.menuNode) && this.menuNode.isToggled) {
56
- return !!this.menuNode.isToggled(this.effectiveMenuPath);
55
+ return !!this.menuNode.isToggled(this.effectiveMenuPath, widget);
57
56
  }
58
57
  return false;
59
58
  }
@@ -61,9 +60,7 @@ abstract class AbstractToolbarMenuWrapper {
61
60
  return this.renderMenuItem(widget);
62
61
  }
63
62
 
64
- toMenuNode?(): MenuNode | undefined {
65
- return this.menuNode;
66
- }
63
+ abstract toMenuNode(): MenuNode | undefined;
67
64
 
68
65
  /**
69
66
  * Presents the menu to popup on the `event` that is the clicking of
@@ -78,7 +75,7 @@ abstract class AbstractToolbarMenuWrapper {
78
75
  const anchor = toAnchor(event);
79
76
 
80
77
  this.contextMenuRenderer.render({
81
- menuPath: menuPath,
78
+ menuPath: this.effectiveMenuPath,
82
79
  menu: this.menuNode as CompoundMenuNode,
83
80
  args: [widget],
84
81
  anchor,
@@ -102,9 +99,9 @@ abstract class AbstractToolbarMenuWrapper {
102
99
  return <div key={this.id} className={TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM + ' enabled menu'}>
103
100
  <div className={className}
104
101
  title={this.tooltip || this.text}
105
- onClick={e => this.executeCommand(e)}
102
+ onClick={e => this.executeCommand(widget, e)}
106
103
  />
107
- <div className={ACTION_ITEM} onClick={event => this.showPopupMenu(widget, this.menuPath!, event, contextMatcher)} >
104
+ <div className={ACTION_ITEM} onClick={event => this.showPopupMenu(widget, this.effectiveMenuPath!, event, contextMatcher)} >
108
105
  <div className={codicon('chevron-down') + ' chevron'} />
109
106
  </div>
110
107
  </div>;
@@ -112,41 +109,67 @@ abstract class AbstractToolbarMenuWrapper {
112
109
  return <div key={this.id} className={TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM + ' enabled menu'}>
113
110
  <div className={className}
114
111
  title={this.tooltip || this.text}
115
- onClick={e => this.executeCommand(e)}
112
+ onClick={e => this.executeCommand(widget, e)}
116
113
  />
117
114
  </div>;
118
115
  }
119
116
  }
120
117
  }
121
118
 
122
- export class ToolbarMenuNodeWrapper extends AbstractToolbarMenuWrapper implements TabBarToolbarItem {
119
+ export class SubmenuAsToolbarItemWrapper extends AbstractToolbarMenuWrapper implements TabBarToolbarItem {
123
120
  constructor(
124
121
  effectiveMenuPath: MenuPath,
125
122
  commandRegistry: CommandRegistry,
126
123
  menuRegistry: MenuModelRegistry,
127
124
  contextKeyService: ContextKeyService,
128
125
  contextMenuRenderer: ContextMenuRenderer,
129
- protected readonly menuNode: MenuNode & RenderedMenuNode,
130
- readonly group: string | undefined,
131
- readonly menuPath?: MenuPath) {
126
+ protected readonly menuNode: Submenu,
127
+ readonly group: string | undefined) {
132
128
  super(effectiveMenuPath, commandRegistry, menuRegistry, contextKeyService, contextMenuRenderer);
133
129
  }
130
+ priority?: number | undefined;
134
131
 
135
- executeCommand(e: React.MouseEvent<HTMLDivElement, MouseEvent>): void {
136
- if (CommandMenu.is(this.menuNode)) {
137
- this.menuNode.run(this.effectiveMenuPath);
138
- }
132
+ executeCommand(widget: Widget, e: React.MouseEvent<HTMLDivElement, MouseEvent>): void {
139
133
  }
140
134
 
141
135
  isVisible(widget: Widget): boolean {
142
- const menuNodeVisible = this.menuNode.isVisible(this.effectiveMenuPath, this.contextKeyService, widget.node);
143
- if (CommandMenu.is(this.menuNode)) {
144
- return menuNodeVisible;
145
- } else if (CompoundMenuNode.is(this.menuNode)) {
146
- return menuNodeVisible && !MenuModelRegistry.isEmpty(this.menuNode);
147
- } else {
148
- return menuNodeVisible;
149
- }
136
+ const menuNodeVisible = this.menuNode.isVisible(this.effectiveMenuPath, this.contextKeyService, widget.node, widget);
137
+ return menuNodeVisible && !MenuModelRegistry.isEmpty(this.menuNode);
138
+ }
139
+
140
+ get id(): string { return this.menuNode.id + TOOLBAR_WRAPPER_ID_SUFFIX; }
141
+ get icon(): string | undefined { return this.menuNode.icon; }
142
+ get tooltip(): string | undefined { return this.menuNode.label; }
143
+ get text(): string | undefined {
144
+ return (this.group === NAVIGATION || this.group === undefined) ? undefined : this.menuNode.label;
145
+ }
146
+ get onDidChange(): Event<void> | undefined {
147
+ return this.menuNode.onDidChange;
148
+ }
149
+
150
+ override toMenuNode(): Group | undefined {
151
+ return new ToolbarItemAsSubmenuWrapper(this.menuNode!, this.effectiveMenuPath);
152
+ };
153
+ }
154
+
155
+ export class CommandMenuAsToolbarItemWrapper extends AbstractToolbarMenuWrapper implements TabBarToolbarItem {
156
+ constructor(
157
+ effectiveMenuPath: MenuPath,
158
+ commandRegistry: CommandRegistry,
159
+ menuRegistry: MenuModelRegistry,
160
+ contextKeyService: ContextKeyService,
161
+ contextMenuRenderer: ContextMenuRenderer,
162
+ protected readonly menuNode: CommandMenu,
163
+ readonly group: string | undefined) {
164
+ super(effectiveMenuPath, commandRegistry, menuRegistry, contextKeyService, contextMenuRenderer);
165
+ }
166
+
167
+ isVisible(widget: Widget): boolean {
168
+ return this.menuNode.isVisible(this.effectiveMenuPath, this.contextKeyService, widget.node, widget);
169
+ }
170
+
171
+ executeCommand(widget: Widget, e: React.MouseEvent<HTMLDivElement, MouseEvent>): void {
172
+ this.menuNode.run(this.effectiveMenuPath, widget);
150
173
  }
151
174
 
152
175
  get id(): string { return this.menuNode.id + TOOLBAR_WRAPPER_ID_SUFFIX; }
@@ -158,9 +181,13 @@ export class ToolbarMenuNodeWrapper extends AbstractToolbarMenuWrapper implement
158
181
  get onDidChange(): Event<void> | undefined {
159
182
  return this.menuNode.onDidChange;
160
183
  }
184
+
185
+ override toMenuNode(): MenuNode | undefined {
186
+ return new ToolbarItemAsCommandMenuWrapper(this.menuNode, this.effectiveMenuPath);
187
+ }
161
188
  }
162
189
 
163
- export class ToolbarSubmenuWrapper extends AbstractToolbarMenuWrapper implements TabBarToolbarItem {
190
+ export class ToolbarActionWrapper extends AbstractToolbarMenuWrapper implements TabBarToolbarItem {
164
191
  constructor(
165
192
  effectiveMenuPath: MenuPath,
166
193
  commandRegistry: CommandRegistry,
@@ -176,7 +203,7 @@ export class ToolbarSubmenuWrapper extends AbstractToolbarMenuWrapper implements
176
203
  return this.toolbarItem.command ? this.commandRegistry.isEnabled(this.toolbarItem.command, widget) : !!this.toolbarItem.menuPath;
177
204
  }
178
205
 
179
- protected executeCommand(e: React.MouseEvent<HTMLElement>, widget?: Widget): void {
206
+ protected executeCommand(widget: Widget, e: React.MouseEvent<HTMLElement>): void {
180
207
  e.preventDefault();
181
208
  e.stopPropagation();
182
209
 
@@ -232,8 +259,80 @@ export class ToolbarSubmenuWrapper extends AbstractToolbarMenuWrapper implements
232
259
  return this.toolbarItem.menuPath!;
233
260
  }
234
261
 
235
- get menuNode(): MenuNode | undefined {
262
+ get menuNode(): CompoundMenuNode | undefined {
236
263
  return this.menuRegistry.getMenu(this.menuPath);
237
264
  }
265
+
266
+ override toMenuNode(): MenuNode | undefined {
267
+ return new ToolbarItemAsSubmenuWrapper(this.menuNode!, this.effectiveMenuPath);
268
+ }
238
269
  }
239
270
 
271
+ /**
272
+ * This class wraps a menu node, but replaces the effective menu path. Command parameters need to be mapped
273
+ * for commands contributed by extension and this mapping is keyed by the menu path
274
+ */
275
+ abstract class AbstractMenuNodeAsToolbarItemWrapper<T extends MenuNode> {
276
+ constructor(protected readonly menuNode: T, readonly effectiveMenuPath: MenuPath) { }
277
+
278
+ get label(): string | undefined {
279
+ if (RenderedMenuNode.is(this.menuNode)) {
280
+ return this.menuNode.label;
281
+ }
282
+ };
283
+ /**
284
+ * Icon classes for the menu node. If present, these will produce an icon to the left of the label in browser-style menus.
285
+ */
286
+ get icon(): string | undefined {
287
+ if (RenderedMenuNode.is(this.menuNode)) {
288
+ return this.menuNode.label;
289
+ }
290
+ }
291
+ get id(): string {
292
+ return this.menuNode.id;
293
+ }
294
+ get sortString(): string {
295
+ return this.menuNode.sortString;
296
+ }
297
+
298
+ isVisible<K>(effectiveMenuPath: MenuPath, contextMatcher: ContextExpressionMatcher<K>, context: K | undefined, ...args: unknown[]): boolean {
299
+ return this.menuNode!.isVisible(this.effectiveMenuPath, contextMatcher, context, args);
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Wrapper form submenu nodes
305
+ */
306
+ class ToolbarItemAsSubmenuWrapper extends AbstractMenuNodeAsToolbarItemWrapper<CompoundMenuNode> implements Group {
307
+
308
+ get contextKeyOverlays(): Record<string, string> | undefined {
309
+ return this.menuNode.contextKeyOverlays;
310
+ }
311
+ isEmpty<T>(effectiveMenuPath: MenuPath, contextMatcher: ContextExpressionMatcher<T>, context: T | undefined, ...args: unknown[]): boolean {
312
+ return this.menuNode.isEmpty(this.effectiveMenuPath, contextMatcher, context, args);
313
+ }
314
+ get children(): MenuNode[] {
315
+ return this.menuNode.children;
316
+ }
317
+
318
+ }
319
+ /**
320
+ * Wrapper for command menus
321
+ */
322
+ class ToolbarItemAsCommandMenuWrapper extends AbstractMenuNodeAsToolbarItemWrapper<CommandMenu> implements CommandMenu {
323
+
324
+ isEnabled(effectiveMenuPath: MenuPath, ...args: unknown[]): boolean {
325
+ return this.menuNode.isEnabled(this.effectiveMenuPath, ...args);
326
+ }
327
+ isToggled(effectiveMenuPath: MenuPath, ...args: unknown[]): boolean {
328
+ return this.menuNode.isToggled(this.effectiveMenuPath, ...args);
329
+ }
330
+ run(effectiveMenuPath: MenuPath, ...args: unknown[]): Promise<void> {
331
+ return this.menuNode.run(this.effectiveMenuPath, args);
332
+ }
333
+
334
+ override get label(): string {
335
+ return super.label!;
336
+ }
337
+
338
+ }
@@ -22,7 +22,7 @@ import { ContextKeyService } from '../../context-key-service';
22
22
  import { FrontendApplicationContribution } from '../../frontend-application-contribution';
23
23
  import { Widget } from '../../widgets';
24
24
  import { ReactTabBarToolbarAction, RenderedToolbarAction } from './tab-bar-toolbar-types';
25
- import { ToolbarMenuNodeWrapper, ToolbarSubmenuWrapper } from './tab-bar-toolbar-menu-adapters';
25
+ import { CommandMenuAsToolbarItemWrapper, SubmenuAsToolbarItemWrapper, ToolbarActionWrapper } from './tab-bar-toolbar-menu-adapters';
26
26
  import { KeybindingRegistry } from '../../keybinding';
27
27
  import { LabelParser } from '../../label-parser';
28
28
  import { ContextMenuRenderer } from '../../context-menu-renderer';
@@ -90,7 +90,7 @@ export class TabBarToolbarRegistry implements FrontendApplicationContribution {
90
90
  return this.doRegisterItem(new ReactToolbarItemImpl(this.commandRegistry, this.contextKeyService, item));
91
91
  } else {
92
92
  if (item.menuPath) {
93
- return this.doRegisterItem(new ToolbarSubmenuWrapper(item.menuPath,
93
+ return this.doRegisterItem(new ToolbarActionWrapper(item.menuPath,
94
94
  this.commandRegistry, this.menuRegistry, this.contextKeyService, this.contextMenuRenderer, item));
95
95
  } else {
96
96
  const wrapper = new RenderedToolbarItemImpl(this.commandRegistry, this.contextKeyService, this.keybindingRegistry, this.labelParser, item);
@@ -146,13 +146,19 @@ export class TabBarToolbarRegistry implements FrontendApplicationContribution {
146
146
  for (const grandchild of child.children) {
147
147
  if (grandchild.isVisible([...delegate.menuPath, child.id, grandchild.id],
148
148
  this.contextKeyService, widget.node) && RenderedMenuNode.is(grandchild)) {
149
- result.push(new ToolbarMenuNodeWrapper([...delegate.menuPath, child.id, grandchild.id], this.commandRegistry, this.menuRegistry,
150
- this.contextKeyService, this.contextMenuRenderer, grandchild, child.id, delegate.menuPath));
149
+ if (CommandMenu.is(grandchild)) {
150
+ result.push(new CommandMenuAsToolbarItemWrapper([...delegate.menuPath, child.id, grandchild.id], this.commandRegistry,
151
+ this.menuRegistry, this.contextKeyService, this.contextMenuRenderer, grandchild, child.id));
152
+ } else if (CompoundMenuNode.is(grandchild)) {
153
+ result.push(new SubmenuAsToolbarItemWrapper([...delegate.menuPath, child.id, grandchild.id], this.commandRegistry, this.menuRegistry,
154
+ this.contextKeyService, this.contextMenuRenderer, grandchild, child.id));
155
+ }
156
+
151
157
  }
152
158
  }
153
159
  } else if (CommandMenu.is(child)) {
154
- result.push(new ToolbarMenuNodeWrapper([...delegate.menuPath, child.id], this.commandRegistry, this.menuRegistry,
155
- this.contextKeyService, this.contextMenuRenderer, child, undefined, delegate.menuPath));
160
+ result.push(new CommandMenuAsToolbarItemWrapper([...delegate.menuPath, child.id], this.commandRegistry, this.menuRegistry,
161
+ this.contextKeyService, this.contextMenuRenderer, child, undefined));
156
162
  }
157
163
  }
158
164
  }
@@ -22,7 +22,7 @@ import { Anchor, ContextMenuAccess, ContextMenuRenderer } from '../../context-me
22
22
  import { LabelParser } from '../../label-parser';
23
23
  import { codicon, ReactWidget, Widget } from '../../widgets';
24
24
  import { TabBarToolbarRegistry } from './tab-bar-toolbar-registry';
25
- import { TabBarDelegator, TabBarToolbarAction } from './tab-bar-toolbar-types';
25
+ import { TAB_BAR_TOOLBAR_CONTEXT_MENU, TabBarDelegator, TabBarToolbarAction } from './tab-bar-toolbar-types';
26
26
  import { KeybindingRegistry } from '../..//keybinding';
27
27
  import { TabBarToolbarItem } from './tab-toolbar-item';
28
28
  import { GroupImpl, MenuModelRegistry } from '../../../common/menu';
@@ -173,7 +173,7 @@ export class TabBarToolbar extends ReactWidget {
173
173
  }
174
174
  return this.contextMenuRenderer.render({
175
175
  menu: MenuModelRegistry.removeSingleRootNodes(menu),
176
- menuPath: ['contextMenu'],
176
+ menuPath: TAB_BAR_TOOLBAR_CONTEXT_MENU,
177
177
  args: [this.current],
178
178
  anchor,
179
179
  context: this.current?.node || this.node,
@@ -28,8 +28,8 @@ import { ActionMenuNode, GroupImpl, MenuNode } from '../../../common/menu';
28
28
  export interface TabBarToolbarItem {
29
29
  id: string;
30
30
  isVisible(widget: Widget): boolean;
31
- isEnabled(widget?: Widget): boolean;
32
- isToggled(): boolean;
31
+ isEnabled(widget: Widget): boolean;
32
+ isToggled(widget: Widget): boolean;
33
33
  render(widget?: Widget): React.ReactNode;
34
34
  onDidChange?: Event<void>;
35
35
  group?: string;
@@ -241,6 +241,13 @@ export class TheiaDockPanel extends DockPanel {
241
241
  }
242
242
  return undefined;
243
243
  }
244
+
245
+ override dispose(): void {
246
+ super.dispose();
247
+ this.onDidChangeCurrentEmitter.dispose();
248
+ this._currentTitle = undefined;
249
+ this.toDisposeOnMarkAsCurrent.dispose();
250
+ }
244
251
  }
245
252
  export namespace TheiaDockPanel {
246
253
  export const Factory = Symbol('TheiaDockPanel#Factory');
@@ -1442,9 +1442,10 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
1442
1442
  if (contextMenuPath) {
1443
1443
  const { x, y } = event.nativeEvent;
1444
1444
  const args = this.toContextMenuArgs(node);
1445
+ const target = event.currentTarget;
1445
1446
  setTimeout(() => this.contextMenuRenderer.render({
1446
1447
  menuPath: contextMenuPath,
1447
- context: event.currentTarget,
1448
+ context: target,
1448
1449
  anchor: { x, y },
1449
1450
  args
1450
1451
  }), 10);
@@ -23,7 +23,7 @@ import {
23
23
  import { Event as CommonEvent, Emitter } from '../common/event';
24
24
  import { Disposable, DisposableCollection } from '../common/disposable';
25
25
  import { CommandRegistry } from '../common/command';
26
- import { MenuModelRegistry, MenuPath, MenuAction, SubmenuImpl, ActionMenuNode, MenuNode, RenderedMenuNode } from '../common/menu';
26
+ import { MenuModelRegistry, MenuPath, MenuAction, SubmenuImpl, ActionMenuNode, Submenu } from '../common/menu';
27
27
  import { ApplicationShell, StatefulWidget, SplitPositionHandler, SplitPositionOptions, SIDE_PANEL_TOOLBAR_CONTEXT_MENU } from './shell';
28
28
  import { MAIN_AREA_ID, BOTTOM_AREA_ID } from './shell/theia-dock-panel';
29
29
  import { FrontendApplicationStateService } from './frontend-application-state';
@@ -40,7 +40,7 @@ import { ElementExt } from '@lumino/domutils';
40
40
  import { TabBarDecoratorService } from './shell/tab-bar-decorator';
41
41
  import { ContextKeyService } from './context-key-service';
42
42
  import { KeybindingRegistry } from './keybinding';
43
- import { ToolbarMenuNodeWrapper } from './shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters';
43
+ import { SubmenuAsToolbarItemWrapper } from './shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters';
44
44
  import { TheiaSplitPanel } from './shell/theia-split-panel';
45
45
 
46
46
  export interface ViewContainerTitleOptions {
@@ -94,7 +94,7 @@ export namespace DynamicToolbarWidget {
94
94
  }
95
95
  }
96
96
 
97
- class PartsMenuToolbarItem extends ToolbarMenuNodeWrapper {
97
+ class PartsMenuToolbarItem extends SubmenuAsToolbarItemWrapper {
98
98
  constructor(
99
99
  protected readonly target: () => Widget | undefined,
100
100
  effectiveMenuPath: MenuPath,
@@ -102,11 +102,11 @@ class PartsMenuToolbarItem extends ToolbarMenuNodeWrapper {
102
102
  menuRegistry: MenuModelRegistry,
103
103
  contextKeyService: ContextKeyService,
104
104
  contextMenuRenderer: ContextMenuRenderer,
105
- menuNode: MenuNode & RenderedMenuNode,
105
+ menuNode: Submenu,
106
106
  group: string | undefined,
107
107
  menuPath?: MenuPath,
108
108
  ) {
109
- super(effectiveMenuPath, commandRegistry, menuRegistry, contextKeyService, contextMenuRenderer, menuNode, group, menuPath);
109
+ super(effectiveMenuPath, commandRegistry, menuRegistry, contextKeyService, contextMenuRenderer, menuNode, group);
110
110
  }
111
111
 
112
112
  override isVisible(widget: Widget): boolean {
@@ -39,6 +39,8 @@ export interface MenuNode {
39
39
  * Menu nodes are sorted in ascending order based on their `sortString`.
40
40
  */
41
41
  readonly sortString: string;
42
+
43
+ readonly effectiveMenuPath?: string[]; // override the path to be passed as the effectiveMenuPath
42
44
  isVisible<T>(effectiveMenuPath: MenuPath, contextMatcher: ContextExpressionMatcher<T>, context: T | undefined, ...args: unknown[]): boolean;
43
45
  onDidChange?: Event<void>;
44
46
  }
@@ -26,6 +26,7 @@
26
26
  /* eslint-disable @typescript-eslint/no-explicit-any */
27
27
 
28
28
  import { DisposableCollection, Disposable } from './disposable';
29
+ import { BinaryBuffer } from './buffer';
29
30
 
30
31
  export interface ReadableStreamEvents<T> {
31
32
 
@@ -205,7 +206,7 @@ export interface ITransformer<Original, Transformed> {
205
206
  }
206
207
 
207
208
  export function newWriteableStream<T>(reducer: Reducer<T>, options?: WriteableStreamOptions): WriteableStream<T> {
208
- return new WriteableStreamImpl<T>(reducer);
209
+ return new WriteableStreamImpl<T>(reducer, options);
209
210
  }
210
211
 
211
212
  export interface WriteableStreamOptions {
@@ -716,3 +717,103 @@ export function transform<Original, Transformed>(stream: ReadableStreamEvents<Or
716
717
 
717
718
  return target;
718
719
  }
720
+
721
+ /**
722
+ * Convert File to ReadableStream<BinaryBuffer> for use in services which require ReadableStream
723
+ */
724
+ export function fileToStream(file: File): ReadableStream<BinaryBuffer> {
725
+ const ws = newWriteableStream<BinaryBuffer>(BinaryBuffer.concat, { highWaterMark: 0 });
726
+
727
+ (async () => {
728
+ const reader = file.stream().getReader();
729
+
730
+ try {
731
+ while (true) {
732
+ const { value, done } = await reader.read();
733
+ if (done) {break;}
734
+
735
+ if (value?.byteLength) {
736
+ await ws.write(BinaryBuffer.wrap(value));
737
+ }
738
+ }
739
+ ws.end();
740
+ } catch (e: unknown) {
741
+ try {
742
+ await reader.cancel();
743
+ } catch {}
744
+
745
+ ws.error(e instanceof Error ? e : new Error(String(e)));
746
+ }
747
+ })();
748
+
749
+ return ws as ReadableStream<BinaryBuffer>;
750
+ }
751
+
752
+ /**
753
+ * Convert BinaryBufferReadableStream to Web ReadableStream<Uint8Array>
754
+ */
755
+ export function binaryStreamToWebStream(
756
+ binaryStream: ReadableStream<BinaryBuffer>,
757
+ abortSignal?: AbortSignal
758
+ ): globalThis.ReadableStream<Uint8Array> {
759
+ return new globalThis.ReadableStream<Uint8Array>({
760
+ start(controller) {
761
+ const cleanup = () => {
762
+ // Remove all event listeners
763
+ binaryStream.removeListener('data', onData);
764
+ binaryStream.removeListener('end', onEnd);
765
+ binaryStream.removeListener('error', onError);
766
+ };
767
+
768
+ const onAbort = () => {
769
+ cleanup();
770
+ controller.error(new Error('Operation aborted'));
771
+ };
772
+
773
+ if (abortSignal?.aborted) {
774
+ onAbort();
775
+ return;
776
+ }
777
+
778
+ if (abortSignal) {
779
+ abortSignal.addEventListener('abort', onAbort, { once: true });
780
+ }
781
+
782
+ const onData = (chunk: BinaryBuffer) => {
783
+ if (abortSignal?.aborted) {
784
+ return;
785
+ }
786
+ try {
787
+ // Convert BinaryBuffer to Uint8Array efficiently
788
+ controller.enqueue(new Uint8Array(chunk.buffer));
789
+ } catch (error) {
790
+ cleanup();
791
+ if (abortSignal) {
792
+ abortSignal.removeEventListener('abort', onAbort);
793
+ }
794
+ controller.error(error);
795
+ }
796
+ };
797
+
798
+ const onEnd = () => {
799
+ cleanup();
800
+ if (abortSignal) {
801
+ abortSignal.removeEventListener('abort', onAbort);
802
+ }
803
+ controller.close();
804
+ };
805
+
806
+ const onError = (error: Error) => {
807
+ cleanup();
808
+ if (abortSignal) {
809
+ abortSignal.removeEventListener('abort', onAbort);
810
+ }
811
+ controller.error(error);
812
+ };
813
+
814
+ binaryStream.on('data', onData);
815
+ binaryStream.on('end', onEnd);
816
+ binaryStream.on('error', onError);
817
+ }
818
+ });
819
+ }
@@ -175,7 +175,9 @@ export class ElectronMainMenuFactory extends BrowserMainMenuFactory {
175
175
  const showDisabled = options?.showDisabled !== false;
176
176
  const honorDisabled = options?.honorDisabled !== false;
177
177
 
178
- if (CompoundMenuNode.is(menu) && menu.children.length && menu.isVisible(menuPath, contextMatcher, options.context, ...args)) {
178
+ const effectivePath = menu.effectiveMenuPath || menuPath;
179
+
180
+ if (CompoundMenuNode.is(menu) && menu.children.length && menu.isVisible(effectivePath, contextMatcher, options.context, ...args)) {
179
181
  if (Group.is(menu) && menu.id === 'inline') {
180
182
  return parentItems;
181
183
  }
@@ -186,7 +188,7 @@ export class ElectronMainMenuFactory extends BrowserMainMenuFactory {
186
188
  }
187
189
  const children = menu.children;
188
190
  const myItems: MenuDto[] = [];
189
- children.forEach(child => this.fillMenuTemplate(myItems, [...menuPath, child.id], child, args, contextMatcher, options, false));
191
+ children.forEach(child => this.fillMenuTemplate(myItems, [...effectivePath, child.id], child, args, contextMatcher, options, false));
190
192
  if (myItems.length === 0) {
191
193
  return parentItems;
192
194
  }
@@ -200,12 +202,12 @@ export class ElectronMainMenuFactory extends BrowserMainMenuFactory {
200
202
  parentItems.push({ type: 'separator' });
201
203
  }
202
204
  } else if (CommandMenu.is(menu)) {
203
- if (!menu.isVisible(menuPath, contextMatcher, options.context, ...args)) {
205
+ if (!menu.isVisible(effectivePath, contextMatcher, options.context, ...args)) {
204
206
  return parentItems;
205
207
  }
206
208
 
207
209
  // We should omit rendering context-menu items which are disabled.
208
- if (!showDisabled && !menu.isEnabled(menuPath, ...args)) {
210
+ if (!showDisabled && !menu.isEnabled(effectivePath, ...args)) {
209
211
  return parentItems;
210
212
  }
211
213
 
@@ -214,15 +216,15 @@ export class ElectronMainMenuFactory extends BrowserMainMenuFactory {
214
216
  const menuItem: MenuDto = {
215
217
  id: menu.id,
216
218
  label: menu.label,
217
- type: menu.isToggled(menuPath, ...args) ? 'checkbox' : 'normal',
218
- checked: menu.isToggled(menuPath, ...args),
219
- enabled: !honorDisabled || menu.isEnabled(menuPath, ...args), // see https://github.com/eclipse-theia/theia/issues/446
219
+ type: menu.isToggled(effectivePath, ...args) ? 'checkbox' : 'normal',
220
+ checked: menu.isToggled(effectivePath, ...args),
221
+ enabled: !honorDisabled || menu.isEnabled(effectivePath, ...args), // see https://github.com/eclipse-theia/theia/issues/446
220
222
  visible: true,
221
223
  accelerator,
222
224
  execute: async () => {
223
225
  const wasToggled = menuItem.checked;
224
- await menu.run(menuPath, ...args);
225
- const isToggled = menu.isToggled(menuPath, ...args);
226
+ await menu.run(effectivePath, ...args);
227
+ const isToggled = menu.isToggled(effectivePath, ...args);
226
228
  if (isToggled !== wasToggled) {
227
229
  menuItem.type = isToggled ? 'checkbox' : 'normal';
228
230
  menuItem.checked = isToggled;