@theia/core 1.28.0-next.9 → 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 (201) 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/messaging/abstract-connection-provider.d.ts +1 -1
  126. package/lib/common/messaging/abstract-connection-provider.js +3 -3
  127. package/lib/common/quick-pick-service.d.ts +1 -0
  128. package/lib/common/quick-pick-service.d.ts.map +1 -1
  129. package/lib/common/quick-pick-service.js.map +1 -1
  130. package/lib/electron-browser/menu/electron-context-menu-renderer.js +2 -2
  131. package/lib/electron-browser/menu/electron-context-menu-renderer.js.map +1 -1
  132. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts +14 -5
  133. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
  134. package/lib/electron-browser/menu/electron-main-menu-factory.js +71 -82
  135. package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
  136. package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
  137. package/lib/electron-browser/menu/electron-menu-contribution.js +6 -0
  138. package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
  139. package/lib/electron-browser/messaging/electron-ws-connection-provider.js +1 -1
  140. package/lib/electron-browser/window/electron-window-service.js +1 -1
  141. package/lib/electron-browser/window/electron-window-service.js.map +1 -1
  142. package/lib/electron-common/messaging/electron-messages.d.ts +3 -14
  143. package/lib/electron-common/messaging/electron-messages.d.ts.map +1 -1
  144. package/lib/electron-common/messaging/electron-messages.js +3 -16
  145. package/lib/electron-common/messaging/electron-messages.js.map +1 -1
  146. package/lib/electron-main/messaging/electron-messaging-contribution.d.ts +3 -3
  147. package/lib/electron-main/messaging/electron-messaging-contribution.js +6 -6
  148. package/package.json +7 -6
  149. package/src/browser/common-frontend-contribution.ts +6 -5
  150. package/src/browser/context-key-service.ts +1 -1
  151. package/src/browser/context-menu-renderer.ts +5 -0
  152. package/src/browser/frontend-application-module.ts +7 -1
  153. package/src/browser/frontend-application.ts +3 -2
  154. package/src/browser/keybinding.spec.ts +13 -3
  155. package/src/browser/keybinding.ts +8 -9
  156. package/src/browser/menu/browser-context-menu-renderer.ts +2 -2
  157. package/src/browser/menu/browser-menu-plugin.ts +74 -86
  158. package/src/browser/resource-context-key.ts +9 -6
  159. package/src/browser/shell/shell-layout-restorer.ts +2 -1
  160. package/src/browser/shell/side-panel-toolbar.ts +0 -1
  161. package/src/browser/shell/tab-bar-toolbar/index.ts +19 -0
  162. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.ts +31 -0
  163. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.ts +170 -0
  164. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.ts +186 -0
  165. package/src/browser/shell/{tab-bar-toolbar.spec.ts → tab-bar-toolbar/tab-bar-toolbar.spec.ts} +2 -2
  166. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.tsx +261 -0
  167. package/src/browser/style/alert-messages.css +6 -0
  168. package/src/browser/view-container.ts +1 -10
  169. package/src/browser/widget-manager.spec.ts +14 -0
  170. package/src/browser/widget-manager.ts +2 -1
  171. package/src/browser/window/default-window-service.ts +9 -4
  172. package/src/browser/window/window-service.ts +2 -1
  173. package/src/common/color.ts +3 -0
  174. package/src/common/frontend-application-state.ts +15 -0
  175. package/src/common/menu/action-menu-node.ts +65 -0
  176. package/src/common/menu/composite-menu-node.ts +121 -0
  177. package/src/common/menu/index.ts +21 -0
  178. package/src/common/menu/menu-adapter.ts +103 -0
  179. package/src/common/{menu.ts → menu/menu-model-registry.ts} +61 -222
  180. package/src/common/menu/menu-types.ts +183 -0
  181. package/src/common/{menu.spec.ts → menu/menu.spec.ts} +3 -2
  182. package/src/common/messaging/abstract-connection-provider.ts +4 -4
  183. package/src/common/quick-pick-service.ts +1 -0
  184. package/src/electron-browser/menu/electron-context-menu-renderer.ts +2 -2
  185. package/src/electron-browser/menu/electron-main-menu-factory.ts +82 -96
  186. package/src/electron-browser/menu/electron-menu-contribution.ts +8 -0
  187. package/src/electron-browser/messaging/electron-ws-connection-provider.ts +1 -1
  188. package/src/electron-browser/window/electron-window-service.ts +1 -1
  189. package/src/electron-common/messaging/electron-messages.ts +4 -15
  190. package/src/electron-main/messaging/electron-messaging-contribution.ts +8 -8
  191. package/lib/browser/shell/tab-bar-toolbar.d.ts +0 -186
  192. package/lib/browser/shell/tab-bar-toolbar.d.ts.map +0 -1
  193. package/lib/browser/shell/tab-bar-toolbar.js +0 -362
  194. package/lib/browser/shell/tab-bar-toolbar.js.map +0 -1
  195. package/lib/browser/shell/tab-bar-toolbar.spec.d.ts.map +0 -1
  196. package/lib/browser/shell/tab-bar-toolbar.spec.js.map +0 -1
  197. package/lib/common/menu.d.ts.map +0 -1
  198. package/lib/common/menu.js.map +0 -1
  199. package/lib/common/menu.spec.d.ts.map +0 -1
  200. package/lib/common/menu.spec.js.map +0 -1
  201. package/src/browser/shell/tab-bar-toolbar.tsx +0 -495
@@ -15,74 +15,12 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { injectable, inject, named } from 'inversify';
18
- import { Disposable } from './disposable';
19
- import { CommandRegistry, Command } from './command';
20
- import { ContributionProvider } from './contribution-provider';
21
-
22
- /**
23
- * A menu entry representing an action, e.g. "New File".
24
- */
25
- export interface MenuAction {
26
- /**
27
- * The command to execute.
28
- */
29
- commandId: string
30
- /**
31
- * In addition to the mandatory command property, an alternative command can be defined.
32
- * It will be shown and invoked when pressing Alt while opening a menu.
33
- */
34
- alt?: string;
35
- /**
36
- * A specific label for this action. If not specified the command label or command id will be used.
37
- */
38
- label?: string
39
- /**
40
- * Icon class(es). If not specified the icon class associated with the specified command
41
- * (i.e. `command.iconClass`) will be used if it exists.
42
- */
43
- icon?: string
44
- /**
45
- * Menu entries are sorted in ascending order based on their `order` strings. If omitted the determined
46
- * label will be used instead.
47
- */
48
- order?: string
49
- /**
50
- * Optional expression which will be evaluated by the {@link ContextKeyService} to determine visibility
51
- * of the action, e.g. `resourceLangId == markdown`.
52
- */
53
- when?: string
54
- }
55
-
56
- export namespace MenuAction {
57
- /* Determine whether object is a MenuAction */
58
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
- export function is(arg: MenuAction | any): arg is MenuAction {
60
- return !!arg && arg === Object(arg) && 'commandId' in arg;
61
- }
62
- }
63
-
64
- /**
65
- * Additional options when creating a new submenu.
66
- */
67
- export interface SubMenuOptions {
68
- /**
69
- * The class to use for the submenu icon.
70
- */
71
- iconClass?: string
72
- /**
73
- * Menu entries are sorted in ascending order based on their `order` strings. If omitted the determined
74
- * label will be used instead.
75
- */
76
- order?: string
77
- }
78
-
79
- export type MenuPath = string[];
80
-
81
- export const MAIN_MENU_BAR: MenuPath = ['menubar'];
82
-
83
- export const SETTINGS_MENU: MenuPath = ['settings_menu'];
84
- export const ACCOUNTS_MENU: MenuPath = ['accounts_menu'];
85
- export const ACCOUNTS_SUBMENU = [...ACCOUNTS_MENU, '1_accounts_submenu'];
18
+ import { Disposable } from '../disposable';
19
+ import { CommandRegistry, Command } from '../command';
20
+ import { ContributionProvider } from '../contribution-provider';
21
+ import { CompositeMenuNode, CompositeMenuNodeWrapper } from './composite-menu-node';
22
+ import { MenuAction, MenuNode, MenuPath, SubMenuOptions } from './menu-types';
23
+ import { ActionMenuNode } from './action-menu-node';
86
24
 
87
25
  export const MenuContribution = Symbol('MenuContribution');
88
26
 
@@ -128,6 +66,7 @@ export interface MenuContribution {
128
66
  @injectable()
129
67
  export class MenuModelRegistry {
130
68
  protected readonly root = new CompositeMenuNode('');
69
+ protected readonly independentSubmenus = new Map<string, CompositeMenuNode>();
131
70
 
132
71
  constructor(
133
72
  @inject(ContributionProvider) @named(MenuContribution)
@@ -156,11 +95,24 @@ export class MenuModelRegistry {
156
95
  *
157
96
  * @returns a disposable which, when called, will remove the menu node again.
158
97
  */
159
- registerMenuNode(menuPath: MenuPath, menuNode: MenuNode): Disposable {
160
- const parent = this.findGroup(menuPath);
98
+ registerMenuNode(menuPath: MenuPath | string, menuNode: MenuNode, group?: string): Disposable {
99
+ const parent = this.getMenuNode(menuPath, group);
161
100
  return parent.addNode(menuNode);
162
101
  }
163
102
 
103
+ getMenuNode(menuPath: MenuPath | string, group?: string): CompositeMenuNode {
104
+ if (typeof menuPath === 'string') {
105
+ const target = this.independentSubmenus.get(menuPath);
106
+ if (!target) { throw new Error(`Could not find submenu with id ${menuPath}`); }
107
+ if (group) {
108
+ return this.findSubMenu(target, group);
109
+ }
110
+ return target;
111
+ } else {
112
+ return this.findGroup(group ? menuPath.concat(group) : menuPath);
113
+ }
114
+ }
115
+
164
116
  /**
165
117
  * Register a new menu at the given path with the given label.
166
118
  * (If the menu already exists without a label, iconClass or order this method can be used to set them.)
@@ -186,7 +138,7 @@ export class MenuModelRegistry {
186
138
  const parent = this.findGroup(groupPath, options);
187
139
  let groupNode = this.findSubMenu(parent, menuId, options);
188
140
  if (!groupNode) {
189
- groupNode = new CompositeMenuNode(menuId, label, options);
141
+ groupNode = new CompositeMenuNode(menuId, label, options, parent);
190
142
  return parent.addNode(groupNode);
191
143
  } else {
192
144
  if (!groupNode.label) {
@@ -206,6 +158,21 @@ export class MenuModelRegistry {
206
158
  }
207
159
  }
208
160
 
161
+ registerIndependentSubmenu(id: string, label: string, options?: SubMenuOptions): Disposable {
162
+ if (this.independentSubmenus.has(id)) {
163
+ console.debug(`Independent submenu with path ${id} registered, but given ID already exists.`);
164
+ }
165
+ this.independentSubmenus.set(id, new CompositeMenuNode(id, label, options));
166
+ return { dispose: () => this.independentSubmenus.delete(id) };
167
+ }
168
+
169
+ linkSubmenu(parentPath: MenuPath | string, childId: string | MenuPath, options?: SubMenuOptions, group?: string): Disposable {
170
+ const child = this.getMenuNode(childId);
171
+ const parent = this.getMenuNode(parentPath, group);
172
+ const wrapper = new CompositeMenuNodeWrapper(child, parent, options);
173
+ return parent.addNode(wrapper);
174
+ }
175
+
209
176
  /**
210
177
  * Unregister all menu nodes with the same id as the given menu action.
211
178
  *
@@ -258,6 +225,10 @@ export class MenuModelRegistry {
258
225
  recurse(this.root);
259
226
  }
260
227
 
228
+ /**
229
+ * Finds a submenu as a descendant of the `root` node.
230
+ * See {@link MenuModelRegistry.findSubMenu findSubMenu}.
231
+ */
261
232
  protected findGroup(menuPath: MenuPath, options?: SubMenuOptions): CompositeMenuNode {
262
233
  let currentMenu = this.root;
263
234
  for (const segment of menuPath) {
@@ -266,6 +237,10 @@ export class MenuModelRegistry {
266
237
  return currentMenu;
267
238
  }
268
239
 
240
+ /**
241
+ * Finds or creates a submenu as an immediate child of `current`.
242
+ * @throws if a node with the given `menuId` exists but is not a {@link CompositeMenuNode}.
243
+ */
269
244
  protected findSubMenu(current: CompositeMenuNode, menuId: string, options?: SubMenuOptions): CompositeMenuNode {
270
245
  const sub = current.children.find(e => e.id === menuId);
271
246
  if (sub instanceof CompositeMenuNode) {
@@ -274,7 +249,7 @@ export class MenuModelRegistry {
274
249
  if (sub) {
275
250
  throw new Error(`'${menuId}' is not a menu group.`);
276
251
  }
277
- const newSub = new CompositeMenuNode(menuId, undefined, options);
252
+ const newSub = new CompositeMenuNode(menuId, undefined, options, current);
278
253
  current.addNode(newSub);
279
254
  return newSub;
280
255
  }
@@ -290,160 +265,24 @@ export class MenuModelRegistry {
290
265
  getMenu(menuPath: MenuPath = []): CompositeMenuNode {
291
266
  return this.findGroup(menuPath);
292
267
  }
293
- }
294
268
 
295
- /**
296
- * Base interface of the nodes used in the menu tree structure.
297
- */
298
- export interface MenuNode {
299
269
  /**
300
- * the optional label for this specific node.
270
+ * Returns the {@link MenuPath path} at which a given menu node can be accessed from this registry, if it can be determined.
271
+ * Returns `undefined` if the `parent` of any node in the chain is unknown.
301
272
  */
302
- readonly label?: string
303
- /**
304
- * technical identifier.
305
- */
306
- readonly id: string
307
- /**
308
- * Menu nodes are sorted in ascending order based on their `sortString`.
309
- */
310
- readonly sortString: string
311
- }
312
-
313
- /**
314
- * Node representing a (sub)menu in the menu tree structure.
315
- */
316
- export class CompositeMenuNode implements MenuNode {
317
- protected readonly _children: MenuNode[] = [];
318
- public iconClass?: string;
319
- public order?: string;
320
-
321
- constructor(
322
- public readonly id: string,
323
- public label?: string,
324
- options?: SubMenuOptions
325
- ) {
326
- if (options) {
327
- this.iconClass = options.iconClass;
328
- this.order = options.order;
329
- }
330
- }
331
-
332
- get children(): ReadonlyArray<MenuNode> {
333
- return this._children;
334
- }
335
-
336
- /**
337
- * Inserts the given node at the position indicated by `sortString`.
338
- *
339
- * @returns a disposable which, when called, will remove the given node again.
340
- */
341
- public addNode(node: MenuNode): Disposable {
342
- this._children.push(node);
343
- this._children.sort((m1, m2) => {
344
- // The navigation group is special as it will always be sorted to the top/beginning of a menu.
345
- if (CompositeMenuNode.isNavigationGroup(m1)) {
346
- return -1;
347
- }
348
- if (CompositeMenuNode.isNavigationGroup(m2)) {
349
- return 1;
273
+ getPath(node: MenuNode): MenuPath | undefined {
274
+ const identifiers = [];
275
+ const visited: MenuNode[] = [];
276
+ let next: MenuNode | undefined = node;
277
+
278
+ while (next && !visited.includes(next)) {
279
+ if (next === this.root) {
280
+ return identifiers.reverse();
350
281
  }
351
- if (m1.sortString < m2.sortString) {
352
- return -1;
353
- } else if (m1.sortString > m2.sortString) {
354
- return 1;
355
- } else {
356
- return 0;
357
- }
358
- });
359
- return {
360
- dispose: () => {
361
- const idx = this._children.indexOf(node);
362
- if (idx >= 0) {
363
- this._children.splice(idx, 1);
364
- }
365
- }
366
- };
367
- }
368
-
369
- /**
370
- * Removes the first node with the given id.
371
- *
372
- * @param id node id.
373
- */
374
- public removeNode(id: string): void {
375
- const node = this._children.find(n => n.id === id);
376
- if (node) {
377
- const idx = this._children.indexOf(node);
378
- if (idx >= 0) {
379
- this._children.splice(idx, 1);
380
- }
381
- }
382
- }
383
-
384
- get sortString(): string {
385
- return this.order || this.id;
386
- }
387
-
388
- get isSubmenu(): boolean {
389
- return this.label !== undefined;
390
- }
391
-
392
- /**
393
- * Indicates whether the given node is the special `navigation` menu.
394
- *
395
- * @param node the menu node to check.
396
- * @returns `true` when the given node is a {@link CompositeMenuNode} with id `navigation`,
397
- * `false` otherwise.
398
- */
399
- static isNavigationGroup(node: MenuNode): node is CompositeMenuNode {
400
- return node instanceof CompositeMenuNode && node.id === 'navigation';
401
- }
402
- }
403
-
404
- /**
405
- * Node representing an action in the menu tree structure.
406
- * It's based on {@link MenuAction} for which it tries to determine the
407
- * best label, icon and sortString with the given data.
408
- */
409
- export class ActionMenuNode implements MenuNode {
410
-
411
- readonly altNode: ActionMenuNode | undefined;
412
-
413
- constructor(
414
- public readonly action: MenuAction,
415
- protected readonly commands: CommandRegistry
416
- ) {
417
- if (action.alt) {
418
- this.altNode = new ActionMenuNode({ commandId: action.alt }, commands);
419
- }
420
- }
421
-
422
- get id(): string {
423
- return this.action.commandId;
424
- }
425
-
426
- get label(): string {
427
- if (this.action.label) {
428
- return this.action.label;
282
+ visited.push(next);
283
+ identifiers.push(next.id);
284
+ next = next.parent;
429
285
  }
430
- const cmd = this.commands.getCommand(this.action.commandId);
431
- if (!cmd) {
432
- console.debug(`No label for action menu node: No command "${this.action.commandId}" exists.`);
433
- return '';
434
- }
435
- return cmd.label || cmd.id;
436
- }
437
-
438
- get icon(): string | undefined {
439
- if (this.action.icon) {
440
- return this.action.icon;
441
- }
442
- const command = this.commands.getCommand(this.action.commandId);
443
- return command && command.iconClass;
444
- }
445
-
446
- get sortString(): string {
447
- return this.action.order || this.label;
286
+ return undefined;
448
287
  }
449
288
  }
@@ -0,0 +1,183 @@
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
+ /**
18
+ * A menu entry representing an action, e.g. "New File".
19
+ */
20
+ export interface MenuAction extends MenuNodeRenderingData, Pick<MenuNodeMetadata, 'when'> {
21
+ /**
22
+ * The command to execute.
23
+ */
24
+ commandId: string;
25
+ /**
26
+ * In addition to the mandatory command property, an alternative command can be defined.
27
+ * It will be shown and invoked when pressing Alt while opening a menu.
28
+ */
29
+ alt?: string;
30
+ /**
31
+ * Menu entries are sorted in ascending order based on their `order` strings. If omitted the determined
32
+ * label will be used instead.
33
+ */
34
+ order?: string;
35
+ }
36
+
37
+ export namespace MenuAction {
38
+ /* Determine whether object is a MenuAction */
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ export function is(arg: MenuAction | any): arg is MenuAction {
41
+ return !!arg && arg === Object(arg) && 'commandId' in arg;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Additional options when creating a new submenu.
47
+ */
48
+ export interface SubMenuOptions extends Pick<MenuAction, 'order'>, Pick<MenuNodeMetadata, 'when'>, Partial<Pick<CompoundMenuNodeMetadata, 'role'>> {
49
+ /**
50
+ * The class to use for the submenu icon.
51
+ */
52
+ iconClass?: string;
53
+ }
54
+
55
+ export type MenuPath = string[];
56
+
57
+ export const MAIN_MENU_BAR: MenuPath = ['menubar'];
58
+
59
+ export const SETTINGS_MENU: MenuPath = ['settings_menu'];
60
+ export const ACCOUNTS_MENU: MenuPath = ['accounts_menu'];
61
+ export const ACCOUNTS_SUBMENU = [...ACCOUNTS_MENU, '1_accounts_submenu'];
62
+
63
+ export interface MenuNodeMetadata {
64
+ /**
65
+ * technical identifier.
66
+ */
67
+ readonly id: string;
68
+ /**
69
+ * Menu nodes are sorted in ascending order based on their `sortString`.
70
+ */
71
+ readonly sortString: string;
72
+ /**
73
+ * Condition under which the menu node should be rendered.
74
+ * See https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts
75
+ */
76
+ readonly when?: string;
77
+ /**
78
+ * A reference to the parent node - useful for determining the menu path by which the node can be accessed.
79
+ */
80
+ readonly parent?: MenuNode;
81
+ }
82
+
83
+ export interface MenuNodeRenderingData {
84
+ /**
85
+ * Optional label. Will be rendered as text of the menu item.
86
+ */
87
+ readonly label?: string;
88
+ /**
89
+ * Icon classes for the menu node. If present, these will produce an icon to the left of the label in browser-style menus.
90
+ */
91
+ readonly icon?: string;
92
+ }
93
+
94
+ export const enum CompoundMenuNodeRole {
95
+ /** Indicates that the node should be rendered as submenu that opens a new menu on hover */
96
+ Submenu,
97
+ /** Indicates that the node's children should be rendered as group separated from other items by a separator */
98
+ Group,
99
+ /** Indicates that the node's children should be treated as though they were direct children of the node's parent */
100
+ Flat,
101
+ }
102
+
103
+ export interface CompoundMenuNode {
104
+ /**
105
+ * Items that are grouped under this menu.
106
+ */
107
+ readonly children: ReadonlyArray<MenuNode>
108
+ }
109
+
110
+ export namespace CompoundMenuNode {
111
+ export function is(node: MenuNode): node is MenuNode & CompoundMenuNode { return Array.isArray(node.children); }
112
+ export function getRole(node: MenuNode): CompoundMenuNodeRole | undefined {
113
+ if (!is(node)) { return undefined; }
114
+ return node.role ?? (node.label ? CompoundMenuNodeRole.Submenu : CompoundMenuNodeRole.Group);
115
+ }
116
+ export function sortChildren(m1: MenuNode, m2: MenuNode): number {
117
+ // The navigation group is special as it will always be sorted to the top/beginning of a menu.
118
+ if (isNavigationGroup(m1)) {
119
+ return -1;
120
+ }
121
+ if (isNavigationGroup(m2)) {
122
+ return 1;
123
+ }
124
+ return m1.sortString.localeCompare(m2.sortString);
125
+ }
126
+
127
+ /** Collapses the children of any subemenus with role {@link CompoundMenuNodeRole Flat} and sorts */
128
+ export function getFlatChildren(children: ReadonlyArray<MenuNode>): MenuNode[] {
129
+ const childrenToMerge: ReadonlyArray<MenuNode>[] = [];
130
+ return children.filter(child => {
131
+ if (getRole(child) === CompoundMenuNodeRole.Flat) {
132
+ childrenToMerge.push((child as CompoundMenuNode).children);
133
+ return false;
134
+ }
135
+ return true;
136
+ }).concat(...childrenToMerge).sort(sortChildren);
137
+ }
138
+
139
+ /**
140
+ * Indicates whether the given node is the special `navigation` menu.
141
+ *
142
+ * @param node the menu node to check.
143
+ * @returns `true` when the given node is a {@link CompoundMenuNode} with id `navigation`,
144
+ * `false` otherwise.
145
+ */
146
+ export function isNavigationGroup(node: MenuNode): node is MenuNode & CompoundMenuNode {
147
+ return is(node) && node.id === 'navigation';
148
+ }
149
+ }
150
+
151
+ export interface CompoundMenuNodeMetadata {
152
+ /**
153
+ * @deprecated @since 1.28 use `role` instead.
154
+ * Whether the item should be rendered as a submenu.
155
+ */
156
+ readonly isSubmenu: boolean;
157
+ /**
158
+ * How the node and its children should be rendered. See {@link CompoundMenuNodeRole}.
159
+ */
160
+ readonly role: CompoundMenuNodeRole;
161
+ }
162
+
163
+ export interface CommandMenuNode {
164
+ command: string;
165
+ }
166
+
167
+ export namespace CommandMenuNode {
168
+ export function is(candidate: MenuNode): candidate is MenuNode & CommandMenuNode { return Boolean(candidate.command); }
169
+ }
170
+
171
+ export interface AlternativeHandlerMenuNode {
172
+ altNode: MenuNodeMetadata & MenuNodeRenderingData & CommandMenuNode;
173
+ }
174
+
175
+ /**
176
+ * Base interface of the nodes used in the menu tree structure.
177
+ */
178
+ export interface MenuNode extends MenuNodeMetadata,
179
+ MenuNodeRenderingData,
180
+ Partial<CompoundMenuNode>,
181
+ Partial<CommandMenuNode>,
182
+ Partial<CompoundMenuNodeMetadata>,
183
+ Partial<AlternativeHandlerMenuNode> { }
@@ -14,9 +14,10 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { CommandContribution, CommandRegistry } from './command';
18
- import { CompositeMenuNode, MenuContribution, MenuModelRegistry } from './menu';
17
+ import { CommandContribution, CommandRegistry } from '../command';
18
+ import { MenuContribution, MenuModelRegistry } from './menu-model-registry';
19
19
  import * as chai from 'chai';
20
+ import { CompositeMenuNode } from './composite-menu-node';
20
21
 
21
22
  const expect = chai.expect;
22
23
 
@@ -71,7 +71,7 @@ export abstract class AbstractConnectionProvider<AbstractOptions extends object>
71
71
  return factory.createProxy();
72
72
  }
73
73
 
74
- protected channelMultiPlexer?: ChannelMultiplexer;
74
+ protected channelMultiplexer?: ChannelMultiplexer;
75
75
 
76
76
  // A set of channel opening functions that are executed if the backend reconnects to restore the
77
77
  // the channels that were open before the disconnect occurred.
@@ -80,7 +80,7 @@ export abstract class AbstractConnectionProvider<AbstractOptions extends object>
80
80
  protected initializeMultiplexer(): void {
81
81
  const mainChannel = this.createMainChannel();
82
82
  mainChannel.onMessage(() => this.onIncomingMessageActivityEmitter.fire());
83
- this.channelMultiPlexer = new ChannelMultiplexer(mainChannel);
83
+ this.channelMultiplexer = new ChannelMultiplexer(mainChannel);
84
84
  }
85
85
 
86
86
  /**
@@ -93,10 +93,10 @@ export abstract class AbstractConnectionProvider<AbstractOptions extends object>
93
93
  }
94
94
 
95
95
  async openChannel(path: string, handler: (channel: Channel) => void, options?: AbstractOptions): Promise<void> {
96
- if (!this.channelMultiPlexer) {
96
+ if (!this.channelMultiplexer) {
97
97
  throw new Error('The channel multiplexer has not been initialized yet!');
98
98
  }
99
- const newChannel = await this.channelMultiPlexer.open(path);
99
+ const newChannel = await this.channelMultiplexer.open(path);
100
100
  newChannel.onClose(() => {
101
101
  const { reconnecting } = { reconnecting: true, ...options };
102
102
  if (reconnecting) {
@@ -195,6 +195,7 @@ export interface QuickPick<T extends QuickPickItemOrSeparator> extends QuickInpu
195
195
  }
196
196
 
197
197
  export interface PickOptions<T extends QuickPickItem> {
198
+ title?: string;
198
199
  placeHolder?: string;
199
200
  matchOnDescription?: boolean;
200
201
  matchOnDetail?: boolean;
@@ -101,8 +101,8 @@ export class ElectronContextMenuRenderer extends BrowserContextMenuRenderer {
101
101
 
102
102
  protected override doRender(options: RenderContextMenuOptions): ContextMenuAccess {
103
103
  if (this.useNativeStyle) {
104
- const { menuPath, anchor, args, onHide } = options;
105
- const menu = this.electronMenuFactory.createElectronContextMenu(menuPath, args);
104
+ const { menuPath, anchor, args, onHide, context } = options;
105
+ const menu = this.electronMenuFactory.createElectronContextMenu(menuPath, args, context);
106
106
  const { x, y } = coordinateFromAnchor(anchor);
107
107
  const zoom = electron.webFrame.getZoomFactor();
108
108
  // TODO: Remove the offset once Electron fixes https://github.com/electron/electron/issues/31641