@theia/core 1.40.1 → 1.42.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 (284) hide show
  1. package/README.md +7 -7
  2. package/i18n/nls.cs.json +6 -1
  3. package/i18n/nls.de.json +6 -1
  4. package/i18n/nls.es.json +6 -1
  5. package/i18n/nls.fr.json +6 -1
  6. package/i18n/nls.hu.json +6 -1
  7. package/i18n/nls.it.json +6 -1
  8. package/i18n/nls.ja.json +6 -1
  9. package/i18n/nls.json +6 -1
  10. package/i18n/nls.pl.json +6 -1
  11. package/i18n/nls.pt-br.json +6 -1
  12. package/i18n/nls.pt-pt.json +6 -1
  13. package/i18n/nls.ru.json +6 -1
  14. package/i18n/nls.zh-cn.json +6 -1
  15. package/lib/browser/common-frontend-contribution.d.ts +11 -0
  16. package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
  17. package/lib/browser/common-frontend-contribution.js +98 -14
  18. package/lib/browser/common-frontend-contribution.js.map +1 -1
  19. package/lib/browser/context-menu-renderer.d.ts +5 -0
  20. package/lib/browser/context-menu-renderer.d.ts.map +1 -1
  21. package/lib/browser/label-parser.d.ts +8 -0
  22. package/lib/browser/label-parser.d.ts.map +1 -1
  23. package/lib/browser/label-parser.js +14 -0
  24. package/lib/browser/label-parser.js.map +1 -1
  25. package/lib/browser/label-parser.spec.js +33 -0
  26. package/lib/browser/label-parser.spec.js.map +1 -1
  27. package/lib/browser/menu/browser-context-menu-renderer.d.ts +1 -1
  28. package/lib/browser/menu/browser-context-menu-renderer.d.ts.map +1 -1
  29. package/lib/browser/menu/browser-context-menu-renderer.js +2 -2
  30. package/lib/browser/menu/browser-context-menu-renderer.js.map +1 -1
  31. package/lib/browser/menu/browser-menu-plugin.d.ts +1 -1
  32. package/lib/browser/menu/browser-menu-plugin.d.ts.map +1 -1
  33. package/lib/browser/menu/browser-menu-plugin.js +2 -2
  34. package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
  35. package/lib/browser/performance/frontend-stopwatch.d.ts.map +1 -1
  36. package/lib/browser/performance/frontend-stopwatch.js +6 -2
  37. package/lib/browser/performance/frontend-stopwatch.js.map +1 -1
  38. package/lib/browser/preferences/preference-contribution.d.ts +2 -0
  39. package/lib/browser/preferences/preference-contribution.d.ts.map +1 -1
  40. package/lib/browser/preferences/preference-contribution.js +48 -24
  41. package/lib/browser/preferences/preference-contribution.js.map +1 -1
  42. package/lib/browser/preload/i18n-preload-contribution.d.ts +7 -0
  43. package/lib/browser/preload/i18n-preload-contribution.d.ts.map +1 -0
  44. package/lib/browser/preload/i18n-preload-contribution.js +63 -0
  45. package/lib/browser/preload/i18n-preload-contribution.js.map +1 -0
  46. package/lib/browser/preload/os-preload-contribution.d.ts +7 -0
  47. package/lib/browser/preload/os-preload-contribution.d.ts.map +1 -0
  48. package/lib/browser/preload/os-preload-contribution.js +49 -0
  49. package/lib/browser/preload/os-preload-contribution.js.map +1 -0
  50. package/lib/browser/preload/preload-module.d.ts +4 -0
  51. package/lib/browser/preload/preload-module.d.ts.map +1 -0
  52. package/lib/browser/preload/preload-module.js +39 -0
  53. package/lib/browser/preload/preload-module.js.map +1 -0
  54. package/lib/browser/preload/preloader.d.ts +12 -0
  55. package/lib/browser/preload/preloader.d.ts.map +1 -0
  56. package/lib/browser/preload/preloader.js +45 -0
  57. package/lib/browser/preload/preloader.js.map +1 -0
  58. package/lib/browser/preload/theme-preload-contribution.d.ts +5 -0
  59. package/lib/browser/preload/theme-preload-contribution.d.ts.map +1 -0
  60. package/lib/browser/preload/theme-preload-contribution.js +40 -0
  61. package/lib/browser/preload/theme-preload-contribution.js.map +1 -0
  62. package/lib/browser/saveable.d.ts +15 -1
  63. package/lib/browser/saveable.d.ts.map +1 -1
  64. package/lib/browser/saveable.js +34 -1
  65. package/lib/browser/saveable.js.map +1 -1
  66. package/lib/browser/shell/application-shell.d.ts +2 -0
  67. package/lib/browser/shell/application-shell.d.ts.map +1 -1
  68. package/lib/browser/shell/application-shell.js +8 -0
  69. package/lib/browser/shell/application-shell.js.map +1 -1
  70. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.d.ts +46 -1
  71. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.d.ts.map +1 -1
  72. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js +87 -6
  73. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js.map +1 -1
  74. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.d.ts +20 -2
  75. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.d.ts.map +1 -1
  76. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.js +28 -1
  77. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.js.map +1 -1
  78. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts +25 -1
  79. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts.map +1 -1
  80. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js +79 -7
  81. package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js.map +1 -1
  82. package/lib/browser/shell/tab-bars.d.ts.map +1 -1
  83. package/lib/browser/shell/tab-bars.js +9 -1
  84. package/lib/browser/shell/tab-bars.js.map +1 -1
  85. package/lib/browser/tree/tree-model.d.ts +2 -0
  86. package/lib/browser/tree/tree-model.d.ts.map +1 -1
  87. package/lib/browser/tree/tree-model.js +6 -0
  88. package/lib/browser/tree/tree-model.js.map +1 -1
  89. package/lib/browser/tree/tree-widget.d.ts +18 -0
  90. package/lib/browser/tree/tree-widget.d.ts.map +1 -1
  91. package/lib/browser/tree/tree-widget.js +57 -0
  92. package/lib/browser/tree/tree-widget.js.map +1 -1
  93. package/lib/browser/tree/tree.d.ts +18 -0
  94. package/lib/browser/tree/tree.d.ts.map +1 -1
  95. package/lib/browser/tree/tree.js +6 -0
  96. package/lib/browser/tree/tree.js.map +1 -1
  97. package/lib/browser/widgets/enhanced-preview-widget.d.ts +7 -0
  98. package/lib/browser/widgets/enhanced-preview-widget.d.ts.map +1 -0
  99. package/lib/browser/widgets/enhanced-preview-widget.js +27 -0
  100. package/lib/browser/widgets/enhanced-preview-widget.js.map +1 -0
  101. package/lib/browser/window-contribution.js +1 -1
  102. package/lib/browser/window-contribution.js.map +1 -1
  103. package/lib/common/array-utils.d.ts +7 -0
  104. package/lib/common/array-utils.d.ts.map +1 -1
  105. package/lib/common/array-utils.js +21 -0
  106. package/lib/common/array-utils.js.map +1 -1
  107. package/lib/common/event.d.ts +5 -0
  108. package/lib/common/event.d.ts.map +1 -1
  109. package/lib/common/event.js +5 -1
  110. package/lib/common/event.js.map +1 -1
  111. package/lib/common/i18n/localization-server.d.ts +7 -0
  112. package/lib/common/i18n/localization-server.d.ts.map +1 -0
  113. package/lib/common/i18n/localization-server.js +21 -0
  114. package/lib/common/i18n/localization-server.js.map +1 -0
  115. package/lib/common/keys.d.ts.map +1 -1
  116. package/lib/common/keys.js +4 -3
  117. package/lib/common/keys.js.map +1 -1
  118. package/lib/common/logger-protocol.d.ts +2 -0
  119. package/lib/common/logger-protocol.d.ts.map +1 -1
  120. package/lib/common/logger-protocol.js +3 -0
  121. package/lib/common/logger-protocol.js.map +1 -1
  122. package/lib/common/logger-watcher.d.ts +4 -3
  123. package/lib/common/logger-watcher.d.ts.map +1 -1
  124. package/lib/common/logger-watcher.js +10 -6
  125. package/lib/common/logger-watcher.js.map +1 -1
  126. package/lib/common/logger.d.ts.map +1 -1
  127. package/lib/common/logger.js +4 -0
  128. package/lib/common/logger.js.map +1 -1
  129. package/lib/common/menu/menu-model-registry.d.ts +12 -1
  130. package/lib/common/menu/menu-model-registry.d.ts.map +1 -1
  131. package/lib/common/menu/menu-model-registry.js +46 -0
  132. package/lib/common/menu/menu-model-registry.js.map +1 -1
  133. package/lib/common/os.d.ts +5 -0
  134. package/lib/common/os.d.ts.map +1 -1
  135. package/lib/common/os.js +3 -1
  136. package/lib/common/os.js.map +1 -1
  137. package/lib/common/performance/measurement.d.ts +21 -0
  138. package/lib/common/performance/measurement.d.ts.map +1 -1
  139. package/lib/common/performance/stopwatch.d.ts +10 -2
  140. package/lib/common/performance/stopwatch.d.ts.map +1 -1
  141. package/lib/common/performance/stopwatch.js +34 -11
  142. package/lib/common/performance/stopwatch.js.map +1 -1
  143. package/lib/common/promise-util.d.ts +4 -0
  144. package/lib/common/promise-util.d.ts.map +1 -1
  145. package/lib/common/promise-util.js +11 -1
  146. package/lib/common/promise-util.js.map +1 -1
  147. package/lib/common/promise-util.spec.js +26 -12
  148. package/lib/common/promise-util.spec.js.map +1 -1
  149. package/lib/common/quick-pick-service.d.ts +6 -0
  150. package/lib/common/quick-pick-service.d.ts.map +1 -1
  151. package/lib/common/quick-pick-service.js.map +1 -1
  152. package/lib/common/types.d.ts +4 -0
  153. package/lib/common/types.d.ts.map +1 -1
  154. package/lib/common/types.js +16 -1
  155. package/lib/common/types.js.map +1 -1
  156. package/lib/common/uri.d.ts +1 -0
  157. package/lib/common/uri.d.ts.map +1 -1
  158. package/lib/common/uri.js +3 -0
  159. package/lib/common/uri.js.map +1 -1
  160. package/lib/electron-browser/menu/electron-context-menu-renderer.js +2 -2
  161. package/lib/electron-browser/menu/electron-context-menu-renderer.js.map +1 -1
  162. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts +1 -1
  163. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
  164. package/lib/electron-browser/menu/electron-main-menu-factory.js +2 -2
  165. package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
  166. package/lib/electron-browser/menu/electron-menu-contribution.d.ts +4 -0
  167. package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
  168. package/lib/electron-browser/menu/electron-menu-contribution.js +12 -0
  169. package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
  170. package/lib/electron-browser/preload.d.ts.map +1 -1
  171. package/lib/electron-browser/preload.js +3 -0
  172. package/lib/electron-browser/preload.js.map +1 -1
  173. package/lib/electron-common/electron-api.d.ts +2 -0
  174. package/lib/electron-common/electron-api.d.ts.map +1 -1
  175. package/lib/electron-common/electron-api.js +2 -1
  176. package/lib/electron-common/electron-api.js.map +1 -1
  177. package/lib/electron-main/electron-api-main.d.ts.map +1 -1
  178. package/lib/electron-main/electron-api-main.js +1 -0
  179. package/lib/electron-main/electron-api-main.js.map +1 -1
  180. package/lib/electron-main/electron-main-application.d.ts +6 -0
  181. package/lib/electron-main/electron-main-application.d.ts.map +1 -1
  182. package/lib/electron-main/electron-main-application.js +37 -4
  183. package/lib/electron-main/electron-main-application.js.map +1 -1
  184. package/lib/node/backend-application-module.d.ts.map +1 -1
  185. package/lib/node/backend-application-module.js +4 -3
  186. package/lib/node/backend-application-module.js.map +1 -1
  187. package/lib/node/backend-application.d.ts +5 -1
  188. package/lib/node/backend-application.d.ts.map +1 -1
  189. package/lib/node/backend-application.js +28 -5
  190. package/lib/node/backend-application.js.map +1 -1
  191. package/lib/node/console-logger-server.d.ts.map +1 -1
  192. package/lib/node/console-logger-server.js +5 -1
  193. package/lib/node/console-logger-server.js.map +1 -1
  194. package/lib/node/i18n/i18n-backend-module.d.ts.map +1 -1
  195. package/lib/node/i18n/i18n-backend-module.js +7 -4
  196. package/lib/node/i18n/i18n-backend-module.js.map +1 -1
  197. package/lib/node/i18n/{localization-backend-contribution.d.ts → localization-server.d.ts} +5 -4
  198. package/lib/node/i18n/localization-server.d.ts.map +1 -0
  199. package/lib/node/i18n/{localization-backend-contribution.js → localization-server.js} +13 -16
  200. package/lib/node/i18n/localization-server.js.map +1 -0
  201. package/lib/node/logger-backend-module.d.ts.map +1 -1
  202. package/lib/node/logger-backend-module.js +6 -1
  203. package/lib/node/logger-backend-module.js.map +1 -1
  204. package/lib/node/logger-cli-contribution.spec.js +1 -1
  205. package/lib/node/logger-cli-contribution.spec.js.map +1 -1
  206. package/lib/node/main.d.ts +2 -5
  207. package/lib/node/main.d.ts.map +1 -1
  208. package/lib/node/main.js.map +1 -1
  209. package/lib/node/os-backend-provider.d.ts +5 -0
  210. package/lib/node/os-backend-provider.d.ts.map +1 -0
  211. package/lib/node/{os-backend-application-contribution.js → os-backend-provider.js} +8 -10
  212. package/lib/node/os-backend-provider.js.map +1 -0
  213. package/lib/node/performance/node-stopwatch.js +1 -1
  214. package/lib/node/performance/node-stopwatch.js.map +1 -1
  215. package/package.json +10 -9
  216. package/src/browser/common-frontend-contribution.ts +108 -17
  217. package/src/browser/context-menu-renderer.ts +5 -0
  218. package/src/browser/label-parser.spec.ts +38 -0
  219. package/src/browser/label-parser.ts +15 -0
  220. package/src/browser/menu/browser-context-menu-renderer.ts +2 -2
  221. package/src/browser/menu/browser-menu-plugin.ts +2 -2
  222. package/src/browser/performance/frontend-stopwatch.ts +5 -2
  223. package/src/browser/preferences/preference-contribution.ts +49 -24
  224. package/src/browser/preload/i18n-preload-contribution.ts +50 -0
  225. package/src/browser/preload/os-preload-contribution.ts +37 -0
  226. package/src/browser/preload/preload-module.ts +45 -0
  227. package/src/browser/preload/preloader.ts +37 -0
  228. package/src/browser/preload/theme-preload-contribution.ts +31 -0
  229. package/src/browser/saveable.ts +41 -2
  230. package/src/browser/shell/application-shell.ts +11 -0
  231. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.ts +94 -8
  232. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.ts +28 -1
  233. package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.tsx +87 -8
  234. package/src/browser/shell/tab-bars.ts +8 -1
  235. package/src/browser/style/tabs.css +32 -2
  236. package/src/browser/tree/tree-model.ts +8 -0
  237. package/src/browser/tree/tree-widget.tsx +66 -0
  238. package/src/browser/tree/tree.ts +27 -0
  239. package/src/browser/widgets/enhanced-preview-widget.ts +27 -0
  240. package/src/browser/window-contribution.ts +1 -1
  241. package/src/common/array-utils.ts +20 -0
  242. package/src/common/event.ts +12 -2
  243. package/src/common/i18n/localization-server.ts +25 -0
  244. package/src/common/i18n/nls.metadata.json +6767 -6260
  245. package/src/common/keys.ts +4 -3
  246. package/src/common/logger-protocol.ts +4 -0
  247. package/src/common/logger-watcher.ts +12 -7
  248. package/src/common/logger.ts +5 -0
  249. package/src/common/menu/menu-model-registry.ts +50 -0
  250. package/src/common/os.ts +8 -0
  251. package/src/common/performance/measurement.ts +26 -0
  252. package/src/common/performance/stopwatch.ts +38 -12
  253. package/src/common/promise-util.spec.ts +43 -12
  254. package/src/common/promise-util.ts +12 -0
  255. package/src/common/quick-pick-service.ts +1 -0
  256. package/src/common/types.ts +17 -0
  257. package/src/common/uri.ts +4 -0
  258. package/src/electron-browser/menu/electron-context-menu-renderer.ts +2 -2
  259. package/src/electron-browser/menu/electron-main-menu-factory.ts +2 -2
  260. package/src/electron-browser/menu/electron-menu-contribution.ts +13 -0
  261. package/src/electron-browser/preload.ts +4 -1
  262. package/src/electron-common/electron-api.ts +2 -0
  263. package/src/electron-main/electron-api-main.ts +4 -1
  264. package/src/electron-main/electron-main-application.ts +43 -4
  265. package/src/node/backend-application-module.ts +7 -4
  266. package/src/node/backend-application.ts +30 -5
  267. package/src/node/console-logger-server.ts +5 -2
  268. package/src/node/i18n/i18n-backend-module.ts +9 -4
  269. package/src/node/i18n/{localization-backend-contribution.ts → localization-server.ts} +9 -10
  270. package/src/node/logger-backend-module.ts +8 -1
  271. package/src/node/logger-cli-contribution.spec.ts +1 -1
  272. package/src/node/main.ts +1 -6
  273. package/src/node/{os-backend-application-contribution.ts → os-backend-provider.ts} +4 -9
  274. package/src/node/performance/node-stopwatch.ts +1 -1
  275. package/lib/browser/preloader.d.ts +0 -2
  276. package/lib/browser/preloader.d.ts.map +0 -1
  277. package/lib/browser/preloader.js +0 -75
  278. package/lib/browser/preloader.js.map +0 -1
  279. package/lib/node/i18n/localization-backend-contribution.d.ts.map +0 -1
  280. package/lib/node/i18n/localization-backend-contribution.js.map +0 -1
  281. package/lib/node/os-backend-application-contribution.d.ts +0 -6
  282. package/lib/node/os-backend-application-contribution.d.ts.map +0 -1
  283. package/lib/node/os-backend-application-contribution.js.map +0 -1
  284. package/src/browser/preloader.ts +0 -76
@@ -22,7 +22,7 @@ import { Anchor, ContextMenuAccess, ContextMenuRenderer } from '../../context-me
22
22
  import { LabelIcon, LabelParser } from '../../label-parser';
23
23
  import { ACTION_ITEM, codicon, ReactWidget, Widget } from '../../widgets';
24
24
  import { TabBarToolbarRegistry } from './tab-bar-toolbar-registry';
25
- import { AnyToolbarItem, ReactTabBarToolbarItem, TabBarDelegator, TabBarToolbarItem, TAB_BAR_TOOLBAR_CONTEXT_MENU } from './tab-bar-toolbar-types';
25
+ import { AnyToolbarItem, ReactTabBarToolbarItem, TabBarDelegator, TabBarToolbarItem, TAB_BAR_TOOLBAR_CONTEXT_MENU, MenuToolbarItem } from './tab-bar-toolbar-types';
26
26
  import { KeybindingRegistry } from '../..//keybinding';
27
27
 
28
28
  /**
@@ -33,6 +33,11 @@ export interface TabBarToolbarFactory {
33
33
  (): TabBarToolbar;
34
34
  }
35
35
 
36
+ /**
37
+ * Class name indicating rendering of a toolbar item without an icon but instead with a text label.
38
+ */
39
+ const NO_ICON_CLASS = 'no-icon';
40
+
36
41
  /**
37
42
  * Tab-bar toolbar widget representing the active [tab-bar toolbar items](TabBarToolbarItem).
38
43
  */
@@ -149,7 +154,9 @@ export class TabBarToolbar extends ReactWidget {
149
154
  this.keybindingContextKeys.clear();
150
155
  return <React.Fragment>
151
156
  {this.renderMore()}
152
- {[...this.inline.values()].map(item => TabBarToolbarItem.is(item) ? this.renderItem(item) : item.render(this.current))}
157
+ {[...this.inline.values()].map(item => TabBarToolbarItem.is(item)
158
+ ? (MenuToolbarItem.is(item) && !item.command ? this.renderMenuItem(item) : this.renderItem(item))
159
+ : item.render(this.current))}
153
160
  </React.Fragment>;
154
161
  }
155
162
 
@@ -176,8 +183,12 @@ export class TabBarToolbar extends ReactWidget {
176
183
  protected renderItem(item: AnyToolbarItem): React.ReactNode {
177
184
  let innerText = '';
178
185
  const classNames = [];
179
- if (item.text) {
180
- for (const labelPart of this.labelParser.parse(item.text)) {
186
+ const command = item.command ? this.commands.getCommand(item.command) : undefined;
187
+ // Fall back to the item ID in extremis so there is _something_ to render in the
188
+ // case that there is neither an icon nor a title
189
+ const itemText = item.text || command?.label || command?.id || item.id;
190
+ if (itemText) {
191
+ for (const labelPart of this.labelParser.parse(itemText)) {
181
192
  if (LabelIcon.is(labelPart)) {
182
193
  const className = `fa fa-${labelPart.name}${labelPart.animation ? ' fa-' + labelPart.animation : ''}`;
183
194
  classNames.push(...className.split(' '));
@@ -186,13 +197,23 @@ export class TabBarToolbar extends ReactWidget {
186
197
  }
187
198
  }
188
199
  }
189
- const command = item.command ? this.commands.getCommand(item.command) : undefined;
190
- let iconClass = (typeof item.icon === 'function' && item.icon()) || item.icon as string || (command && command.iconClass);
200
+ const iconClass = (typeof item.icon === 'function' && item.icon()) || item.icon as string || (command && command.iconClass);
191
201
  if (iconClass) {
192
- iconClass += ` ${ACTION_ITEM}`;
193
202
  classNames.push(iconClass);
194
203
  }
195
- const tooltip = `${item.tooltip || (command && command.label) || ''}${this.resolveKeybindingForCommand(command?.id)}`;
204
+ const tooltipText = item.tooltip || (command && command.label) || '';
205
+ const tooltip = `${this.labelParser.stripIcons(tooltipText)}${this.resolveKeybindingForCommand(command?.id)}`;
206
+
207
+ // Only present text if there is no icon
208
+ if (classNames.length) {
209
+ innerText = '';
210
+ } else if (innerText) {
211
+ // Make room for the label text
212
+ classNames.push(NO_ICON_CLASS);
213
+ }
214
+
215
+ // In any case, this is an action item, with or without icon.
216
+ classNames.push(ACTION_ITEM);
196
217
 
197
218
  const toolbarItemClassNames = this.getToolbarItemClassNames(item);
198
219
  return <div key={item.id}
@@ -224,6 +245,10 @@ export class TabBarToolbar extends ReactWidget {
224
245
  if (this.commandIsToggled(item.command)) {
225
246
  classNames.push('toggled');
226
247
  }
248
+ } else {
249
+ if (this.isEnabled(item)) {
250
+ classNames.push('enabled');
251
+ }
227
252
  }
228
253
  return classNames;
229
254
  }
@@ -281,6 +306,60 @@ export class TabBarToolbar extends ReactWidget {
281
306
  args: [this.current],
282
307
  anchor,
283
308
  context: this.current?.node,
309
+ onHide: () => toDisposeOnHide.dispose(),
310
+ skipSingleRootNode: true,
311
+ });
312
+ }
313
+
314
+ /**
315
+ * Renders a toolbar item that is a menu, presenting it as a button with a little
316
+ * chevron decoration that pops up a floating menu when clicked.
317
+ *
318
+ * @param item a toolbar item that is a menu item
319
+ * @returns the rendered toolbar item
320
+ */
321
+ protected renderMenuItem(item: TabBarToolbarItem & MenuToolbarItem): React.ReactNode {
322
+ const icon = typeof item.icon === 'function' ? item.icon() : item.icon ?? 'ellipsis';
323
+ return <div key={item.id}
324
+ className={TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM + ' enabled menu'}
325
+ onClick={this.showPopupMenu.bind(this, item.menuPath)}>
326
+ <div id={item.id} className={codicon(icon, true)}
327
+ title={item.text} />
328
+ <div className={codicon('chevron-down') + ' chevron'} />
329
+ </div >;
330
+ }
331
+
332
+ /**
333
+ * Presents the menu to popup on the `event` that is the clicking of
334
+ * a menu toolbar item.
335
+ *
336
+ * @param menuPath the path of the registered menu to show
337
+ * @param event the mouse event triggering the menu
338
+ */
339
+ protected showPopupMenu = (menuPath: MenuPath, event: React.MouseEvent) => {
340
+ event.stopPropagation();
341
+ event.preventDefault();
342
+ const anchor = this.toAnchor(event);
343
+ this.renderPopupMenu(menuPath, anchor);
344
+ };
345
+
346
+ /**
347
+ * Renders the menu popped up on a menu toolbar item.
348
+ *
349
+ * @param menuPath the path of the registered menu to render
350
+ * @param anchor a description of where to render the menu
351
+ * @returns platform-specific access to the rendered context menu
352
+ */
353
+ protected renderPopupMenu(menuPath: MenuPath, anchor: Anchor): ContextMenuAccess {
354
+ const toDisposeOnHide = new DisposableCollection();
355
+ this.addClass('menu-open');
356
+ toDisposeOnHide.push(Disposable.create(() => this.removeClass('menu-open')));
357
+
358
+ return this.contextMenuRenderer.render({
359
+ menuPath,
360
+ args: [this.current],
361
+ anchor,
362
+ context: this.current?.node,
284
363
  onHide: () => toDisposeOnHide.dispose()
285
364
  });
286
365
  }
@@ -38,6 +38,7 @@ import { Root, createRoot } from 'react-dom/client';
38
38
  import { SelectComponent } from '../widgets/select-component';
39
39
  import { createElement } from 'react';
40
40
  import { PreviewableWidget } from '../widgets/previewable-widget';
41
+ import { EnhancedPreviewWidget } from '../widgets/enhanced-preview-widget';
41
42
 
42
43
  /** The class name added to hidden content nodes, which are required to render vertical side bars. */
43
44
  const HIDDEN_CONTENT_CLASS = 'theia-TabBar-hidden-content';
@@ -504,7 +505,13 @@ export class TabBarRenderer extends TabBar.Renderer {
504
505
  labelElement.classList.add('theia-horizontal-tabBar-hover-title');
505
506
  labelElement.textContent = title.label;
506
507
  hoverBox.append(labelElement);
507
- if (title.caption) {
508
+ const widget = title.owner;
509
+ if (EnhancedPreviewWidget.is(widget)) {
510
+ const enhancedPreviewNode = widget.getEnhancedPreviewNode();
511
+ if (enhancedPreviewNode) {
512
+ hoverBox.appendChild(enhancedPreviewNode);
513
+ }
514
+ } else if (title.caption) {
508
515
  const captionElement = document.createElement('p');
509
516
  captionElement.classList.add('theia-horizontal-tabBar-hover-caption');
510
517
  captionElement.textContent = title.caption;
@@ -254,8 +254,8 @@
254
254
  }
255
255
 
256
256
  .p-TabBar.theia-app-centers
257
- .p-TabBar-tab:hover.p-mod-closable
258
- > .p-TabBar-tabCloseIcon {
257
+ .p-TabBar-tab.p-mod-closable
258
+ > .p-TabBar-tabCloseIcon:hover {
259
259
  border-radius: 5px;
260
260
  background-color: rgba(50%, 50%, 50%, 0.2);
261
261
  }
@@ -459,6 +459,10 @@
459
459
  cursor: pointer;
460
460
  }
461
461
 
462
+ .p-TabBar-toolbar .item.enabled .action-label::before {
463
+ display: flex;
464
+ }
465
+
462
466
  .p-TabBar-toolbar :not(.item.enabled) .action-label {
463
467
  background: transparent;
464
468
  cursor: default;
@@ -476,6 +480,11 @@
476
480
  line-height: 18px;
477
481
  }
478
482
 
483
+ .p-TabBar-toolbar .item > div.no-icon {
484
+ /* Make room for a text label instead of an icon. */
485
+ width: 100%;
486
+ }
487
+
479
488
  .p-TabBar-toolbar .item .collapse-all {
480
489
  background: var(--theia-icon-collapse-all) no-repeat;
481
490
  }
@@ -496,6 +505,27 @@
496
505
  background: var(--theia-icon-close) no-repeat;
497
506
  }
498
507
 
508
+ /** Configure layout of a toolbar item that shows a pop-up menu. */
509
+ .p-TabBar-toolbar .item.menu {
510
+ display: grid;
511
+ }
512
+
513
+ /** The elements of the item that shows a pop-up menu are stack atop one other. */
514
+ .p-TabBar-toolbar .item.menu > div {
515
+ grid-area: 1 / 1;
516
+ }
517
+
518
+ /**
519
+ * The chevron for the pop-up menu indication is shrunk and
520
+ * stuffed in the bottom-right corner.
521
+ */
522
+ .p-TabBar-toolbar .item.menu > .chevron {
523
+ scale: 50%;
524
+ align-self: end;
525
+ justify-self: end;
526
+ translate: 5px 3px;
527
+ }
528
+
499
529
  #theia-main-content-panel
500
530
  .p-TabBar:not(.theia-tabBar-active)
501
531
  .p-TabBar-toolbar {
@@ -472,6 +472,14 @@ export class TreeModelImpl implements TreeModel, SelectionProvider<ReadonlyArray
472
472
  return this.tree.markAsBusy(node, ms, token);
473
473
  }
474
474
 
475
+ get onDidUpdate(): Event<TreeNode[]> {
476
+ return this.tree.onDidUpdate;
477
+ }
478
+
479
+ markAsChecked(node: TreeNode, checked: boolean): void {
480
+ this.tree.markAsChecked(node, checked);
481
+ }
482
+
475
483
  }
476
484
  export namespace TreeModelImpl {
477
485
  export interface State {
@@ -243,12 +243,16 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
243
243
  }),
244
244
  ]);
245
245
  }
246
+ this.node.addEventListener('mousedown', this.handleMiddleClickEvent.bind(this));
247
+ this.node.addEventListener('mouseup', this.handleMiddleClickEvent.bind(this));
248
+ this.node.addEventListener('auxclick', this.handleMiddleClickEvent.bind(this));
246
249
  this.toDispose.pushAll([
247
250
  this.model,
248
251
  this.model.onChanged(() => this.updateRows()),
249
252
  this.model.onSelectionChanged(() => this.scheduleUpdateScrollToRow({ resize: false })),
250
253
  this.focusService.onDidChangeFocus(() => this.scheduleUpdateScrollToRow({ resize: false })),
251
254
  this.model.onDidChangeBusy(() => this.update()),
255
+ this.model.onDidUpdate(() => this.update()),
252
256
  this.model.onNodeRefreshed(() => this.updateDecorations()),
253
257
  this.model.onExpansionChanged(() => this.updateDecorations()),
254
258
  this.decoratorService,
@@ -575,6 +579,40 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
575
579
  </div>;
576
580
  }
577
581
 
582
+ /**
583
+ * Render the node expansion toggle.
584
+ * @param node the tree node.
585
+ * @param props the node properties.
586
+ */
587
+ protected renderCheckbox(node: TreeNode, props: NodeProps): React.ReactNode {
588
+ if (node.checkboxInfo === undefined) {
589
+ // eslint-disable-next-line no-null/no-null
590
+ return null;
591
+ }
592
+ return <input data-node-id={node.id}
593
+ readOnly
594
+ type='checkbox'
595
+ checked={!!node.checkboxInfo.checked}
596
+ title={node.checkboxInfo.tooltip}
597
+ aria-label={node.checkboxInfo.accessibilityInformation?.label}
598
+ role={node.checkboxInfo.accessibilityInformation?.role}
599
+ className='theia-input'
600
+ onClick={event => this.toggleChecked(event)} />;
601
+ }
602
+
603
+ protected toggleChecked(event: React.MouseEvent<HTMLElement>): void {
604
+ const nodeId = event.currentTarget.getAttribute('data-node-id');
605
+ if (nodeId) {
606
+ const node = this.model.getNode(nodeId);
607
+ if (node) {
608
+ this.model.markAsChecked(node, !node.checkboxInfo!.checked);
609
+ } else {
610
+ this.handleClickEvent(node, event);
611
+ }
612
+ }
613
+ event.preventDefault();
614
+ event.stopPropagation();
615
+ }
578
616
  /**
579
617
  * Render the tree node caption given the node properties.
580
618
  * @param node the tree node.
@@ -902,6 +940,7 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
902
940
  const attributes = this.createNodeAttributes(node, props);
903
941
  const content = <div className={TREE_NODE_CONTENT_CLASS}>
904
942
  {this.renderExpansionToggle(node, props)}
943
+ {this.renderCheckbox(node, props)}
905
944
  {this.decorateIcon(node, this.renderIcon(node, props))}
906
945
  {this.renderCaptionAffixes(node, props, 'captionPrefixes')}
907
946
  {this.renderCaption(node, props)}
@@ -924,6 +963,7 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
924
963
  style,
925
964
  onClick: event => this.handleClickEvent(node, event),
926
965
  onDoubleClick: event => this.handleDblClickEvent(node, event),
966
+ onAuxClick: event => this.handleAuxClickEvent(node, event),
927
967
  onContextMenu: event => this.handleContextMenuEvent(node, event),
928
968
  };
929
969
  }
@@ -1238,6 +1278,32 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
1238
1278
  event.stopPropagation();
1239
1279
  }
1240
1280
 
1281
+ /**
1282
+ * Handle the middle-click mouse event.
1283
+ * @param node the tree node if available.
1284
+ * @param event the middle-click mouse event.
1285
+ */
1286
+ protected handleAuxClickEvent(node: TreeNode | undefined, event: React.MouseEvent<HTMLElement>): void {
1287
+ if (event.button === 1) {
1288
+ this.model.openNode(node);
1289
+ if (SelectableTreeNode.is(node)) {
1290
+ this.model.selectNode(node);
1291
+ }
1292
+ }
1293
+ event.stopPropagation();
1294
+ }
1295
+
1296
+ /**
1297
+ * Handle the middle-click mouse event.
1298
+ * @param event the middle-click mouse event.
1299
+ */
1300
+ protected handleMiddleClickEvent(event: MouseEvent): void {
1301
+ // Prevents auto-scrolling behavior when middle-clicking.
1302
+ if (event.button === 1) {
1303
+ event.preventDefault();
1304
+ }
1305
+ }
1306
+
1241
1307
  /**
1242
1308
  * Handle the context menu click event.
1243
1309
  * - The context menu click event is triggered by the right-click.
@@ -20,6 +20,7 @@ import { Disposable, DisposableCollection } from '../../common/disposable';
20
20
  import { CancellationToken, CancellationTokenSource } from '../../common/cancellation';
21
21
  import { timeout } from '../../common/promise-util';
22
22
  import { isObject, Mutable } from '../../common';
23
+ import { AccessibilityInformation } from '../../common/accessibility';
23
24
 
24
25
  export const Tree = Symbol('Tree');
25
26
 
@@ -70,6 +71,19 @@ export interface Tree extends Disposable {
70
71
  * A token source of the given token should be canceled to unmark.
71
72
  */
72
73
  markAsBusy(node: Readonly<TreeNode>, ms: number, token: CancellationToken): Promise<void>;
74
+
75
+ /**
76
+ * An update to the tree node occurred, but the tree structure remains unchanged
77
+ */
78
+ readonly onDidUpdate: Event<TreeNode[]>;
79
+
80
+ markAsChecked(node: TreeNode, checked: boolean): void;
81
+ }
82
+
83
+ export interface TreeViewItemCheckboxInfo {
84
+ checked: boolean;
85
+ tooltip?: string;
86
+ accessibilityInformation?: AccessibilityInformation
73
87
  }
74
88
 
75
89
  /**
@@ -120,6 +134,11 @@ export interface TreeNode {
120
134
  * Whether this node is busy. Greater than 0 then busy; otherwise not.
121
135
  */
122
136
  readonly busy?: number;
137
+
138
+ /**
139
+ * Whether this node is checked.
140
+ */
141
+ readonly checkboxInfo?: TreeViewItemCheckboxInfo;
123
142
  }
124
143
 
125
144
  export namespace TreeNode {
@@ -238,6 +257,8 @@ export class TreeImpl implements Tree {
238
257
 
239
258
  protected readonly onDidChangeBusyEmitter = new Emitter<TreeNode>();
240
259
  readonly onDidChangeBusy = this.onDidChangeBusyEmitter.event;
260
+ protected readonly onDidUpdateEmitter = new Emitter<TreeNode[]>();
261
+ readonly onDidUpdate = this.onDidUpdateEmitter.event;
241
262
 
242
263
  protected nodes: {
243
264
  [id: string]: Mutable<TreeNode> | undefined
@@ -368,6 +389,12 @@ export class TreeImpl implements Tree {
368
389
  await this.doMarkAsBusy(node, ms, token);
369
390
  }
370
391
  }
392
+
393
+ markAsChecked(node: Mutable<TreeNode>, checked: boolean): void {
394
+ node.checkboxInfo!.checked = checked;
395
+ this.onDidUpdateEmitter.fire([node]);
396
+ }
397
+
371
398
  protected async doMarkAsBusy(node: Mutable<TreeNode>, ms: number, token: CancellationToken): Promise<void> {
372
399
  try {
373
400
  await timeout(ms, token);
@@ -0,0 +1,27 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2023 STMicroelectronics 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-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { isFunction, isObject } from '../../common';
18
+
19
+ export interface EnhancedPreviewWidget {
20
+ getEnhancedPreviewNode(): Node | undefined;
21
+ }
22
+
23
+ export namespace EnhancedPreviewWidget {
24
+ export function is(arg: unknown): arg is EnhancedPreviewWidget {
25
+ return isObject<EnhancedPreviewWidget>(arg) && isFunction(arg.getEnhancedPreviewNode);
26
+ }
27
+ }
@@ -51,7 +51,7 @@ export class WindowContribution implements CommandContribution, KeybindingContri
51
51
  }
52
52
 
53
53
  registerMenus(registry: MenuModelRegistry): void {
54
- registry.registerMenuAction(CommonMenus.FILE_NEW, {
54
+ registry.registerMenuAction(CommonMenus.FILE_NEW_TEXT, {
55
55
  commandId: WindowCommands.NEW_WINDOW.id,
56
56
  order: 'c'
57
57
  });
@@ -106,4 +106,24 @@ export namespace ArrayUtils {
106
106
  export function coalesce<T>(array: ReadonlyArray<T | undefined | null>): T[] {
107
107
  return <T[]>array.filter(e => !!e);
108
108
  }
109
+
110
+ /**
111
+ * groups array elements through a comparator function
112
+ * @param data array of elements to group
113
+ * @param compare comparator function: return of 0 means should group, anything above means not group
114
+ * @returns array of arrays with grouped elements
115
+ */
116
+ export function groupBy<T>(data: ReadonlyArray<T>, compare: (a: T, b: T) => number): T[][] {
117
+ const result: T[][] = [];
118
+ let currentGroup: T[] | undefined = undefined;
119
+ for (const element of data.slice(0).sort(compare)) {
120
+ if (!currentGroup || compare(currentGroup[0], element) !== 0) {
121
+ currentGroup = [element];
122
+ result.push(currentGroup);
123
+ } else {
124
+ currentGroup.push(element);
125
+ }
126
+ }
127
+ return result;
128
+ }
109
129
  }
@@ -16,7 +16,7 @@
16
16
 
17
17
  /* eslint-disable @typescript-eslint/no-explicit-any */
18
18
 
19
- import { Disposable, DisposableGroup } from './disposable';
19
+ import { Disposable, DisposableGroup, DisposableCollection } from './disposable';
20
20
  import { MaybePromise } from './types';
21
21
 
22
22
  /**
@@ -67,6 +67,16 @@ export namespace Event {
67
67
  set maxListeners(maxListeners: number) { }
68
68
  });
69
69
  }
70
+
71
+ /**
72
+ * Given a collection of events, returns a single event which emits whenever any of the provided events emit.
73
+ */
74
+ export function any<T>(...events: Event<T>[]): Event<T>;
75
+ export function any(...events: Event<any>[]): Event<void>;
76
+ export function any<T>(...events: Event<T>[]): Event<T> {
77
+ return (listener, thisArgs = undefined, disposables?: Disposable[]) =>
78
+ new DisposableCollection(...events.map(event => event(e => listener.call(thisArgs, e), undefined, disposables)));
79
+ }
70
80
  }
71
81
 
72
82
  type Callback = (...args: any[]) => any;
@@ -276,7 +286,7 @@ export class Emitter<T = any> {
276
286
  */
277
287
  fire(event: T): any {
278
288
  if (this._callbacks) {
279
- this._callbacks.invoke(event);
289
+ return this._callbacks.invoke(event);
280
290
  }
281
291
  }
282
292
 
@@ -0,0 +1,25 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2023 TypeFox 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-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { Localization } from './localization';
18
+
19
+ export const LocalizationServerPath = '/localization-server';
20
+
21
+ export const LocalizationServer = Symbol('LocalizationServer');
22
+
23
+ export interface LocalizationServer {
24
+ loadLocalization(languageId: string): Promise<Localization>;
25
+ }