@theia/core 1.51.0 → 1.53.0-next.18

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 (122) hide show
  1. package/README.md +12 -8
  2. package/i18n/nls.cs.json +4 -0
  3. package/i18n/nls.de.json +4 -0
  4. package/i18n/nls.es.json +4 -0
  5. package/i18n/nls.fr.json +4 -0
  6. package/i18n/nls.hu.json +4 -0
  7. package/i18n/nls.it.json +4 -0
  8. package/i18n/nls.ja.json +4 -0
  9. package/i18n/nls.json +4 -0
  10. package/i18n/nls.pl.json +4 -0
  11. package/i18n/nls.pt-br.json +4 -0
  12. package/i18n/nls.pt-pt.json +4 -0
  13. package/i18n/nls.ru.json +4 -0
  14. package/i18n/nls.zh-cn.json +4 -0
  15. package/lib/browser/browser.d.ts +2 -0
  16. package/lib/browser/browser.d.ts.map +1 -1
  17. package/lib/browser/browser.js +6 -1
  18. package/lib/browser/browser.js.map +1 -1
  19. package/lib/browser/common-frontend-contribution.d.ts +4 -0
  20. package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
  21. package/lib/browser/common-frontend-contribution.js +98 -3
  22. package/lib/browser/common-frontend-contribution.js.map +1 -1
  23. package/lib/browser/frontend-application-module.d.ts.map +1 -1
  24. package/lib/browser/frontend-application-module.js +5 -0
  25. package/lib/browser/frontend-application-module.js.map +1 -1
  26. package/lib/browser/index.d.ts +1 -0
  27. package/lib/browser/index.d.ts.map +1 -1
  28. package/lib/browser/index.js +1 -0
  29. package/lib/browser/index.js.map +1 -1
  30. package/lib/browser/saveable-service.d.ts.map +1 -1
  31. package/lib/browser/saveable-service.js +6 -2
  32. package/lib/browser/saveable-service.js.map +1 -1
  33. package/lib/browser/saveable.d.ts +16 -1
  34. package/lib/browser/saveable.d.ts.map +1 -1
  35. package/lib/browser/saveable.js +59 -1
  36. package/lib/browser/saveable.js.map +1 -1
  37. package/lib/browser/shell/application-shell.d.ts.map +1 -1
  38. package/lib/browser/shell/application-shell.js +5 -1
  39. package/lib/browser/shell/application-shell.js.map +1 -1
  40. package/lib/browser/shell/split-panels.d.ts +1 -1
  41. package/lib/browser/shell/split-panels.d.ts.map +1 -1
  42. package/lib/browser/shell/split-panels.js +4 -3
  43. package/lib/browser/shell/split-panels.js.map +1 -1
  44. package/lib/browser/shell/tab-bars.js +1 -1
  45. package/lib/browser/shell/tab-bars.js.map +1 -1
  46. package/lib/browser/undo-redo-handler.d.ts +22 -0
  47. package/lib/browser/undo-redo-handler.d.ts.map +1 -0
  48. package/lib/browser/undo-redo-handler.js +83 -0
  49. package/lib/browser/undo-redo-handler.js.map +1 -0
  50. package/lib/browser/widget-manager.d.ts +2 -1
  51. package/lib/browser/widget-manager.d.ts.map +1 -1
  52. package/lib/browser/widget-manager.js +16 -9
  53. package/lib/browser/widget-manager.js.map +1 -1
  54. package/lib/browser/widget-open-handler.d.ts +4 -1
  55. package/lib/browser/widget-open-handler.d.ts.map +1 -1
  56. package/lib/browser/widget-open-handler.js +1 -1
  57. package/lib/browser/widget-open-handler.js.map +1 -1
  58. package/lib/browser/widgets/index.d.ts +1 -0
  59. package/lib/browser/widgets/index.d.ts.map +1 -1
  60. package/lib/browser/widgets/index.js +1 -0
  61. package/lib/browser/widgets/index.js.map +1 -1
  62. package/lib/browser/widgets/split-widget.d.ts +45 -0
  63. package/lib/browser/widgets/split-widget.d.ts.map +1 -0
  64. package/lib/browser/widgets/split-widget.js +126 -0
  65. package/lib/browser/widgets/split-widget.js.map +1 -0
  66. package/lib/common/event.d.ts +2 -0
  67. package/lib/common/event.d.ts.map +1 -1
  68. package/lib/common/event.js +4 -0
  69. package/lib/common/event.js.map +1 -1
  70. package/lib/common/json-schema.d.ts +2 -0
  71. package/lib/common/json-schema.d.ts.map +1 -1
  72. package/lib/common/preferences/preference-schema.d.ts +5 -0
  73. package/lib/common/preferences/preference-schema.d.ts.map +1 -1
  74. package/lib/common/preferences/preference-schema.js.map +1 -1
  75. package/lib/common/quick-pick-service.d.ts +0 -9
  76. package/lib/common/quick-pick-service.d.ts.map +1 -1
  77. package/lib/common/quick-pick-service.js.map +1 -1
  78. package/lib/electron-browser/preload.js +1 -1
  79. package/lib/electron-browser/preload.js.map +1 -1
  80. package/lib/electron-browser/window/electron-window-service.js +1 -1
  81. package/lib/electron-browser/window/electron-window-service.js.map +1 -1
  82. package/lib/electron-common/electron-api.d.ts +1 -1
  83. package/lib/electron-common/electron-api.d.ts.map +1 -1
  84. package/lib/electron-main/electron-main-application.d.ts.map +1 -1
  85. package/lib/electron-main/electron-main-application.js +4 -0
  86. package/lib/electron-main/electron-main-application.js.map +1 -1
  87. package/lib/electron-main/theia-electron-window.d.ts +1 -1
  88. package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
  89. package/lib/electron-main/theia-electron-window.js +8 -3
  90. package/lib/electron-main/theia-electron-window.js.map +1 -1
  91. package/lib/node/messaging/websocket-frontend-connection-service.d.ts +1 -0
  92. package/lib/node/messaging/websocket-frontend-connection-service.d.ts.map +1 -1
  93. package/lib/node/messaging/websocket-frontend-connection-service.js +8 -1
  94. package/lib/node/messaging/websocket-frontend-connection-service.js.map +1 -1
  95. package/package.json +7 -7
  96. package/src/browser/browser.ts +10 -1
  97. package/src/browser/common-frontend-contribution.ts +112 -3
  98. package/src/browser/frontend-application-module.ts +6 -0
  99. package/src/browser/index.ts +1 -0
  100. package/src/browser/saveable-service.ts +6 -2
  101. package/src/browser/saveable.ts +65 -1
  102. package/src/browser/shell/application-shell.ts +5 -1
  103. package/src/browser/shell/split-panels.ts +4 -3
  104. package/src/browser/shell/tab-bars.ts +1 -1
  105. package/src/browser/style/index.css +3 -1
  106. package/src/browser/style/split-widget.css +38 -0
  107. package/src/browser/style/tabs.css +11 -0
  108. package/src/browser/undo-redo-handler.ts +85 -0
  109. package/src/browser/widget-manager.ts +19 -11
  110. package/src/browser/widget-open-handler.ts +7 -4
  111. package/src/browser/widgets/index.ts +1 -0
  112. package/src/browser/widgets/split-widget.ts +163 -0
  113. package/src/common/event.ts +6 -0
  114. package/src/common/json-schema.ts +2 -0
  115. package/src/common/preferences/preference-schema.ts +5 -0
  116. package/src/common/quick-pick-service.ts +0 -3
  117. package/src/electron-browser/preload.ts +1 -1
  118. package/src/electron-browser/window/electron-window-service.ts +1 -1
  119. package/src/electron-common/electron-api.ts +1 -1
  120. package/src/electron-main/electron-main-application.ts +8 -2
  121. package/src/electron-main/theia-electron-window.ts +7 -3
  122. package/src/node/messaging/websocket-frontend-connection-service.ts +11 -1
@@ -91,13 +91,14 @@ export class SplitPositionHandler {
91
91
  move.resolve = resolve;
92
92
  move.reject = reject;
93
93
  if (this.splitMoves.length === 0) {
94
- window.requestAnimationFrame(this.animationFrame.bind(this));
94
+ setTimeout(this.animationFrame.bind(this), 10);
95
95
  }
96
96
  this.splitMoves.push(move);
97
97
  });
98
98
  }
99
99
 
100
- protected animationFrame(time: number): void {
100
+ protected animationFrame(): void {
101
+ const time = Date.now();
101
102
  const move = this.splitMoves[this.currentMoveIndex];
102
103
  let rejectedOrResolved = false;
103
104
  if (move.ended || move.referenceWidget && move.referenceWidget.isHidden) {
@@ -133,7 +134,7 @@ export class SplitPositionHandler {
133
134
  this.currentMoveIndex = 0;
134
135
  }
135
136
  if (this.splitMoves.length > 0) {
136
- window.requestAnimationFrame(this.animationFrame.bind(this));
137
+ setTimeout(this.animationFrame.bind(this));
137
138
  }
138
139
  }
139
140
 
@@ -619,7 +619,7 @@ export class TabBarRenderer extends TabBar.Renderer {
619
619
  cssClasses: ['extended-tab-preview'],
620
620
  visualPreview: this.corePreferences?.['window.tabbar.enhancedPreview'] === 'visual' ? width => this.renderVisualPreview(width, title) : undefined
621
621
  });
622
- } else {
622
+ } else if (title.caption) {
623
623
  this.hoverService.requestHover({
624
624
  content: title.caption,
625
625
  target: event.currentTarget,
@@ -239,7 +239,8 @@ blockquote {
239
239
  -o-user-select: none;
240
240
  }
241
241
 
242
- :focus {
242
+ /* Since an iframe has its own focus tracking, we don't show focus on iframes */
243
+ :focus:not(iframe) {
243
244
  outline-width: 1px;
244
245
  outline-style: solid;
245
246
  outline-offset: -1px;
@@ -349,3 +350,4 @@ button.secondary[disabled],
349
350
  @import "./progress-bar.css";
350
351
  @import "./breadcrumbs.css";
351
352
  @import "./tooltip.css";
353
+ @import "./split-widget.css";
@@ -0,0 +1,38 @@
1
+ /********************************************************************************
2
+ * Copyright (C) 2024 1C-Soft LLC 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
+ .theia-split-widget > .p-SplitPanel {
18
+ height: 100%;
19
+ width: 100%;
20
+ outline: none;
21
+ }
22
+
23
+ .theia-split-widget > .p-SplitPanel > .p-SplitPanel-child {
24
+ min-width: 50px;
25
+ min-height: var(--theia-content-line-height);
26
+ }
27
+
28
+ .theia-split-widget > .p-SplitPanel > .p-SplitPanel-handle {
29
+ box-sizing: border-box;
30
+ }
31
+
32
+ .theia-split-widget > .p-SplitPanel[data-orientation="horizontal"] > .p-SplitPanel-handle {
33
+ border-left: var(--theia-border-width) solid var(--theia-sideBarSectionHeader-border);
34
+ }
35
+
36
+ .theia-split-widget > .p-SplitPanel[data-orientation="vertical"] > .p-SplitPanel-handle {
37
+ border-top: var(--theia-border-width) solid var(--theia-sideBarSectionHeader-border);
38
+ }
@@ -177,6 +177,17 @@
177
177
  padding-right: 8px;
178
178
  }
179
179
 
180
+ .p-TabBar.theia-app-centers .p-TabBar-tabIcon[class*="plugin-icon-"],
181
+ .p-TabBar-tab.p-mod-drag-image .p-TabBar-tabIcon[class*="plugin-icon-"] {
182
+ background: none;
183
+ height: var(--theia-icon-size);
184
+ }
185
+
186
+ .p-TabBar.theia-app-centers .p-TabBar-tabIcon[class*="plugin-icon-"]::before,
187
+ .p-TabBar-tab.p-mod-drag-image .p-TabBar-tabIcon[class*="plugin-icon-"]::before {
188
+ display: inline-block;
189
+ }
190
+
180
191
  /* codicons */
181
192
  .p-TabBar.theia-app-centers .p-TabBar-tabIcon.codicon,
182
193
  .p-TabBar-tab.p-mod-drag-image .p-TabBar-tabIcon.codicon {
@@ -0,0 +1,85 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 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 { inject, injectable, named, postConstruct } from 'inversify';
18
+ import { ContributionProvider } from '../common';
19
+
20
+ export const UndoRedoHandler = Symbol('UndoRedoHandler');
21
+
22
+ export interface UndoRedoHandler<T> {
23
+ priority: number;
24
+ select(): T | undefined;
25
+ undo(item: T): void;
26
+ redo(item: T): void;
27
+ }
28
+
29
+ @injectable()
30
+ export class UndoRedoHandlerService {
31
+
32
+ @inject(ContributionProvider) @named(UndoRedoHandler)
33
+ protected readonly provider: ContributionProvider<UndoRedoHandler<unknown>>;
34
+
35
+ protected handlers: UndoRedoHandler<unknown>[];
36
+
37
+ @postConstruct()
38
+ protected init(): void {
39
+ this.handlers = this.provider.getContributions().sort((a, b) => b.priority - a.priority);
40
+ }
41
+
42
+ undo(): void {
43
+ for (const handler of this.handlers) {
44
+ const selection = handler.select();
45
+ if (selection) {
46
+ handler.undo(selection);
47
+ return;
48
+ }
49
+ }
50
+ }
51
+
52
+ redo(): void {
53
+ for (const handler of this.handlers) {
54
+ const selection = handler.select();
55
+ if (selection) {
56
+ handler.redo(selection);
57
+ return;
58
+ }
59
+ }
60
+ }
61
+
62
+ }
63
+
64
+ @injectable()
65
+ export class DomInputUndoRedoHandler implements UndoRedoHandler<Element> {
66
+
67
+ priority = 1000;
68
+
69
+ select(): Element | undefined {
70
+ const element = document.activeElement;
71
+ if (element && ['input', 'textarea'].includes(element.tagName.toLowerCase())) {
72
+ return element;
73
+ }
74
+ return undefined;
75
+ }
76
+
77
+ undo(item: Element): void {
78
+ document.execCommand('undo');
79
+ }
80
+
81
+ redo(item: Element): void {
82
+ document.execCommand('redo');
83
+ }
84
+
85
+ }
@@ -114,7 +114,7 @@ export class WidgetManager {
114
114
 
115
115
  protected _cachedFactories: Map<string, WidgetFactory>;
116
116
  protected readonly widgets = new Map<string, Widget>();
117
- protected readonly pendingWidgetPromises = new Map<string, MaybePromise<Widget>>();
117
+ protected readonly pendingWidgetPromises = new Map<string, Promise<Widget>>();
118
118
 
119
119
  @inject(ContributionProvider) @named(WidgetFactory)
120
120
  protected readonly factoryProvider: ContributionProvider<WidgetFactory>;
@@ -207,9 +207,9 @@ export class WidgetManager {
207
207
  return widget as T;
208
208
  }
209
209
  }
210
- for (const [key, widget] of this.pendingWidgetPromises.entries()) {
210
+ for (const [key, widgetPromise] of this.pendingWidgetPromises.entries()) {
211
211
  if (this.testPredicate(key, factoryId, predicate)) {
212
- return widget as T;
212
+ return widgetPromise as Promise<T>;
213
213
  }
214
214
  }
215
215
  }
@@ -244,18 +244,26 @@ export class WidgetManager {
244
244
  if (!factory) {
245
245
  throw Error("No widget factory '" + factoryId + "' has been registered.");
246
246
  }
247
- try {
248
- const widgetPromise = factory.createWidget(options);
249
- this.pendingWidgetPromises.set(key, widgetPromise);
250
- const widget = await widgetPromise;
251
- await WaitUntilEvent.fire(this.onWillCreateWidgetEmitter, { factoryId, widget });
247
+ const widgetPromise = this.doCreateWidget<T>(factory, options).then(widget => {
252
248
  this.widgets.set(key, widget);
253
249
  widget.disposed.connect(() => this.widgets.delete(key));
254
250
  this.onDidCreateWidgetEmitter.fire({ factoryId, widget });
255
- return widget as T;
256
- } finally {
257
- this.pendingWidgetPromises.delete(key);
251
+ return widget;
252
+ }).finally(() => this.pendingWidgetPromises.delete(key));
253
+ this.pendingWidgetPromises.set(key, widgetPromise);
254
+ return widgetPromise;
255
+ }
256
+
257
+ protected async doCreateWidget<T extends Widget>(factory: WidgetFactory, options?: any): Promise<T> {
258
+ const widget = await factory.createWidget(options);
259
+ // Note: the widget creation process also includes the 'onWillCreateWidget' part, which can potentially fail
260
+ try {
261
+ await WaitUntilEvent.fire(this.onWillCreateWidgetEmitter, { factoryId: factory.id, widget });
262
+ } catch (e) {
263
+ widget.dispose();
264
+ throw e;
258
265
  }
266
+ return widget as T;
259
267
  }
260
268
 
261
269
  /**
@@ -24,7 +24,10 @@ import { WidgetManager } from './widget-manager';
24
24
 
25
25
  export type WidgetOpenMode = 'open' | 'reveal' | 'activate';
26
26
  /**
27
- * `WidgetOpenerOptions` define serializable generic options used by the {@link WidgetOpenHandler}.
27
+ * `WidgetOpenerOptions` define generic options used by the {@link WidgetOpenHandler}.
28
+ *
29
+ * _Note:_ This object may contain references to widgets (e.g. `widgetOptions.ref`);
30
+ * these need to be transformed before it can be serialized.
28
31
  */
29
32
  export interface WidgetOpenerOptions extends OpenerOptions {
30
33
  /**
@@ -96,7 +99,7 @@ export abstract class WidgetOpenHandler<W extends BaseWidget> implements OpenHan
96
99
  ...options
97
100
  };
98
101
  if (!widget.isAttached) {
99
- this.shell.addWidget(widget, op.widgetOptions || { area: 'main' });
102
+ await this.shell.addWidget(widget, op.widgetOptions || { area: 'main' });
100
103
  }
101
104
  if (op.mode === 'activate') {
102
105
  await this.shell.activateWidget(widget.id);
@@ -143,12 +146,12 @@ export abstract class WidgetOpenHandler<W extends BaseWidget> implements OpenHan
143
146
 
144
147
  protected getWidget(uri: URI, options?: WidgetOpenerOptions): Promise<W | undefined> {
145
148
  const widgetOptions = this.createWidgetOptions(uri, options);
146
- return this.widgetManager.getWidget<W>(this.id, widgetOptions);
149
+ return this.widgetManager.getWidget(this.id, widgetOptions);
147
150
  }
148
151
 
149
152
  protected getOrCreateWidget(uri: URI, options?: WidgetOpenerOptions): Promise<W> {
150
153
  const widgetOptions = this.createWidgetOptions(uri, options);
151
- return this.widgetManager.getOrCreateWidget<W>(this.id, widgetOptions);
154
+ return this.widgetManager.getOrCreateWidget(this.id, widgetOptions);
152
155
  }
153
156
 
154
157
  protected abstract createWidgetOptions(uri: URI, options?: WidgetOpenerOptions): Object;
@@ -18,3 +18,4 @@ export * from './widget';
18
18
  export * from './react-renderer';
19
19
  export * from './react-widget';
20
20
  export * from './extractable-widget';
21
+ export * from './split-widget';
@@ -0,0 +1,163 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 1C-Soft LLC 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 { Emitter } from 'vscode-languageserver-protocol';
18
+ import { ApplicationShell, StatefulWidget } from '../shell';
19
+ import { BaseWidget, Message, PanelLayout, SplitPanel, Widget } from './widget';
20
+ import { CompositeSaveable, Saveable, SaveableSource } from '../saveable';
21
+ import { Navigatable } from '../navigatable-types';
22
+ import { URI } from '../../common';
23
+
24
+ /**
25
+ * A widget containing a number of panes in a split layout.
26
+ */
27
+ export class SplitWidget extends BaseWidget implements ApplicationShell.TrackableWidgetProvider, SaveableSource, Navigatable, StatefulWidget {
28
+
29
+ protected readonly splitPanel: SplitPanel;
30
+
31
+ protected readonly onDidChangeTrackableWidgetsEmitter = new Emitter<Widget[]>();
32
+ readonly onDidChangeTrackableWidgets = this.onDidChangeTrackableWidgetsEmitter.event;
33
+
34
+ protected readonly compositeSaveable = new CompositeSaveable();
35
+
36
+ protected navigatable?: Navigatable;
37
+
38
+ constructor(options?: SplitPanel.IOptions & { navigatable?: Navigatable }) {
39
+ super();
40
+
41
+ this.toDispose.pushAll([this.onDidChangeTrackableWidgetsEmitter]);
42
+
43
+ this.addClass('theia-split-widget');
44
+
45
+ const layout = new PanelLayout();
46
+ this.layout = layout;
47
+ const that = this;
48
+ this.splitPanel = new class extends SplitPanel {
49
+
50
+ protected override onChildAdded(msg: Widget.ChildMessage): void {
51
+ super.onChildAdded(msg);
52
+ that.onPaneAdded(msg.child);
53
+ }
54
+
55
+ protected override onChildRemoved(msg: Widget.ChildMessage): void {
56
+ super.onChildRemoved(msg);
57
+ that.onPaneRemoved(msg.child);
58
+ }
59
+ }({
60
+ spacing: 1, // --theia-border-width
61
+ ...options
62
+ });
63
+ this.splitPanel.node.tabIndex = -1;
64
+ layout.addWidget(this.splitPanel);
65
+
66
+ this.navigatable = options?.navigatable;
67
+ }
68
+
69
+ get orientation(): SplitPanel.Orientation {
70
+ return this.splitPanel.orientation;
71
+ }
72
+
73
+ set orientation(value: SplitPanel.Orientation) {
74
+ this.splitPanel.orientation = value;
75
+ }
76
+
77
+ relativeSizes(): number[] {
78
+ return this.splitPanel.relativeSizes();
79
+ }
80
+
81
+ setRelativeSizes(sizes: number[]): void {
82
+ this.splitPanel.setRelativeSizes(sizes);
83
+ }
84
+
85
+ get handles(): readonly HTMLDivElement[] {
86
+ return this.splitPanel.handles;
87
+ }
88
+
89
+ get saveable(): Saveable {
90
+ return this.compositeSaveable;
91
+ }
92
+
93
+ getResourceUri(): URI | undefined {
94
+ return this.navigatable?.getResourceUri();
95
+ }
96
+
97
+ createMoveToUri(resourceUri: URI): URI | undefined {
98
+ return this.navigatable?.createMoveToUri(resourceUri);
99
+ }
100
+
101
+ storeState(): SplitWidget.State {
102
+ return { orientation: this.orientation, widgets: this.panes, relativeSizes: this.relativeSizes() };
103
+ }
104
+
105
+ restoreState(oldState: SplitWidget.State): void {
106
+ const { orientation, widgets, relativeSizes } = oldState;
107
+ if (orientation) {
108
+ this.orientation = orientation;
109
+ }
110
+ for (const widget of widgets) {
111
+ this.addPane(widget);
112
+ }
113
+ if (relativeSizes) {
114
+ this.setRelativeSizes(relativeSizes);
115
+ }
116
+ }
117
+
118
+ get panes(): readonly Widget[] {
119
+ return this.splitPanel.widgets;
120
+ }
121
+
122
+ getTrackableWidgets(): Widget[] {
123
+ return [...this.panes];
124
+ }
125
+
126
+ protected fireDidChangeTrackableWidgets(): void {
127
+ this.onDidChangeTrackableWidgetsEmitter.fire(this.getTrackableWidgets());
128
+ }
129
+
130
+ addPane(pane: Widget): void {
131
+ this.splitPanel.addWidget(pane);
132
+ }
133
+
134
+ insertPane(index: number, pane: Widget): void {
135
+ this.splitPanel.insertWidget(index, pane);
136
+ }
137
+
138
+ protected onPaneAdded(pane: Widget): void {
139
+ if (Saveable.isSource(pane)) {
140
+ this.compositeSaveable.add(pane.saveable);
141
+ }
142
+ this.fireDidChangeTrackableWidgets();
143
+ }
144
+
145
+ protected onPaneRemoved(pane: Widget): void {
146
+ if (Saveable.isSource(pane)) {
147
+ this.compositeSaveable.remove(pane.saveable);
148
+ }
149
+ this.fireDidChangeTrackableWidgets();
150
+ }
151
+
152
+ protected override onActivateRequest(msg: Message): void {
153
+ this.splitPanel.node.focus();
154
+ }
155
+ }
156
+
157
+ export namespace SplitWidget {
158
+ export interface State {
159
+ orientation?: SplitPanel.Orientation;
160
+ widgets: readonly Widget[]; // note: don't rename this property; it has special meaning for `ShellLayoutRestorer`
161
+ relativeSizes?: number[];
162
+ }
163
+ }
@@ -89,6 +89,12 @@ export namespace Event {
89
89
  return new Promise(resolve => once(event)(resolve));
90
90
  }
91
91
 
92
+ export function filter<T>(event: Event<T>, predicate: (e: T) => unknown): Event<T>;
93
+ export function filter<T, S extends T>(event: Event<T>, predicate: (e: T) => e is S): Event<S>;
94
+ export function filter<T>(event: Event<T>, predicate: (e: T) => unknown): Event<T> {
95
+ return (listener, thisArg, disposables) => event(e => predicate(e) && listener.call(thisArg, e), undefined, disposables);
96
+ }
97
+
92
98
  /**
93
99
  * Given an event and a `map` function, returns another event which maps each element
94
100
  * through the mapping function.
@@ -36,6 +36,8 @@ export interface IJSONSchema {
36
36
  $id?: string;
37
37
  $schema?: string;
38
38
  type?: JsonType | JsonType[];
39
+ owner?: string;
40
+ group?: string;
39
41
  title?: string;
40
42
  default?: JSONValue;
41
43
  definitions?: IJSONSchemaMap;
@@ -25,6 +25,11 @@ export interface PreferenceSchema {
25
25
  [name: string]: any,
26
26
  scope?: 'application' | 'window' | 'resource' | PreferenceScope,
27
27
  overridable?: boolean;
28
+ /**
29
+ * The title of the preference schema.
30
+ * It is used in the preference UI to associate a localized group of preferences.
31
+ */
32
+ title?: string;
28
33
  properties: PreferenceSchemaProperties
29
34
  }
30
35
  export namespace PreferenceSchema {
@@ -18,7 +18,6 @@ import * as fuzzy from 'fuzzy';
18
18
  import { Event } from './event';
19
19
  import { KeySequence } from './keys';
20
20
  import { CancellationToken } from './cancellation';
21
- import { URI as Uri } from 'vscode-uri';
22
21
 
23
22
  export const quickPickServicePath = '/services/quickPick';
24
23
  export const QuickPickService = Symbol('QuickPickService');
@@ -53,7 +52,6 @@ export interface QuickPickItem {
53
52
  description?: string;
54
53
  detail?: string;
55
54
  keySequence?: KeySequence;
56
- iconPath?: { light?: Uri; dark: Uri };
57
55
  iconClasses?: string[];
58
56
  alwaysShow?: boolean;
59
57
  highlights?: QuickPickItemHighlights;
@@ -94,7 +92,6 @@ export interface QuickPickValue<V> extends QuickPickItem {
94
92
  }
95
93
 
96
94
  export interface QuickInputButton {
97
- iconPath?: { light?: Uri; dark: Uri };
98
95
  iconClass?: string;
99
96
  tooltip?: string;
100
97
  /**
@@ -199,7 +199,7 @@ const api: TheiaCoreAPI = {
199
199
  ipcRenderer.send(CHANNEL_TOGGLE_FULL_SCREEN);
200
200
  },
201
201
 
202
- requestReload: () => ipcRenderer.send(CHANNEL_REQUEST_RELOAD),
202
+ requestReload: (newUrl?: string) => ipcRenderer.send(CHANNEL_REQUEST_RELOAD, newUrl),
203
203
  restart: () => ipcRenderer.send(CHANNEL_RESTART),
204
204
 
205
205
  applicationStateChanged: state => {
@@ -100,7 +100,7 @@ export class ElectronWindowService extends DefaultWindowService {
100
100
  if (params.hash) {
101
101
  newLocation.hash = '#' + params.hash;
102
102
  }
103
- location.assign(newLocation);
103
+ window.electronTheiaCore.requestReload(newLocation.toString());
104
104
  } else {
105
105
  window.electronTheiaCore.requestReload();
106
106
  }
@@ -84,7 +84,7 @@ export interface TheiaCoreAPI {
84
84
  isFullScreen(): boolean; // TODO: this should really be async, since it blocks the renderer process
85
85
  toggleFullScreen(): void;
86
86
 
87
- requestReload(): void;
87
+ requestReload(newUrl?: string): void;
88
88
  restart(): void;
89
89
 
90
90
  applicationStateChanged(state: FrontendApplicationState): void;
@@ -15,8 +15,10 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { inject, injectable, named } from 'inversify';
18
- import { screen, app, BrowserWindow, WebContents, Event as ElectronEvent, BrowserWindowConstructorOptions, nativeImage,
19
- nativeTheme, shell, dialog } from '../../electron-shared/electron';
18
+ import {
19
+ screen, app, BrowserWindow, WebContents, Event as ElectronEvent, BrowserWindowConstructorOptions, nativeImage,
20
+ nativeTheme, shell, dialog
21
+ } from '../../electron-shared/electron';
20
22
  import * as path from 'path';
21
23
  import { Argv } from 'yargs';
22
24
  import { AddressInfo } from 'net';
@@ -350,6 +352,9 @@ export class ElectronMainApplication {
350
352
  alwaysOnTop: true,
351
353
  show: false,
352
354
  transparent: true,
355
+ webPreferences: {
356
+ backgroundThrottling: false
357
+ }
353
358
  });
354
359
 
355
360
  if (this.isShowWindowEarly()) {
@@ -458,6 +463,7 @@ export class ElectronMainApplication {
458
463
  // Setting the following option to `true` causes some features to break, somehow.
459
464
  // Issue: https://github.com/eclipse-theia/theia/issues/8577
460
465
  nodeIntegrationInWorker: false,
466
+ backgroundThrottling: false,
461
467
  preload: path.resolve(this.globals.THEIA_APP_PROJECT_PATH, 'lib', 'frontend', 'preload.js').toString()
462
468
  },
463
469
  ...this.config.electron?.windowOptions || {},
@@ -147,10 +147,14 @@ export class TheiaElectronWindow {
147
147
  return this.handleStopRequest(() => this.doCloseWindow(), reason);
148
148
  }
149
149
 
150
- protected reload(): void {
150
+ protected reload(newUrl?: string): void {
151
151
  this.handleStopRequest(async () => {
152
152
  this.applicationState = 'init';
153
- this._window.reload();
153
+ if (newUrl) {
154
+ this._window.loadURL(newUrl);
155
+ } else {
156
+ this._window.reload();
157
+ }
154
158
  }, StopReason.Reload);
155
159
  }
156
160
 
@@ -195,7 +199,7 @@ export class TheiaElectronWindow {
195
199
  }
196
200
 
197
201
  protected attachReloadListener(): void {
198
- this.toDispose.push(TheiaRendererAPI.onRequestReload(this.window.webContents, () => this.reload()));
202
+ this.toDispose.push(TheiaRendererAPI.onRequestReload(this.window.webContents, (newUrl?: string) => this.reload(newUrl)));
199
203
  }
200
204
 
201
205
  dispose(): void {
@@ -105,7 +105,8 @@ export class WebsocketFrontendConnectionService implements FrontendConnectionSer
105
105
  socket.on('disconnect', evt => {
106
106
  console.info('socked closed');
107
107
  channel.disconnect();
108
- const timeout = BackendApplicationConfigProvider.get().frontendConnectionTimeout;
108
+
109
+ const timeout = this.frontendConnectionTimeout();
109
110
  const isMarkedForClose = this.channelsMarkedForClose.delete(frontEndId);
110
111
  if (timeout === 0 || isMarkedForClose) {
111
112
  this.closeConnection(frontEndId, evt);
@@ -124,6 +125,15 @@ export class WebsocketFrontendConnectionService implements FrontendConnectionSer
124
125
  markForClose(channelId: string): void {
125
126
  this.channelsMarkedForClose.add(channelId);
126
127
  }
128
+
129
+ private frontendConnectionTimeout(): number {
130
+ const envValue = Number(process.env['FRONTEND_CONNECTION_TIMEOUT']);
131
+ if (!isNaN(envValue)) {
132
+ return envValue;
133
+ }
134
+
135
+ return BackendApplicationConfigProvider.get().frontendConnectionTimeout;
136
+ }
127
137
  }
128
138
 
129
139
  class ReconnectableSocketChannel extends AbstractChannel {