@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
@@ -14,6 +14,7 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
+ import { nls } from './nls';
17
18
  import { isOSX } from './os';
18
19
  import { isObject } from './types';
19
20
 
@@ -252,7 +253,7 @@ export class KeyCode {
252
253
  }
253
254
  /* If duplicates i.e ctrl+ctrl+a or alt+alt+b or b+alt+b it is invalid */
254
255
  if (keys.length !== new Set(keys).size) {
255
- throw new Error(`Can't parse keybinding ${keybinding} Duplicate modifiers`);
256
+ throw new Error(nls.localize('theia/core/keybinding/duplicateModifierError', "Can't parse keybinding {0} Duplicate modifiers", keybinding));
256
257
  }
257
258
 
258
259
  for (let keyString of keys) {
@@ -266,7 +267,7 @@ export class KeyCode {
266
267
  if (isOSX) {
267
268
  schema.meta = true;
268
269
  } else {
269
- throw new Error(`Can't parse keybinding ${keybinding} meta is for OSX only`);
270
+ throw new Error(nls.localize('theia/core/keybinding/metaError', "Can't parse keybinding {0} meta is for OSX only", keybinding));
270
271
  }
271
272
  /* ctrlcmd for M1 keybindings that work on both macOS and other platforms */
272
273
  } else if (keyString === SpecialCases.CTRLCMD) {
@@ -288,7 +289,7 @@ export class KeyCode {
288
289
  schema.key = key;
289
290
  }
290
291
  } else {
291
- throw new Error(`Unrecognized key '${keyString}' in '${keybinding}'`);
292
+ throw new Error(nls.localize('theia/core/keybinding/unrecognizedKeyError', 'Unrecognized key {0} in {1}', keyString, keybinding));
292
293
  }
293
294
  }
294
295
 
@@ -38,6 +38,7 @@ export interface ILogLevelChangedEvent {
38
38
 
39
39
  export interface ILoggerClient {
40
40
  onLogLevelChanged(event: ILogLevelChangedEvent): void;
41
+ onLogConfigChanged(): void;
41
42
  }
42
43
 
43
44
  @injectable()
@@ -49,6 +50,9 @@ export class DispatchingLoggerClient implements ILoggerClient {
49
50
  this.clients.forEach(client => client.onLogLevelChanged(event));
50
51
  }
51
52
 
53
+ onLogConfigChanged(): void {
54
+ this.clients.forEach(client => client.onLogConfigChanged());
55
+ }
52
56
  }
53
57
 
54
58
  export const rootLoggerName = 'root';
@@ -22,22 +22,27 @@ import { ILoggerClient, ILogLevelChangedEvent } from './logger-protocol';
22
22
  export class LoggerWatcher {
23
23
 
24
24
  getLoggerClient(): ILoggerClient {
25
- const emitter = this.onLogLevelChangedEmitter;
25
+ const logLevelEmitter = this.onLogLevelChangedEmitter;
26
+ const logConfigEmitter = this.onLogConfigChangedEmitter;
26
27
  return {
27
28
  onLogLevelChanged(event: ILogLevelChangedEvent): void {
28
- emitter.fire(event);
29
- }
29
+ logLevelEmitter.fire(event);
30
+ },
31
+ onLogConfigChanged(): void {
32
+ logConfigEmitter.fire();
33
+ },
30
34
  };
31
35
  }
32
36
 
33
- private onLogLevelChangedEmitter = new Emitter<ILogLevelChangedEvent>();
37
+ protected onLogLevelChangedEmitter = new Emitter<ILogLevelChangedEvent>();
34
38
 
35
39
  get onLogLevelChanged(): Event<ILogLevelChangedEvent> {
36
40
  return this.onLogLevelChangedEmitter.event;
37
41
  }
38
42
 
39
- // FIXME: get rid of it, backend services should as well set a client on the server
40
- fireLogLevelChanged(event: ILogLevelChangedEvent): void {
41
- this.onLogLevelChangedEmitter.fire(event);
43
+ protected onLogConfigChangedEmitter = new Emitter<void>();
44
+
45
+ get onLogConfigChanged(): Event<void> {
46
+ return this.onLogConfigChangedEmitter.event;
42
47
  }
43
48
  }
@@ -261,6 +261,11 @@ export class Logger implements ILogger {
261
261
  }
262
262
  });
263
263
  });
264
+
265
+ /* Refetch log level if overall config in backend changed. */
266
+ this.loggerWatcher.onLogConfigChanged(() => {
267
+ this._logLevel = this.created.then(_ => this.server.getLogLevel(this.name));
268
+ });
264
269
  }
265
270
 
266
271
  setLogLevel(logLevel: number): Promise<void> {
@@ -254,6 +254,56 @@ export class MenuModelRegistry {
254
254
  return this.findGroup(menuPath);
255
255
  }
256
256
 
257
+ /**
258
+ * Checks the given menu model whether it will show a menu with a single submenu.
259
+ *
260
+ * @param fullMenuModel the menu model to analyze
261
+ * @param menuPath the menu's path
262
+ * @returns if the menu will show a single submenu this returns a menu that will show the child elements of the submenu,
263
+ * otherwise the given `fullMenuModel` is return
264
+ */
265
+ removeSingleRootNode(fullMenuModel: MutableCompoundMenuNode, menuPath: MenuPath): CompoundMenuNode {
266
+ // check whether all children are compound menus and that there is only one child that has further children
267
+ if (!this.allChildrenCompound(fullMenuModel.children)) {
268
+ return fullMenuModel;
269
+ }
270
+ let nonEmptyNode = undefined;
271
+ for (const child of fullMenuModel.children) {
272
+ if (!this.isEmpty(child.children || [])) {
273
+ if (nonEmptyNode === undefined) {
274
+ nonEmptyNode = child;
275
+ } else {
276
+ return fullMenuModel;
277
+ }
278
+ }
279
+ }
280
+
281
+ if (CompoundMenuNode.is(nonEmptyNode) && nonEmptyNode.children.length === 1 && CompoundMenuNode.is(nonEmptyNode.children[0])) {
282
+ nonEmptyNode = nonEmptyNode.children[0];
283
+ }
284
+
285
+ return CompoundMenuNode.is(nonEmptyNode) ? nonEmptyNode : fullMenuModel;
286
+ }
287
+
288
+ protected allChildrenCompound(children: ReadonlyArray<MenuNode>): boolean {
289
+ return children.every(CompoundMenuNode.is);
290
+ }
291
+
292
+ protected isEmpty(children: ReadonlyArray<MenuNode>): boolean {
293
+ if (children.length === 0) {
294
+ return true;
295
+ }
296
+ if (!this.allChildrenCompound(children)) {
297
+ return false;
298
+ }
299
+ for (const child of children) {
300
+ if (!this.isEmpty(child.children || [])) {
301
+ return false;
302
+ }
303
+ }
304
+ return true;
305
+ }
306
+
257
307
  /**
258
308
  * Returns the {@link MenuPath path} at which a given menu node can be accessed from this registry, if it can be determined.
259
309
  * Returns `undefined` if the `parent` of any node in the chain is unknown.
package/src/common/os.ts CHANGED
@@ -72,3 +72,11 @@ export namespace OS {
72
72
  };
73
73
 
74
74
  }
75
+
76
+ export const OSBackendProviderPath = '/os';
77
+
78
+ export const OSBackendProvider = Symbol('OSBackendProvider');
79
+
80
+ export interface OSBackendProvider {
81
+ getBackendOS(): Promise<OS.Type>;
82
+ }
@@ -101,4 +101,30 @@ export interface MeasurementOptions {
101
101
  * @see {@link thresholdLogLevel}
102
102
  */
103
103
  thresholdMillis?: number;
104
+
105
+ /**
106
+ * Flag to indicate whether the stopwatch should store measurement results for later retrieval.
107
+ * For example the cache can be used to retrieve measurements which were taken during startup before a listener had a chance to register.
108
+ */
109
+ storeResults?: boolean
110
+ }
111
+
112
+ /**
113
+ * Captures the result of a {@link Measurement} in a serializable format.
114
+ */
115
+ export interface MeasurementResult {
116
+ /** The measurement name. This may show up in the performance measurement framework appropriate to the application context. */
117
+ name: string;
118
+
119
+ /** The time when the measurement recording has been started */
120
+ startTime: number;
121
+
122
+ /**
123
+ * The elapsed time measured, if it has been {@link stop stopped} and measured, or `NaN` if the platform disabled
124
+ * performance measurement.
125
+ */
126
+ elapsed: number;
127
+
128
+ /** An optional label for the application the start of which (in real time) is the basis of all measurements. */
129
+ owner?: string;
104
130
  }
@@ -19,7 +19,8 @@
19
19
  import { inject, injectable } from 'inversify';
20
20
  import { ILogger, LogLevel } from '../logger';
21
21
  import { MaybePromise } from '../types';
22
- import { Measurement, MeasurementOptions } from './measurement';
22
+ import { Measurement, MeasurementOptions, MeasurementResult } from './measurement';
23
+ import { Emitter, Event } from '../event';
23
24
 
24
25
  /** The default log level for measurements that are not otherwise configured with a default. */
25
26
  const DEFAULT_LOG_LEVEL = LogLevel.INFO;
@@ -50,10 +51,20 @@ export abstract class Stopwatch {
50
51
  @inject(ILogger)
51
52
  protected readonly logger: ILogger;
52
53
 
54
+ protected _storedMeasurements: MeasurementResult[] = [];
55
+
56
+ protected onDidAddMeasurementResultEmitter = new Emitter<MeasurementResult>();
57
+ get onDidAddMeasurementResult(): Event<MeasurementResult> {
58
+ return this.onDidAddMeasurementResultEmitter.event;
59
+ }
60
+
53
61
  constructor(protected readonly defaultLogOptions: LogOptions) {
54
62
  if (!defaultLogOptions.defaultLogLevel) {
55
63
  defaultLogOptions.defaultLogLevel = DEFAULT_LOG_LEVEL;
56
64
  }
65
+ if (defaultLogOptions.storeResults === undefined) {
66
+ defaultLogOptions.storeResults = true;
67
+ }
57
68
  }
58
69
 
59
70
  /**
@@ -91,25 +102,36 @@ export abstract class Stopwatch {
91
102
  return result;
92
103
  }
93
104
 
94
- protected createMeasurement(name: string, measurement: () => number, options?: MeasurementOptions): Measurement {
105
+ protected createMeasurement(name: string, measure: () => { startTime: number, duration: number }, options?: MeasurementOptions): Measurement {
95
106
  const logOptions = this.mergeLogOptions(options);
96
107
 
97
- const result: Measurement = {
108
+ const measurement: Measurement = {
98
109
  name,
99
110
  stop: () => {
100
- if (result.elapsed === undefined) {
101
- result.elapsed = measurement();
111
+ if (measurement.elapsed === undefined) {
112
+ const { startTime, duration } = measure();
113
+ measurement.elapsed = duration;
114
+ const result: MeasurementResult = {
115
+ name,
116
+ elapsed: duration,
117
+ startTime,
118
+ owner: logOptions.owner
119
+ };
120
+ if (logOptions.storeResults) {
121
+ this._storedMeasurements.push(result);
122
+ }
123
+ this.onDidAddMeasurementResultEmitter.fire(result);
102
124
  }
103
- return result.elapsed;
125
+ return measurement.elapsed;
104
126
  },
105
- log: (activity: string, ...optionalArgs: any[]) => this.log(result, activity, this.atLevel(logOptions, undefined, optionalArgs)),
106
- debug: (activity: string, ...optionalArgs: any[]) => this.log(result, activity, this.atLevel(logOptions, LogLevel.DEBUG, optionalArgs)),
107
- info: (activity: string, ...optionalArgs: any[]) => this.log(result, activity, this.atLevel(logOptions, LogLevel.INFO, optionalArgs)),
108
- warn: (activity: string, ...optionalArgs: any[]) => this.log(result, activity, this.atLevel(logOptions, LogLevel.WARN, optionalArgs)),
109
- error: (activity: string, ...optionalArgs: any[]) => this.log(result, activity, this.atLevel(logOptions, LogLevel.ERROR, optionalArgs)),
127
+ log: (activity: string, ...optionalArgs: any[]) => this.log(measurement, activity, this.atLevel(logOptions, undefined, optionalArgs)),
128
+ debug: (activity: string, ...optionalArgs: any[]) => this.log(measurement, activity, this.atLevel(logOptions, LogLevel.DEBUG, optionalArgs)),
129
+ info: (activity: string, ...optionalArgs: any[]) => this.log(measurement, activity, this.atLevel(logOptions, LogLevel.INFO, optionalArgs)),
130
+ warn: (activity: string, ...optionalArgs: any[]) => this.log(measurement, activity, this.atLevel(logOptions, LogLevel.WARN, optionalArgs)),
131
+ error: (activity: string, ...optionalArgs: any[]) => this.log(measurement, activity, this.atLevel(logOptions, LogLevel.ERROR, optionalArgs)),
110
132
  };
111
133
 
112
- return result;
134
+ return measurement;
113
135
  }
114
136
 
115
137
  protected mergeLogOptions(logOptions?: Partial<LogOptions>): LogOptions {
@@ -154,4 +176,8 @@ export abstract class Stopwatch {
154
176
  this.logger.log(level, `${whatWasMeasured}: ${elapsed.toFixed(1)} ms [${timeFromStart}]`, ...(options.arguments ?? []));
155
177
  }
156
178
 
179
+ get storedMeasurements(): ReadonlyArray<MeasurementResult> {
180
+ return this._storedMeasurements;
181
+ }
182
+
157
183
  }
@@ -13,22 +13,19 @@
13
13
  //
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
- import * as assert from 'assert';
17
- import { waitForEvent } from './promise-util';
16
+ import * as assert from 'assert/strict';
17
+ import { firstTrue, waitForEvent } from './promise-util';
18
18
  import { Emitter } from './event';
19
+ import { CancellationError } from './cancellation';
19
20
 
20
21
  describe('promise-util', () => {
21
- it('should time out', async () => {
22
- const emitter = new Emitter<string>();
23
- try {
24
- await waitForEvent(emitter.event, 1000);
25
- assert.fail('did not time out');
26
- } catch (e) {
27
- // OK
28
- }
29
- });
30
22
 
31
- describe('promise-util', () => {
23
+ describe('waitForEvent', () => {
24
+ it('should time out', async () => {
25
+ const emitter = new Emitter<string>();
26
+ await assert.rejects(waitForEvent(emitter.event, 1000), reason => reason instanceof CancellationError);
27
+ });
28
+
32
29
  it('should get event', async () => {
33
30
  const emitter = new Emitter<string>();
34
31
  setTimeout(() => {
@@ -38,4 +35,38 @@ describe('promise-util', () => {
38
35
  });
39
36
  });
40
37
 
38
+ describe('firstTrue', () => {
39
+ it('should resolve to false when the promises arg is empty', async () => {
40
+ const actual = await firstTrue();
41
+ assert.strictEqual(actual, false);
42
+ });
43
+
44
+ it('should resolve to true when the first promise resolves to true', async () => {
45
+ const signals: string[] = [];
46
+ const createPromise = (signal: string, timeout: number, result: boolean) =>
47
+ new Promise<boolean>(resolve => setTimeout(() => {
48
+ signals.push(signal);
49
+ resolve(result);
50
+ }, timeout));
51
+ const actual = await firstTrue(
52
+ createPromise('a', 10, false),
53
+ createPromise('b', 20, false),
54
+ createPromise('c', 30, true),
55
+ createPromise('d', 40, false),
56
+ createPromise('e', 50, true)
57
+ );
58
+ assert.strictEqual(actual, true);
59
+ assert.deepStrictEqual(signals, ['a', 'b', 'c']);
60
+ });
61
+
62
+ it('should reject when one of the promises rejects', async () => {
63
+ await assert.rejects(firstTrue(
64
+ new Promise<boolean>(resolve => setTimeout(() => resolve(false), 10)),
65
+ new Promise<boolean>(resolve => setTimeout(() => resolve(false), 20)),
66
+ new Promise<boolean>((_, reject) => setTimeout(() => reject(new Error('my test error')), 30)),
67
+ new Promise<boolean>(resolve => setTimeout(() => resolve(true), 40)),
68
+ ), /Error: my test error/);
69
+ });
70
+ });
71
+
41
72
  });
@@ -129,3 +129,15 @@ export function waitForEvent<T>(event: Event<T>, ms: number, thisArg?: any, disp
129
129
  export function isThenable<T>(obj: unknown): obj is Promise<T> {
130
130
  return isObject<Promise<unknown>>(obj) && isFunction(obj.then);
131
131
  }
132
+
133
+ /**
134
+ * Returns with a promise that waits until the first promise resolves to `true`.
135
+ */
136
+ // Based on https://stackoverflow.com/a/51160727/5529090
137
+ export function firstTrue(...promises: readonly Promise<boolean>[]): Promise<boolean> {
138
+ const newPromises = promises.map(promise => new Promise<boolean>(
139
+ (resolve, reject) => promise.then(result => result && resolve(true), reject)
140
+ ));
141
+ newPromises.push(Promise.all(promises).then(() => false));
142
+ return Promise.race(newPromises);
143
+ }
@@ -54,6 +54,7 @@ export interface QuickPickItem {
54
54
  description?: string;
55
55
  detail?: string;
56
56
  keySequence?: KeySequence;
57
+ iconPath?: URI | Uri | { light?: URI | Uri; dark: URI | Uri } | { id: string };
57
58
  iconClasses?: string[];
58
59
  alwaysShow?: boolean;
59
60
  highlights?: QuickPickItemHighlights;
@@ -56,6 +56,23 @@ export function isFunction<T extends (...args: unknown[]) => unknown>(value: unk
56
56
  return typeof value === 'function';
57
57
  }
58
58
 
59
+ /**
60
+ * @returns whether the provided parameter is an empty JavaScript Object or not.
61
+ */
62
+ export function isEmptyObject(obj: unknown): obj is object {
63
+ if (!isObject(obj)) {
64
+ return false;
65
+ }
66
+
67
+ for (const key in obj) {
68
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
69
+ return false;
70
+ }
71
+ }
72
+
73
+ return true;
74
+ }
75
+
59
76
  export function isObject<T extends object>(value: unknown): value is UnknownObject<T> {
60
77
  // eslint-disable-next-line no-null/no-null
61
78
  return typeof value === 'object' && value !== null;
package/src/common/uri.ts CHANGED
@@ -27,6 +27,10 @@ export class URI {
27
27
  return new URI(Uri.file(path));
28
28
  }
29
29
 
30
+ public static isUri(uri: unknown): boolean {
31
+ return Uri.isUri(uri);
32
+ }
33
+
30
34
  private readonly codeUri: Uri;
31
35
  private _path: Path | undefined;
32
36
 
@@ -100,8 +100,8 @@ export class ElectronContextMenuRenderer extends BrowserContextMenuRenderer {
100
100
 
101
101
  protected override doRender(options: RenderContextMenuOptions): ContextMenuAccess {
102
102
  if (this.useNativeStyle) {
103
- const { menuPath, anchor, args, onHide, context, contextKeyService } = options;
104
- const menu = this.electronMenuFactory.createElectronContextMenu(menuPath, args, context, contextKeyService);
103
+ const { menuPath, anchor, args, onHide, context, contextKeyService, skipSingleRootNode } = options;
104
+ const menu = this.electronMenuFactory.createElectronContextMenu(menuPath, args, context, contextKeyService, skipSingleRootNode);
105
105
  const { x, y } = coordinateFromAnchor(anchor);
106
106
 
107
107
  const menuHandle = window.electronTheiaCore.popup(menu, x, y, () => {
@@ -125,8 +125,8 @@ export class ElectronMainMenuFactory extends BrowserMainMenuFactory {
125
125
  return undefined;
126
126
  }
127
127
 
128
- createElectronContextMenu(menuPath: MenuPath, args?: any[], context?: HTMLElement, contextKeyService?: ContextMatcher): MenuDto[] {
129
- const menuModel = this.menuProvider.getMenu(menuPath);
128
+ createElectronContextMenu(menuPath: MenuPath, args?: any[], context?: HTMLElement, contextKeyService?: ContextMatcher, skipSingleRootNode?: boolean): MenuDto[] {
129
+ const menuModel = skipSingleRootNode ? this.menuProvider.removeSingleRootNode(this.menuProvider.getMenu(menuPath), menuPath) : this.menuProvider.getMenu(menuPath);
130
130
  return this.fillMenuTemplate([], menuModel, args, { showDisabled: true, context, rootMenuPath: menuPath, contextKeyService });
131
131
  }
132
132
 
@@ -30,6 +30,8 @@ import { WindowTitleService } from '../../browser/window/window-title-service';
30
30
 
31
31
  import '../../../src/electron-browser/menu/electron-menu-style.css';
32
32
  import { MenuDto } from '../../electron-common/electron-api';
33
+ import { ThemeService } from '../../browser/theming';
34
+ import { ThemeChangeEvent } from '../../common/theme';
33
35
 
34
36
  export namespace ElectronCommands {
35
37
  export const TOGGLE_DEVELOPER_TOOLS = Command.toDefaultLocalizedCommand({
@@ -88,6 +90,9 @@ export class ElectronMenuContribution extends BrowserMenuBarContribution impleme
88
90
  @inject(WindowService)
89
91
  protected readonly windowService: WindowService;
90
92
 
93
+ @inject(ThemeService)
94
+ protected readonly themeService: ThemeService;
95
+
91
96
  @inject(CustomTitleWidgetFactory)
92
97
  protected readonly customTitleWidgetFactory: CustomTitleWidgetFactory;
93
98
 
@@ -123,6 +128,9 @@ export class ElectronMenuContribution extends BrowserMenuBarContribution impleme
123
128
  this.handleToggleMaximized();
124
129
  });
125
130
  this.attachMenuBarVisibilityListener();
131
+ this.themeService.onDidColorThemeChange(e => {
132
+ this.handleThemeChange(e);
133
+ });
126
134
  }
127
135
 
128
136
  protected attachWindowFocusListener(app: FrontendApplication): void {
@@ -414,6 +422,11 @@ export class ElectronMenuContribution extends BrowserMenuBarContribution impleme
414
422
  }
415
423
  }
416
424
 
425
+ protected handleThemeChange(e: ThemeChangeEvent): void {
426
+ const backgroundColor = window.getComputedStyle(document.body).backgroundColor;
427
+ window.electronTheiaCore.setBackgroundColor(backgroundColor);
428
+ }
429
+
417
430
  }
418
431
 
419
432
  @injectable()
@@ -25,7 +25,7 @@ import {
25
25
  CHANNEL_ON_WINDOW_EVENT, CHANNEL_GET_ZOOM_LEVEL, CHANNEL_SET_ZOOM_LEVEL, CHANNEL_IS_FULL_SCREENABLE, CHANNEL_TOGGLE_FULL_SCREEN,
26
26
  CHANNEL_IS_FULL_SCREEN, CHANNEL_SET_MENU_BAR_VISIBLE, CHANNEL_REQUEST_CLOSE, CHANNEL_SET_TITLE_STYLE, CHANNEL_RESTART,
27
27
  CHANNEL_REQUEST_RELOAD, CHANNEL_APP_STATE_CHANGED, CHANNEL_SHOW_ITEM_IN_FOLDER, CHANNEL_READ_CLIPBOARD, CHANNEL_WRITE_CLIPBOARD,
28
- CHANNEL_KEYBOARD_LAYOUT_CHANGED, CHANNEL_IPC_CONNECTION, InternalMenuDto, CHANNEL_REQUEST_SECONDARY_CLOSE
28
+ CHANNEL_KEYBOARD_LAYOUT_CHANGED, CHANNEL_IPC_CONNECTION, InternalMenuDto, CHANNEL_REQUEST_SECONDARY_CLOSE, CHANNEL_SET_BACKGROUND_COLOR
29
29
  } from '../electron-common/electron-api';
30
30
 
31
31
  // eslint-disable-next-line import/no-extraneous-dependencies
@@ -101,6 +101,9 @@ const api: TheiaCoreAPI = {
101
101
  setTitleBarStyle: function (style): void {
102
102
  ipcRenderer.send(CHANNEL_SET_TITLE_STYLE, style);
103
103
  },
104
+ setBackgroundColor: function (backgroundColor): void {
105
+ ipcRenderer.send(CHANNEL_SET_BACKGROUND_COLOR, backgroundColor);
106
+ },
104
107
  minimize: function (): void {
105
108
  ipcRenderer.send(CHANNEL_MINIMIZE);
106
109
  },
@@ -56,6 +56,7 @@ export interface TheiaCoreAPI {
56
56
 
57
57
  getTitleBarStyleAtStartup(): Promise<string>;
58
58
  setTitleBarStyle(style: string): void;
59
+ setBackgroundColor(backgroundColor: string): void;
59
60
  minimize(): void;
60
61
  isMaximized(): boolean; // TODO: this should really be async, since it blocks the renderer process
61
62
  maximize(): void;
@@ -109,6 +110,7 @@ export const CHANNEL_ATTACH_SECURITY_TOKEN = 'AttachSecurityToken';
109
110
 
110
111
  export const CHANNEL_GET_TITLE_STYLE_AT_STARTUP = 'GetTitleStyleAtStartup';
111
112
  export const CHANNEL_SET_TITLE_STYLE = 'SetTitleStyle';
113
+ export const CHANNEL_SET_BACKGROUND_COLOR = 'SetBackgroundColor';
112
114
  export const CHANNEL_CLOSE = 'Close';
113
115
  export const CHANNEL_MINIMIZE = 'Minimize';
114
116
  export const CHANNEL_MAXIMIZE = 'Maximize';
@@ -50,7 +50,8 @@ import {
50
50
  CHANNEL_SET_MENU_BAR_VISIBLE,
51
51
  CHANNEL_TOGGLE_FULL_SCREEN,
52
52
  CHANNEL_IS_MAXIMIZED,
53
- CHANNEL_REQUEST_SECONDARY_CLOSE
53
+ CHANNEL_REQUEST_SECONDARY_CLOSE,
54
+ CHANNEL_SET_BACKGROUND_COLOR
54
55
  } from '../electron-common/electron-api';
55
56
  import { ElectronMainApplication, ElectronMainApplicationContribution } from './electron-main-application';
56
57
  import { Disposable, DisposableCollection, isOSX, MaybePromise } from '../common';
@@ -152,6 +153,8 @@ export class TheiaMainApi implements ElectronMainApplicationContribution {
152
153
 
153
154
  ipcMain.on(CHANNEL_SET_TITLE_STYLE, (event, style) => application.setTitleBarStyle(event.sender, style));
154
155
 
156
+ ipcMain.on(CHANNEL_SET_BACKGROUND_COLOR, (event, backgroundColor) => application.setBackgroundColor(event.sender, backgroundColor));
157
+
155
158
  ipcMain.on(CHANNEL_MINIMIZE, event => {
156
159
  BrowserWindow.fromWebContents(event.sender)?.minimize();
157
160
  });