@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.
- package/README.md +6 -6
- package/i18n/nls.cs.json +117 -15
- package/i18n/nls.de.json +117 -15
- package/i18n/nls.es.json +117 -15
- package/i18n/nls.fr.json +117 -15
- package/i18n/nls.hu.json +117 -15
- package/i18n/nls.it.json +117 -15
- package/i18n/nls.ja.json +117 -15
- package/i18n/nls.json +121 -19
- package/i18n/nls.ko.json +117 -15
- package/i18n/nls.pl.json +117 -15
- package/i18n/nls.pt-br.json +117 -15
- package/i18n/nls.ru.json +117 -15
- package/i18n/nls.tr.json +117 -15
- package/i18n/nls.zh-cn.json +117 -15
- package/i18n/nls.zh-tw.json +117 -15
- package/lib/browser/catalog.json +15 -1
- package/lib/browser/dialogs/react-dialog.d.ts.map +1 -1
- package/lib/browser/dialogs/react-dialog.js +1 -0
- package/lib/browser/dialogs/react-dialog.js.map +1 -1
- package/lib/browser/json-schema-store.d.ts +2 -0
- package/lib/browser/json-schema-store.d.ts.map +1 -1
- package/lib/browser/json-schema-store.js +10 -3
- package/lib/browser/json-schema-store.js.map +1 -1
- package/lib/browser/menu/browser-menu-plugin.d.ts +1 -1
- package/lib/browser/menu/browser-menu-plugin.d.ts.map +1 -1
- package/lib/browser/menu/browser-menu-plugin.js +2 -2
- package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.d.ts +30 -16
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.d.ts.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js +115 -33
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.d.ts.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js +8 -3
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.d.ts +2 -2
- package/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item.d.ts.map +1 -1
- package/lib/browser/shell/theia-dock-panel.d.ts +1 -0
- package/lib/browser/shell/theia-dock-panel.d.ts.map +1 -1
- package/lib/browser/shell/theia-dock-panel.js +6 -0
- package/lib/browser/shell/theia-dock-panel.js.map +1 -1
- package/lib/browser/tree/tree-widget.d.ts.map +1 -1
- package/lib/browser/tree/tree-widget.js +2 -1
- package/lib/browser/tree/tree-widget.js.map +1 -1
- package/lib/browser/view-container.d.ts.map +1 -1
- package/lib/browser/view-container.js +2 -2
- package/lib/browser/view-container.js.map +1 -1
- package/lib/common/menu/menu-types.d.ts +1 -0
- package/lib/common/menu/menu-types.d.ts.map +1 -1
- package/lib/common/menu/menu-types.js.map +1 -1
- package/lib/common/stream.d.ts +9 -0
- package/lib/common/stream.d.ts.map +1 -1
- package/lib/common/stream.js +93 -2
- package/lib/common/stream.js.map +1 -1
- package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
- package/lib/electron-browser/menu/electron-main-menu-factory.js +10 -9
- package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
- package/package.json +6 -6
- package/src/browser/dialogs/react-dialog.tsx +1 -0
- package/src/browser/json-schema-store.ts +9 -1
- package/src/browser/menu/browser-menu-plugin.ts +3 -3
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.tsx +134 -35
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.ts +12 -6
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.tsx +2 -2
- package/src/browser/shell/tab-bar-toolbar/tab-toolbar-item.tsx +2 -2
- package/src/browser/shell/theia-dock-panel.ts +7 -0
- package/src/browser/tree/tree-widget.tsx +2 -1
- package/src/browser/view-container.ts +5 -5
- package/src/common/menu/menu-types.ts +2 -0
- package/src/common/stream.ts +102 -1
- 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
|
-
|
|
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
|
|
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
|
|
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:
|
|
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.
|
|
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
|
|
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:
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
|
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
|
|
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():
|
|
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 {
|
|
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
|
|
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
|
-
|
|
150
|
-
|
|
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
|
|
155
|
-
this.contextKeyService, this.contextMenuRenderer, child, undefined
|
|
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:
|
|
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
|
|
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:
|
|
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,
|
|
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 {
|
|
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
|
|
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:
|
|
105
|
+
menuNode: Submenu,
|
|
106
106
|
group: string | undefined,
|
|
107
107
|
menuPath?: MenuPath,
|
|
108
108
|
) {
|
|
109
|
-
super(effectiveMenuPath, commandRegistry, menuRegistry, contextKeyService, contextMenuRenderer, menuNode, group
|
|
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
|
}
|
package/src/common/stream.ts
CHANGED
|
@@ -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
|
-
|
|
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, [...
|
|
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(
|
|
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(
|
|
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(
|
|
218
|
-
checked: menu.isToggled(
|
|
219
|
-
enabled: !honorDisabled || menu.isEnabled(
|
|
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(
|
|
225
|
-
const isToggled = menu.isToggled(
|
|
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;
|