@theia/core 1.28.0-next.7 → 1.28.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 (206) hide show
  1. package/README.md +6 -6
  2. package/i18n/nls.cs.json +33 -2
  3. package/i18n/nls.de.json +33 -2
  4. package/i18n/nls.es.json +33 -2
  5. package/i18n/nls.fr.json +33 -2
  6. package/i18n/nls.hu.json +33 -2
  7. package/i18n/nls.it.json +33 -2
  8. package/i18n/nls.ja.json +33 -2
  9. package/i18n/nls.json +35 -4
  10. package/i18n/nls.pl.json +33 -2
  11. package/i18n/nls.pt-br.json +33 -2
  12. package/i18n/nls.pt-pt.json +33 -2
  13. package/i18n/nls.ru.json +33 -2
  14. package/i18n/nls.zh-cn.json +33 -2
  15. package/lib/browser/common-frontend-contribution.d.ts +1 -1
  16. package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
  17. package/lib/browser/common-frontend-contribution.js +6 -5
  18. package/lib/browser/common-frontend-contribution.js.map +1 -1
  19. package/lib/browser/context-key-service.d.ts +3 -1
  20. package/lib/browser/context-key-service.d.ts.map +1 -1
  21. package/lib/browser/context-menu-renderer.d.ts +5 -0
  22. package/lib/browser/context-menu-renderer.d.ts.map +1 -1
  23. package/lib/browser/frontend-application-module.d.ts.map +1 -1
  24. package/lib/browser/frontend-application-module.js +2 -0
  25. package/lib/browser/frontend-application-module.js.map +1 -1
  26. package/lib/browser/frontend-application.d.ts +3 -2
  27. package/lib/browser/frontend-application.d.ts.map +1 -1
  28. package/lib/browser/frontend-application.js.map +1 -1
  29. package/lib/browser/keybinding.d.ts.map +1 -1
  30. package/lib/browser/keybinding.js +9 -7
  31. package/lib/browser/keybinding.js.map +1 -1
  32. package/lib/browser/keybinding.spec.js +13 -3
  33. package/lib/browser/keybinding.spec.js.map +1 -1
  34. package/lib/browser/menu/browser-context-menu-renderer.d.ts +1 -1
  35. package/lib/browser/menu/browser-context-menu-renderer.d.ts.map +1 -1
  36. package/lib/browser/menu/browser-context-menu-renderer.js +2 -2
  37. package/lib/browser/menu/browser-context-menu-renderer.js.map +1 -1
  38. package/lib/browser/menu/browser-menu-plugin.d.ts +23 -24
  39. package/lib/browser/menu/browser-menu-plugin.d.ts.map +1 -1
  40. package/lib/browser/menu/browser-menu-plugin.js +62 -79
  41. package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
  42. package/lib/browser/resource-context-key.d.ts +1 -0
  43. package/lib/browser/resource-context-key.d.ts.map +1 -1
  44. package/lib/browser/resource-context-key.js +8 -6
  45. package/lib/browser/resource-context-key.js.map +1 -1
  46. package/lib/browser/shell/shell-layout-restorer.d.ts.map +1 -1
  47. package/lib/browser/shell/shell-layout-restorer.js +2 -1
  48. package/lib/browser/shell/shell-layout-restorer.js.map +1 -1
  49. package/lib/browser/shell/side-panel-toolbar.d.ts.map +1 -1
  50. package/lib/browser/shell/side-panel-toolbar.js +0 -1
  51. package/lib/browser/shell/side-panel-toolbar.js.map +1 -1
  52. package/lib/browser/shell/tab-bar-toolbar/index.d.ts +4 -0
  53. package/lib/browser/shell/tab-bar-toolbar/index.d.ts.map +1 -0
  54. package/lib/browser/shell/tab-bar-toolbar/index.js +31 -0
  55. package/lib/browser/shell/tab-bar-toolbar/index.js.map +1 -0
  56. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.d.ts +16 -0
  57. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.d.ts.map +1 -0
  58. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js +36 -0
  59. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js.map +1 -0
  60. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.d.ts +51 -0
  61. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.d.ts.map +1 -0
  62. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js +173 -0
  63. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js.map +1 -0
  64. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.d.ts +119 -0
  65. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.d.ts.map +1 -0
  66. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.js +67 -0
  67. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.js.map +1 -0
  68. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts +53 -0
  69. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts.map +1 -0
  70. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js +264 -0
  71. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js.map +1 -0
  72. package/lib/browser/shell/{tab-bar-toolbar.spec.d.ts → tab-bar-toolbar/tab-bar-toolbar.spec.d.ts} +0 -0
  73. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.d.ts.map +1 -0
  74. package/lib/browser/shell/{tab-bar-toolbar.spec.js → tab-bar-toolbar/tab-bar-toolbar.spec.js} +3 -3
  75. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.spec.js.map +1 -0
  76. package/lib/browser/view-container.d.ts.map +1 -1
  77. package/lib/browser/view-container.js +1 -10
  78. package/lib/browser/view-container.js.map +1 -1
  79. package/lib/browser/widget-manager.d.ts.map +1 -1
  80. package/lib/browser/widget-manager.js +2 -1
  81. package/lib/browser/widget-manager.js.map +1 -1
  82. package/lib/browser/widget-manager.spec.js +13 -0
  83. package/lib/browser/widget-manager.spec.js.map +1 -1
  84. package/lib/browser/window/default-window-service.d.ts +2 -1
  85. package/lib/browser/window/default-window-service.d.ts.map +1 -1
  86. package/lib/browser/window/default-window-service.js +9 -4
  87. package/lib/browser/window/default-window-service.js.map +1 -1
  88. package/lib/browser/window/window-service.d.ts +2 -1
  89. package/lib/browser/window/window-service.d.ts.map +1 -1
  90. package/lib/browser/window/window-service.js.map +1 -1
  91. package/lib/common/color.d.ts +3 -0
  92. package/lib/common/color.d.ts.map +1 -1
  93. package/lib/common/frontend-application-state.d.ts +14 -0
  94. package/lib/common/frontend-application-state.d.ts.map +1 -1
  95. package/lib/common/frontend-application-state.js +16 -0
  96. package/lib/common/frontend-application-state.js.map +1 -1
  97. package/lib/common/menu/action-menu-node.d.ts +20 -0
  98. package/lib/common/menu/action-menu-node.d.ts.map +1 -0
  99. package/lib/common/menu/action-menu-node.js +57 -0
  100. package/lib/common/menu/action-menu-node.js.map +1 -0
  101. package/lib/common/menu/composite-menu-node.d.ts +52 -0
  102. package/lib/common/menu/composite-menu-node.d.ts.map +1 -0
  103. package/lib/common/menu/composite-menu-node.js +102 -0
  104. package/lib/common/menu/composite-menu-node.js.map +1 -0
  105. package/lib/common/menu/index.d.ts +6 -0
  106. package/lib/common/menu/index.d.ts.map +1 -0
  107. package/lib/common/menu/index.js +33 -0
  108. package/lib/common/menu/index.js.map +1 -0
  109. package/lib/common/menu/menu-adapter.d.ts +36 -0
  110. package/lib/common/menu/menu-adapter.d.ts.map +1 -0
  111. package/lib/common/menu/menu-adapter.js +101 -0
  112. package/lib/common/menu/menu-adapter.js.map +1 -0
  113. package/lib/common/{menu.d.ts → menu/menu-model-registry.d.ts} +22 -124
  114. package/lib/common/menu/menu-model-registry.d.ts.map +1 -0
  115. package/lib/common/{menu.js → menu/menu-model-registry.js} +71 -147
  116. package/lib/common/menu/menu-model-registry.js.map +1 -0
  117. package/lib/common/menu/menu-types.d.ts +120 -0
  118. package/lib/common/menu/menu-types.d.ts.map +1 -0
  119. package/lib/common/menu/menu-types.js +84 -0
  120. package/lib/common/menu/menu-types.js.map +1 -0
  121. package/lib/common/{menu.spec.d.ts → menu/menu.spec.d.ts} +0 -0
  122. package/lib/common/menu/menu.spec.d.ts.map +1 -0
  123. package/lib/common/{menu.spec.js → menu/menu.spec.js} +3 -3
  124. package/lib/common/menu/menu.spec.js.map +1 -0
  125. package/lib/common/message-rpc/rpc-message-encoder.d.ts +12 -11
  126. package/lib/common/message-rpc/rpc-message-encoder.d.ts.map +1 -1
  127. package/lib/common/message-rpc/rpc-message-encoder.js +21 -12
  128. package/lib/common/message-rpc/rpc-message-encoder.js.map +1 -1
  129. package/lib/common/messaging/abstract-connection-provider.d.ts +1 -1
  130. package/lib/common/messaging/abstract-connection-provider.js +3 -3
  131. package/lib/common/quick-pick-service.d.ts +1 -0
  132. package/lib/common/quick-pick-service.d.ts.map +1 -1
  133. package/lib/common/quick-pick-service.js.map +1 -1
  134. package/lib/electron-browser/menu/electron-context-menu-renderer.js +2 -2
  135. package/lib/electron-browser/menu/electron-context-menu-renderer.js.map +1 -1
  136. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts +14 -5
  137. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
  138. package/lib/electron-browser/menu/electron-main-menu-factory.js +71 -82
  139. package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
  140. package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
  141. package/lib/electron-browser/menu/electron-menu-contribution.js +6 -0
  142. package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
  143. package/lib/electron-browser/messaging/electron-ws-connection-provider.js +1 -1
  144. package/lib/electron-browser/window/electron-window-service.js +1 -1
  145. package/lib/electron-browser/window/electron-window-service.js.map +1 -1
  146. package/lib/electron-common/messaging/electron-messages.d.ts +3 -14
  147. package/lib/electron-common/messaging/electron-messages.d.ts.map +1 -1
  148. package/lib/electron-common/messaging/electron-messages.js +3 -16
  149. package/lib/electron-common/messaging/electron-messages.js.map +1 -1
  150. package/lib/electron-main/messaging/electron-messaging-contribution.d.ts +3 -3
  151. package/lib/electron-main/messaging/electron-messaging-contribution.js +6 -6
  152. package/package.json +7 -6
  153. package/src/browser/common-frontend-contribution.ts +6 -5
  154. package/src/browser/context-key-service.ts +1 -1
  155. package/src/browser/context-menu-renderer.ts +5 -0
  156. package/src/browser/frontend-application-module.ts +7 -1
  157. package/src/browser/frontend-application.ts +3 -2
  158. package/src/browser/keybinding.spec.ts +13 -3
  159. package/src/browser/keybinding.ts +8 -9
  160. package/src/browser/menu/browser-context-menu-renderer.ts +2 -2
  161. package/src/browser/menu/browser-menu-plugin.ts +74 -86
  162. package/src/browser/resource-context-key.ts +9 -6
  163. package/src/browser/shell/shell-layout-restorer.ts +2 -1
  164. package/src/browser/shell/side-panel-toolbar.ts +0 -1
  165. package/src/browser/shell/tab-bar-toolbar/index.ts +19 -0
  166. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.ts +31 -0
  167. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.ts +170 -0
  168. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.ts +186 -0
  169. package/src/browser/shell/{tab-bar-toolbar.spec.ts → tab-bar-toolbar/tab-bar-toolbar.spec.ts} +2 -2
  170. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.tsx +261 -0
  171. package/src/browser/style/alert-messages.css +6 -0
  172. package/src/browser/view-container.ts +1 -10
  173. package/src/browser/widget-manager.spec.ts +14 -0
  174. package/src/browser/widget-manager.ts +2 -1
  175. package/src/browser/window/default-window-service.ts +9 -4
  176. package/src/browser/window/window-service.ts +2 -1
  177. package/src/common/color.ts +3 -0
  178. package/src/common/frontend-application-state.ts +15 -0
  179. package/src/common/menu/action-menu-node.ts +65 -0
  180. package/src/common/menu/composite-menu-node.ts +121 -0
  181. package/src/common/menu/index.ts +21 -0
  182. package/src/common/menu/menu-adapter.ts +103 -0
  183. package/src/common/{menu.ts → menu/menu-model-registry.ts} +61 -222
  184. package/src/common/menu/menu-types.ts +183 -0
  185. package/src/common/{menu.spec.ts → menu/menu.spec.ts} +3 -2
  186. package/src/common/message-rpc/rpc-message-encoder.ts +24 -13
  187. package/src/common/messaging/abstract-connection-provider.ts +4 -4
  188. package/src/common/quick-pick-service.ts +1 -0
  189. package/src/electron-browser/menu/electron-context-menu-renderer.ts +2 -2
  190. package/src/electron-browser/menu/electron-main-menu-factory.ts +82 -96
  191. package/src/electron-browser/menu/electron-menu-contribution.ts +8 -0
  192. package/src/electron-browser/messaging/electron-ws-connection-provider.ts +1 -1
  193. package/src/electron-browser/window/electron-window-service.ts +1 -1
  194. package/src/electron-common/messaging/electron-messages.ts +4 -15
  195. package/src/electron-main/messaging/electron-messaging-contribution.ts +8 -8
  196. package/lib/browser/shell/tab-bar-toolbar.d.ts +0 -186
  197. package/lib/browser/shell/tab-bar-toolbar.d.ts.map +0 -1
  198. package/lib/browser/shell/tab-bar-toolbar.js +0 -362
  199. package/lib/browser/shell/tab-bar-toolbar.js.map +0 -1
  200. package/lib/browser/shell/tab-bar-toolbar.spec.d.ts.map +0 -1
  201. package/lib/browser/shell/tab-bar-toolbar.spec.js.map +0 -1
  202. package/lib/common/menu.d.ts.map +0 -1
  203. package/lib/common/menu.js.map +0 -1
  204. package/lib/common/menu.spec.d.ts.map +0 -1
  205. package/lib/common/menu.spec.js.map +0 -1
  206. package/src/browser/shell/tab-bar-toolbar.tsx +0 -495
@@ -18,8 +18,8 @@ import { injectable, inject } from 'inversify';
18
18
  import { MenuBar, Menu as MenuWidget, Widget } from '@phosphor/widgets';
19
19
  import { CommandRegistry as PhosphorCommandRegistry } from '@phosphor/commands';
20
20
  import {
21
- CommandRegistry, ActionMenuNode, CompositeMenuNode, environment,
22
- MenuModelRegistry, MAIN_MENU_BAR, MenuPath, DisposableCollection, Disposable, MenuNode
21
+ CommandRegistry, CompositeMenuNode, environment,
22
+ MenuModelRegistry, MAIN_MENU_BAR, MenuPath, DisposableCollection, Disposable, MenuNode, MenuCommandExecutor, CompoundMenuNode, CompoundMenuNodeRole, CommandMenuNode
23
23
  } from '../../common';
24
24
  import { KeybindingRegistry } from '../keybinding';
25
25
  import { FrontendApplicationContribution, FrontendApplication } from '../frontend-application';
@@ -35,6 +35,12 @@ export abstract class MenuBarWidget extends MenuBar {
35
35
  abstract triggerMenuItem(label: string, ...labels: string[]): Promise<MenuWidget.IItem>;
36
36
  }
37
37
 
38
+ export interface BrowserMenuOptions extends MenuWidget.IOptions {
39
+ commands: MenuCommandRegistry,
40
+ context?: HTMLElement,
41
+ rootMenuPath: MenuPath
42
+ };
43
+
38
44
  @injectable()
39
45
  export class BrowserMainMenuFactory implements MenuWidgetFactory {
40
46
 
@@ -47,6 +53,9 @@ export class BrowserMainMenuFactory implements MenuWidgetFactory {
47
53
  @inject(CommandRegistry)
48
54
  protected readonly commandRegistry: CommandRegistry;
49
55
 
56
+ @inject(MenuCommandExecutor)
57
+ protected readonly menuCommandExecutor: MenuCommandExecutor;
58
+
50
59
  @inject(CorePreferences)
51
60
  protected readonly corePreferences: CorePreferences;
52
61
 
@@ -92,50 +101,39 @@ export class BrowserMainMenuFactory implements MenuWidgetFactory {
92
101
  const menuCommandRegistry = this.createMenuCommandRegistry(menuModel);
93
102
  for (const menu of menuModel.children) {
94
103
  if (menu instanceof CompositeMenuNode) {
95
- const menuWidget = this.createMenuWidget(menu, { commands: menuCommandRegistry });
104
+ const menuWidget = this.createMenuWidget(menu, { commands: menuCommandRegistry, rootMenuPath: MAIN_MENU_BAR });
96
105
  menuBar.addMenu(menuWidget);
97
106
  }
98
107
  }
99
108
  }
100
109
 
101
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
102
- createContextMenu(path: MenuPath, args?: any[]): MenuWidget {
110
+ createContextMenu(path: MenuPath, args?: unknown[], context?: HTMLElement): MenuWidget {
103
111
  const menuModel = this.menuProvider.getMenu(path);
104
- const menuCommandRegistry = this.createMenuCommandRegistry(menuModel, args).snapshot();
105
- const contextMenu = this.createMenuWidget(menuModel, { commands: menuCommandRegistry });
112
+ const menuCommandRegistry = this.createMenuCommandRegistry(menuModel, args).snapshot(path);
113
+ const contextMenu = this.createMenuWidget(menuModel, { commands: menuCommandRegistry, context, rootMenuPath: path });
106
114
  return contextMenu;
107
115
  }
108
116
 
109
- createMenuWidget(menu: CompositeMenuNode, options: MenuWidget.IOptions & { commands: MenuCommandRegistry }): DynamicMenuWidget {
117
+ createMenuWidget(menu: CompositeMenuNode, options: BrowserMenuOptions): DynamicMenuWidget {
110
118
  return new DynamicMenuWidget(menu, options, this.services);
111
119
  }
112
120
 
113
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
114
- protected createMenuCommandRegistry(menu: CompositeMenuNode, args: any[] = []): MenuCommandRegistry {
121
+ protected createMenuCommandRegistry(menu: CompositeMenuNode, args: unknown[] = []): MenuCommandRegistry {
115
122
  const menuCommandRegistry = new MenuCommandRegistry(this.services);
116
123
  this.registerMenu(menuCommandRegistry, menu, args);
117
124
  return menuCommandRegistry;
118
125
  }
119
126
 
120
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
121
- protected registerMenu(menuCommandRegistry: MenuCommandRegistry, menu: CompositeMenuNode, args: any[]): void {
122
- for (const child of menu.children) {
123
- if (child instanceof ActionMenuNode) {
124
- menuCommandRegistry.registerActionMenu(child, args);
125
- if (child.altNode) {
126
- menuCommandRegistry.registerActionMenu(child.altNode, args);
127
- }
128
- } else if (child instanceof CompositeMenuNode) {
129
- this.registerMenu(menuCommandRegistry, child, args);
130
- } else {
131
- this.handleDefault(menuCommandRegistry, child, args);
127
+ protected registerMenu(menuCommandRegistry: MenuCommandRegistry, menu: MenuNode, args: unknown[]): void {
128
+ if (CompoundMenuNode.is(menu)) {
129
+ menu.children.forEach(child => this.registerMenu(menuCommandRegistry, child, args));
130
+ } else if (CommandMenuNode.is(menu)) {
131
+ menuCommandRegistry.registerActionMenu(menu, args);
132
+ if (menu.altNode) {
133
+ menuCommandRegistry.registerActionMenu(menu.altNode, args);
132
134
  }
133
- }
134
- }
135
135
 
136
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
137
- protected handleDefault(menuCommandRegistry: MenuCommandRegistry, menuNode: MenuNode, args: any[]): void {
138
- // NOOP
136
+ }
139
137
  }
140
138
 
141
139
  protected get services(): MenuServices {
@@ -144,7 +142,8 @@ export class BrowserMainMenuFactory implements MenuWidgetFactory {
144
142
  contextKeyService: this.contextKeyService,
145
143
  commandRegistry: this.commandRegistry,
146
144
  keybindingRegistry: this.keybindingRegistry,
147
- menuWidgetFactory: this
145
+ menuWidgetFactory: this,
146
+ commandExecutor: this.menuCommandExecutor,
148
147
  };
149
148
  }
150
149
 
@@ -225,10 +224,11 @@ export class MenuServices {
225
224
  readonly contextKeyService: ContextKeyService;
226
225
  readonly context: ContextMenuContext;
227
226
  readonly menuWidgetFactory: MenuWidgetFactory;
227
+ readonly commandExecutor: MenuCommandExecutor;
228
228
  }
229
229
 
230
230
  export interface MenuWidgetFactory {
231
- createMenuWidget(menu: CompositeMenuNode, options: MenuWidget.IOptions & { commands: MenuCommandRegistry }): MenuWidget;
231
+ createMenuWidget(menu: MenuNode & Required<Pick<MenuNode, 'children'>>, options: BrowserMenuOptions): MenuWidget;
232
232
  }
233
233
 
234
234
  /**
@@ -243,7 +243,7 @@ export class DynamicMenuWidget extends MenuWidget {
243
243
 
244
244
  constructor(
245
245
  protected menu: CompositeMenuNode,
246
- protected options: MenuWidget.IOptions & { commands: MenuCommandRegistry },
246
+ protected options: BrowserMenuOptions,
247
247
  protected services: MenuServices
248
248
  ) {
249
249
  super(options);
@@ -260,7 +260,7 @@ export class DynamicMenuWidget extends MenuWidget {
260
260
  this.preserveFocusedElement(previousFocusedElement);
261
261
  this.clearItems();
262
262
  this.runWithPreservedFocusContext(() => {
263
- this.options.commands.snapshot();
263
+ this.options.commands.snapshot(this.options.rootMenuPath);
264
264
  this.updateSubMenus(this, this.menu, this.options.commands);
265
265
  });
266
266
  }
@@ -275,59 +275,51 @@ export class DynamicMenuWidget extends MenuWidget {
275
275
  super.open(x, y, options);
276
276
  }
277
277
 
278
- private updateSubMenus(parent: MenuWidget, menu: CompositeMenuNode, commands: MenuCommandRegistry): void {
278
+ protected updateSubMenus(parent: MenuWidget, menu: CompositeMenuNode, commands: MenuCommandRegistry): void {
279
279
  const items = this.buildSubMenus([], menu, commands);
280
+ while (items[items.length - 1]?.type === 'separator') {
281
+ items.pop();
282
+ }
280
283
  for (const item of items) {
281
284
  parent.addItem(item);
282
285
  }
283
286
  }
284
287
 
285
- private buildSubMenus(items: MenuWidget.IItemOptions[], menu: CompositeMenuNode, commands: MenuCommandRegistry): MenuWidget.IItemOptions[] {
286
- for (const item of menu.children) {
287
- if (item instanceof CompositeMenuNode) {
288
- if (item.children.length) { // do not render empty nodes
289
- if (item.isSubmenu) { // submenu node
290
- const submenu = this.services.menuWidgetFactory.createMenuWidget(item, this.options);
291
- if (!submenu.items.length) {
292
- continue;
293
- }
294
- items.push({
295
- type: 'submenu',
296
- submenu,
297
- });
298
- } else { // group node
299
- const submenu = this.buildSubMenus([], item, commands);
300
- if (!submenu.length) {
301
- continue;
302
- }
303
- if (items.length) { // do not put a separator above the first group
304
- items.push({
305
- type: 'separator'
306
- });
307
- }
308
- items.push(...submenu); // render children
288
+ protected buildSubmenusCalled = 0;
289
+
290
+ protected buildSubMenus(parentItems: MenuWidget.IItemOptions[], menu: MenuNode, commands: MenuCommandRegistry): MenuWidget.IItemOptions[] {
291
+ if (CompoundMenuNode.is(menu) && menu.children.length && this.undefinedOrMatch(menu.when, this.options.context)) {
292
+ const role = menu === this.menu ? CompoundMenuNodeRole.Group : CompoundMenuNode.getRole(menu);
293
+ if (role === CompoundMenuNodeRole.Submenu) {
294
+ const submenu = this.services.menuWidgetFactory.createMenuWidget(menu, this.options);
295
+ parentItems.push({ type: 'submenu', submenu });
296
+ } else if (role === CompoundMenuNodeRole.Group && menu.id !== 'inline') {
297
+ const children = CompoundMenuNode.getFlatChildren(menu.children);
298
+ const myItems: MenuWidget.IItemOptions[] = [];
299
+ children.forEach(child => this.buildSubMenus(myItems, child, commands));
300
+ if (myItems.length) {
301
+ if (parentItems.length && parentItems[parentItems.length - 1].type !== 'separator') {
302
+ parentItems.push({ type: 'separator' });
309
303
  }
304
+ parentItems.push(...myItems);
305
+ parentItems.push({ type: 'separator' });
310
306
  }
311
- } else if (item instanceof ActionMenuNode) {
312
- const { context, contextKeyService } = this.services;
313
- const node = item.altNode && context.altPressed ? item.altNode : item;
314
- const { when } = node.action;
315
- if (!(commands.isVisible(node.action.commandId) && (!when || contextKeyService.match(when)))) {
316
- continue;
317
- }
318
- items.push({
319
- command: node.action.commandId,
307
+ }
308
+ } else if (menu.command) {
309
+ const node = menu.altNode && this.services.context.altPressed ? menu.altNode : (menu as MenuNode & CommandMenuNode);
310
+ if (commands.isVisible(node.command) && this.undefinedOrMatch(node.when, this.options.context)) {
311
+ parentItems.push({
312
+ command: node.command,
320
313
  type: 'command'
321
314
  });
322
- } else {
323
- items.push(...this.handleDefault(item));
324
315
  }
325
316
  }
326
- return items;
317
+ return parentItems;
327
318
  }
328
319
 
329
- protected handleDefault(menuNode: MenuNode): MenuWidget.IItemOptions[] {
330
- return [];
320
+ protected undefinedOrMatch(expression?: string, context?: HTMLElement): boolean {
321
+ if (expression) { return this.services.contextKeyService.match(expression, context); }
322
+ return true;
331
323
  }
332
324
 
333
325
  protected preserveFocusedElement(previousFocusedElement: Element | null = document.activeElement): boolean {
@@ -418,19 +410,16 @@ export class BrowserMenuBarContribution implements FrontendApplicationContributi
418
410
  */
419
411
  export class MenuCommandRegistry extends PhosphorCommandRegistry {
420
412
 
421
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
422
- protected actions = new Map<string, [ActionMenuNode, any[]]>();
413
+ protected actions = new Map<string, [MenuNode & CommandMenuNode, unknown[]]>();
423
414
  protected toDispose = new DisposableCollection();
424
415
 
425
416
  constructor(protected services: MenuServices) {
426
417
  super();
427
418
  }
428
419
 
429
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
430
- registerActionMenu(menu: ActionMenuNode, args: any[]): void {
431
- const { commandId } = menu.action;
420
+ registerActionMenu(menu: MenuNode & CommandMenuNode, args: unknown[]): void {
432
421
  const { commandRegistry } = this.services;
433
- const command = commandRegistry.getCommand(commandId);
422
+ const command = commandRegistry.getCommand(menu.command);
434
423
  if (!command) {
435
424
  return;
436
425
  }
@@ -441,18 +430,17 @@ export class MenuCommandRegistry extends PhosphorCommandRegistry {
441
430
  this.actions.set(id, [menu, args]);
442
431
  }
443
432
 
444
- snapshot(): this {
433
+ snapshot(menuPath: MenuPath): this {
445
434
  this.toDispose.dispose();
446
435
  for (const [menu, args] of this.actions.values()) {
447
- this.toDispose.push(this.registerCommand(menu, args));
436
+ this.toDispose.push(this.registerCommand(menu, args, menuPath));
448
437
  }
449
438
  return this;
450
439
  }
451
440
 
452
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
453
- protected registerCommand(menu: ActionMenuNode, args: any[]): Disposable {
454
- const { commandRegistry, keybindingRegistry } = this.services;
455
- const command = commandRegistry.getCommand(menu.action.commandId);
441
+ protected registerCommand(menu: MenuNode & CommandMenuNode, args: unknown[], menuPath: MenuPath): Disposable {
442
+ const { commandRegistry, keybindingRegistry, commandExecutor } = this.services;
443
+ const command = commandRegistry.getCommand(menu.command);
456
444
  if (!command) {
457
445
  return Disposable.NULL;
458
446
  }
@@ -463,11 +451,11 @@ export class MenuCommandRegistry extends PhosphorCommandRegistry {
463
451
  }
464
452
 
465
453
  // We freeze the `isEnabled`, `isVisible`, and `isToggled` states so they won't change.
466
- const enabled = commandRegistry.isEnabled(id, ...args);
467
- const visible = commandRegistry.isVisible(id, ...args);
468
- const toggled = commandRegistry.isToggled(id, ...args);
454
+ const enabled = commandExecutor.isEnabled(menuPath, id, ...args);
455
+ const visible = commandExecutor.isVisible(menuPath, id, ...args);
456
+ const toggled = commandExecutor.isToggled(menuPath, id, ...args);
469
457
  const unregisterCommand = this.addCommand(id, {
470
- execute: () => commandRegistry.executeCommand(id, ...args),
458
+ execute: () => commandExecutor.executeCommand(menuPath, id, ...args),
471
459
  label: menu.label,
472
460
  icon: menu.icon,
473
461
  isEnabled: () => enabled,
@@ -36,6 +36,7 @@ export class ResourceContextKey {
36
36
  protected resourceLangId: ContextKey<string>;
37
37
  protected resourceDirName: ContextKey<string>;
38
38
  protected resourcePath: ContextKey<string>;
39
+ protected resourceSet: ContextKey<boolean>;
39
40
 
40
41
  @postConstruct()
41
42
  protected init(): void {
@@ -46,6 +47,7 @@ export class ResourceContextKey {
46
47
  this.resourceLangId = this.contextKeyService.createKey<string>('resourceLangId', undefined);
47
48
  this.resourceDirName = this.contextKeyService.createKey<string>('resourceDirName', undefined);
48
49
  this.resourcePath = this.contextKeyService.createKey<string>('resourcePath', undefined);
50
+ this.resourceSet = this.contextKeyService.createKey<boolean>('resourceSet', false);
49
51
  }
50
52
 
51
53
  get(): URI | undefined {
@@ -54,13 +56,14 @@ export class ResourceContextKey {
54
56
  }
55
57
 
56
58
  set(resourceUri: URI | undefined): void {
57
- this.resource.set(resourceUri && resourceUri['codeUri']);
58
- this.resourceSchemeKey.set(resourceUri && resourceUri.scheme);
59
- this.resourceFileName.set(resourceUri && resourceUri.path.base);
60
- this.resourceExtname.set(resourceUri && resourceUri.path.ext);
59
+ this.resource.set(resourceUri?.['codeUri']);
60
+ this.resourceSchemeKey.set(resourceUri?.scheme);
61
+ this.resourceFileName.set(resourceUri?.path.base);
62
+ this.resourceExtname.set(resourceUri?.path.ext);
61
63
  this.resourceLangId.set(resourceUri && this.getLanguageId(resourceUri));
62
- this.resourceDirName.set(resourceUri && resourceUri.path.dir.fsPath());
63
- this.resourcePath.set(resourceUri && resourceUri.path.fsPath());
64
+ this.resourceDirName.set(resourceUri?.path.dir.fsPath());
65
+ this.resourcePath.set(resourceUri?.path.fsPath());
66
+ this.resourceSet.set(Boolean(resourceUri));
64
67
  }
65
68
 
66
69
  protected getLanguageId(uri: URI | undefined): string | undefined {
@@ -27,6 +27,7 @@ import { MaybePromise } from '../../common/types';
27
27
  import { ApplicationShell, applicationShellLayoutVersion, ApplicationShellLayoutVersion } from './application-shell';
28
28
  import { CommonCommands } from '../common-frontend-contribution';
29
29
  import { WindowService } from '../window/window-service';
30
+ import { StopReason } from '../../common/frontend-application-state';
30
31
 
31
32
  /**
32
33
  * A contract for widgets that want to store and restore their inner state, between sessions.
@@ -139,7 +140,7 @@ export class ShellLayoutRestorer implements CommandContribution {
139
140
  }
140
141
 
141
142
  protected async resetLayout(): Promise<void> {
142
- if (await this.windowService.isSafeToShutDown()) {
143
+ if (await this.windowService.isSafeToShutDown(StopReason.Reload)) {
143
144
  this.logger.info('>>> Resetting layout...');
144
145
  this.shouldStoreLayout = false;
145
146
  this.storageService.setData(this.storageKey, undefined);
@@ -101,7 +101,6 @@ export class SidePanelToolbar extends BaseWidget {
101
101
  }
102
102
  }
103
103
 
104
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
105
104
  showMoreContextMenu(anchor: Anchor): ContextMenuAccess {
106
105
  if (this.toolbar) {
107
106
  return this.toolbar.renderMoreContextMenu(anchor);
@@ -0,0 +1,19 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2022 Ericsson and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ export * from './tab-bar-toolbar';
18
+ export * from './tab-bar-toolbar-registry';
19
+ export * from './tab-bar-toolbar-types';
@@ -0,0 +1,31 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2022 Ericsson and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { MenuNode, MenuPath } from '../../../common';
18
+ import { NAVIGATION, TabBarToolbarItem } from './tab-bar-toolbar-types';
19
+
20
+ export const TOOLBAR_WRAPPER_ID_SUFFIX = '-as-tabbar-toolbar-item';
21
+
22
+ export class ToolbarMenuNodeWrapper implements TabBarToolbarItem {
23
+ constructor(protected readonly menuNode: MenuNode, readonly group?: string, readonly menuPath?: MenuPath) { }
24
+ get id(): string { return this.menuNode.id + TOOLBAR_WRAPPER_ID_SUFFIX; }
25
+ get command(): string { return this.menuNode.command ?? ''; };
26
+ get icon(): string | undefined { return this.menuNode.icon; }
27
+ get tooltip(): string | undefined { return this.menuNode.label; }
28
+ get when(): string | undefined { return this.menuNode.when; }
29
+ get text(): string | undefined { return (this.group === NAVIGATION || this.group === undefined) ? undefined : this.menuNode.label; }
30
+ }
31
+
@@ -0,0 +1,170 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2022 Ericsson and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import debounce = require('lodash.debounce');
18
+ import { inject, injectable, named } from 'inversify';
19
+ // eslint-disable-next-line max-len
20
+ import { CommandMenuNode, CommandRegistry, CompoundMenuNode, ContributionProvider, Disposable, DisposableCollection, Emitter, Event, MenuModelRegistry, MenuPath } from '../../../common';
21
+ import { ContextKeyService } from '../../context-key-service';
22
+ import { FrontendApplicationContribution } from '../../frontend-application';
23
+ import { Widget } from '../../widgets';
24
+ import { MenuDelegate, ReactTabBarToolbarItem, TabBarToolbarItem } from './tab-bar-toolbar-types';
25
+ import { ToolbarMenuNodeWrapper } from './tab-bar-toolbar-menu-adapters';
26
+
27
+ /**
28
+ * Clients should implement this interface if they want to contribute to the tab-bar toolbar.
29
+ */
30
+ export const TabBarToolbarContribution = Symbol('TabBarToolbarContribution');
31
+ /**
32
+ * Representation of a tabbar toolbar contribution.
33
+ */
34
+ export interface TabBarToolbarContribution {
35
+ /**
36
+ * Registers toolbar items.
37
+ * @param registry the tabbar toolbar registry.
38
+ */
39
+ registerToolbarItems(registry: TabBarToolbarRegistry): void;
40
+ }
41
+
42
+ function yes(): true { return true; }
43
+ const menuDelegateSeparator = '=@=';
44
+
45
+ /**
46
+ * Main, shared registry for tab-bar toolbar items.
47
+ */
48
+ @injectable()
49
+ export class TabBarToolbarRegistry implements FrontendApplicationContribution {
50
+
51
+ protected items = new Map<string, TabBarToolbarItem | ReactTabBarToolbarItem>();
52
+ protected menuDelegates = new Map<string, MenuDelegate>();
53
+
54
+ @inject(CommandRegistry) protected readonly commandRegistry: CommandRegistry;
55
+ @inject(ContextKeyService) protected readonly contextKeyService: ContextKeyService;
56
+ @inject(MenuModelRegistry) protected readonly menuRegistry: MenuModelRegistry;
57
+
58
+ @inject(ContributionProvider) @named(TabBarToolbarContribution)
59
+ protected readonly contributionProvider: ContributionProvider<TabBarToolbarContribution>;
60
+
61
+ protected readonly onDidChangeEmitter = new Emitter<void>();
62
+ readonly onDidChange: Event<void> = this.onDidChangeEmitter.event;
63
+ // debounce in order to avoid to fire more than once in the same tick
64
+ protected fireOnDidChange = debounce(() => this.onDidChangeEmitter.fire(undefined), 0);
65
+
66
+ onStart(): void {
67
+ const contributions = this.contributionProvider.getContributions();
68
+ for (const contribution of contributions) {
69
+ contribution.registerToolbarItems(this);
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Registers the given item. Throws an error, if the corresponding command cannot be found or an item has been already registered for the desired command.
75
+ *
76
+ * @param item the item to register.
77
+ */
78
+ registerItem(item: TabBarToolbarItem | ReactTabBarToolbarItem): Disposable {
79
+ const { id } = item;
80
+ if (this.items.has(id)) {
81
+ throw new Error(`A toolbar item is already registered with the '${id}' ID.`);
82
+ }
83
+ this.items.set(id, item);
84
+ this.fireOnDidChange();
85
+ const toDispose = new DisposableCollection(
86
+ Disposable.create(() => this.fireOnDidChange()),
87
+ Disposable.create(() => this.items.delete(id))
88
+ );
89
+ if (item.onDidChange) {
90
+ toDispose.push(item.onDidChange(() => this.fireOnDidChange()));
91
+ }
92
+ return toDispose;
93
+ }
94
+
95
+ /**
96
+ * Returns an array of tab-bar toolbar items which are visible when the `widget` argument is the current one.
97
+ *
98
+ * By default returns with all items where the command is enabled and `item.isVisible` is `true`.
99
+ */
100
+ visibleItems(widget: Widget): Array<TabBarToolbarItem | ReactTabBarToolbarItem> {
101
+ if (widget.isDisposed) {
102
+ return [];
103
+ }
104
+ const result: Array<TabBarToolbarItem | ReactTabBarToolbarItem> = [];
105
+ for (const item of this.items.values()) {
106
+ const visible = TabBarToolbarItem.is(item)
107
+ ? this.commandRegistry.isVisible(item.command, widget)
108
+ : (!item.isVisible || item.isVisible(widget));
109
+ if (visible && (!item.when || this.contextKeyService.match(item.when, widget.node))) {
110
+ result.push(item);
111
+ }
112
+ }
113
+ for (const delegate of this.menuDelegates.values()) {
114
+ if (delegate.isVisible(widget)) {
115
+ const menu = this.menuRegistry.getMenu(delegate.menuPath);
116
+ const children = CompoundMenuNode.getFlatChildren(menu.children);
117
+ for (const child of children) {
118
+ if (!child.when || this.contextKeyService.match(child.when, widget.node)) {
119
+ if (child.children) {
120
+ for (const grandchild of child.children) {
121
+ if (!grandchild.when || this.contextKeyService.match(grandchild.when, widget.node)) {
122
+ if (CommandMenuNode.is(grandchild)) {
123
+ result.push(new ToolbarMenuNodeWrapper(grandchild, child.id, delegate.menuPath));
124
+ } else if (CompoundMenuNode.is(grandchild)) {
125
+ let menuPath;
126
+ if (menuPath = this.menuRegistry.getPath(grandchild)) {
127
+ result.push(new ToolbarMenuNodeWrapper(grandchild, child.id, menuPath));
128
+ }
129
+ }
130
+ }
131
+ }
132
+ } else if (child.command) {
133
+ result.push(new ToolbarMenuNodeWrapper(child, '', delegate.menuPath));
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }
139
+ return result;
140
+ }
141
+
142
+ unregisterItem(itemOrId: TabBarToolbarItem | ReactTabBarToolbarItem | string): void {
143
+ const id = typeof itemOrId === 'string' ? itemOrId : itemOrId.id;
144
+ if (this.items.delete(id)) {
145
+ this.fireOnDidChange();
146
+ }
147
+ }
148
+
149
+ registerMenuDelegate(menuPath: MenuPath, when?: string | ((widget: Widget) => boolean)): Disposable {
150
+ const id = menuPath.join(menuDelegateSeparator);
151
+ if (!this.menuDelegates.has(id)) {
152
+ const isVisible: MenuDelegate['isVisible'] = !when
153
+ ? yes
154
+ : typeof when === 'function'
155
+ ? when
156
+ : widget => this.contextKeyService.match(when, widget?.node);
157
+ this.menuDelegates.set(id, { menuPath, isVisible });
158
+ this.fireOnDidChange();
159
+ return { dispose: () => this.unregisterMenuDelegate(menuPath) };
160
+ }
161
+ console.warn('Unable to register menu delegate. Delegate has already been registered', menuPath);
162
+ return Disposable.NULL;
163
+ }
164
+
165
+ unregisterMenuDelegate(menuPath: MenuPath): void {
166
+ if (this.menuDelegates.delete(menuPath.join(menuDelegateSeparator))) {
167
+ this.fireOnDidChange();
168
+ }
169
+ }
170
+ }