@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.
- package/README.md +12 -8
- package/i18n/nls.cs.json +4 -0
- package/i18n/nls.de.json +4 -0
- package/i18n/nls.es.json +4 -0
- package/i18n/nls.fr.json +4 -0
- package/i18n/nls.hu.json +4 -0
- package/i18n/nls.it.json +4 -0
- package/i18n/nls.ja.json +4 -0
- package/i18n/nls.json +4 -0
- package/i18n/nls.pl.json +4 -0
- package/i18n/nls.pt-br.json +4 -0
- package/i18n/nls.pt-pt.json +4 -0
- package/i18n/nls.ru.json +4 -0
- package/i18n/nls.zh-cn.json +4 -0
- package/lib/browser/browser.d.ts +2 -0
- package/lib/browser/browser.d.ts.map +1 -1
- package/lib/browser/browser.js +6 -1
- package/lib/browser/browser.js.map +1 -1
- package/lib/browser/common-frontend-contribution.d.ts +4 -0
- package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
- package/lib/browser/common-frontend-contribution.js +98 -3
- package/lib/browser/common-frontend-contribution.js.map +1 -1
- package/lib/browser/frontend-application-module.d.ts.map +1 -1
- package/lib/browser/frontend-application-module.js +5 -0
- package/lib/browser/frontend-application-module.js.map +1 -1
- package/lib/browser/index.d.ts +1 -0
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +1 -0
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/saveable-service.d.ts.map +1 -1
- package/lib/browser/saveable-service.js +6 -2
- package/lib/browser/saveable-service.js.map +1 -1
- package/lib/browser/saveable.d.ts +16 -1
- package/lib/browser/saveable.d.ts.map +1 -1
- package/lib/browser/saveable.js +59 -1
- package/lib/browser/saveable.js.map +1 -1
- package/lib/browser/shell/application-shell.d.ts.map +1 -1
- package/lib/browser/shell/application-shell.js +5 -1
- package/lib/browser/shell/application-shell.js.map +1 -1
- package/lib/browser/shell/split-panels.d.ts +1 -1
- package/lib/browser/shell/split-panels.d.ts.map +1 -1
- package/lib/browser/shell/split-panels.js +4 -3
- package/lib/browser/shell/split-panels.js.map +1 -1
- package/lib/browser/shell/tab-bars.js +1 -1
- package/lib/browser/shell/tab-bars.js.map +1 -1
- package/lib/browser/undo-redo-handler.d.ts +22 -0
- package/lib/browser/undo-redo-handler.d.ts.map +1 -0
- package/lib/browser/undo-redo-handler.js +83 -0
- package/lib/browser/undo-redo-handler.js.map +1 -0
- package/lib/browser/widget-manager.d.ts +2 -1
- package/lib/browser/widget-manager.d.ts.map +1 -1
- package/lib/browser/widget-manager.js +16 -9
- package/lib/browser/widget-manager.js.map +1 -1
- package/lib/browser/widget-open-handler.d.ts +4 -1
- package/lib/browser/widget-open-handler.d.ts.map +1 -1
- package/lib/browser/widget-open-handler.js +1 -1
- package/lib/browser/widget-open-handler.js.map +1 -1
- package/lib/browser/widgets/index.d.ts +1 -0
- package/lib/browser/widgets/index.d.ts.map +1 -1
- package/lib/browser/widgets/index.js +1 -0
- package/lib/browser/widgets/index.js.map +1 -1
- package/lib/browser/widgets/split-widget.d.ts +45 -0
- package/lib/browser/widgets/split-widget.d.ts.map +1 -0
- package/lib/browser/widgets/split-widget.js +126 -0
- package/lib/browser/widgets/split-widget.js.map +1 -0
- package/lib/common/event.d.ts +2 -0
- package/lib/common/event.d.ts.map +1 -1
- package/lib/common/event.js +4 -0
- package/lib/common/event.js.map +1 -1
- package/lib/common/json-schema.d.ts +2 -0
- package/lib/common/json-schema.d.ts.map +1 -1
- package/lib/common/preferences/preference-schema.d.ts +5 -0
- package/lib/common/preferences/preference-schema.d.ts.map +1 -1
- package/lib/common/preferences/preference-schema.js.map +1 -1
- package/lib/common/quick-pick-service.d.ts +0 -9
- package/lib/common/quick-pick-service.d.ts.map +1 -1
- package/lib/common/quick-pick-service.js.map +1 -1
- package/lib/electron-browser/preload.js +1 -1
- package/lib/electron-browser/preload.js.map +1 -1
- package/lib/electron-browser/window/electron-window-service.js +1 -1
- package/lib/electron-browser/window/electron-window-service.js.map +1 -1
- package/lib/electron-common/electron-api.d.ts +1 -1
- package/lib/electron-common/electron-api.d.ts.map +1 -1
- package/lib/electron-main/electron-main-application.d.ts.map +1 -1
- package/lib/electron-main/electron-main-application.js +4 -0
- package/lib/electron-main/electron-main-application.js.map +1 -1
- package/lib/electron-main/theia-electron-window.d.ts +1 -1
- package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
- package/lib/electron-main/theia-electron-window.js +8 -3
- package/lib/electron-main/theia-electron-window.js.map +1 -1
- package/lib/node/messaging/websocket-frontend-connection-service.d.ts +1 -0
- package/lib/node/messaging/websocket-frontend-connection-service.d.ts.map +1 -1
- package/lib/node/messaging/websocket-frontend-connection-service.js +8 -1
- package/lib/node/messaging/websocket-frontend-connection-service.js.map +1 -1
- package/package.json +7 -7
- package/src/browser/browser.ts +10 -1
- package/src/browser/common-frontend-contribution.ts +112 -3
- package/src/browser/frontend-application-module.ts +6 -0
- package/src/browser/index.ts +1 -0
- package/src/browser/saveable-service.ts +6 -2
- package/src/browser/saveable.ts +65 -1
- package/src/browser/shell/application-shell.ts +5 -1
- package/src/browser/shell/split-panels.ts +4 -3
- package/src/browser/shell/tab-bars.ts +1 -1
- package/src/browser/style/index.css +3 -1
- package/src/browser/style/split-widget.css +38 -0
- package/src/browser/style/tabs.css +11 -0
- package/src/browser/undo-redo-handler.ts +85 -0
- package/src/browser/widget-manager.ts +19 -11
- package/src/browser/widget-open-handler.ts +7 -4
- package/src/browser/widgets/index.ts +1 -0
- package/src/browser/widgets/split-widget.ts +163 -0
- package/src/common/event.ts +6 -0
- package/src/common/json-schema.ts +2 -0
- package/src/common/preferences/preference-schema.ts +5 -0
- package/src/common/quick-pick-service.ts +0 -3
- package/src/electron-browser/preload.ts +1 -1
- package/src/electron-browser/window/electron-window-service.ts +1 -1
- package/src/electron-common/electron-api.ts +1 -1
- package/src/electron-main/electron-main-application.ts +8 -2
- package/src/electron-main/theia-electron-window.ts +7 -3
- 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
|
-
|
|
94
|
+
setTimeout(this.animationFrame.bind(this), 10);
|
|
95
95
|
}
|
|
96
96
|
this.splitMoves.push(move);
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
protected animationFrame(
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
210
|
+
for (const [key, widgetPromise] of this.pendingWidgetPromises.entries()) {
|
|
211
211
|
if (this.testPredicate(key, factoryId, predicate)) {
|
|
212
|
-
return
|
|
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
|
-
|
|
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
|
|
256
|
-
}
|
|
257
|
-
|
|
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
|
|
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
|
|
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
|
|
154
|
+
return this.widgetManager.getOrCreateWidget(this.id, widgetOptions);
|
|
152
155
|
}
|
|
153
156
|
|
|
154
157
|
protected abstract createWidgetOptions(uri: URI, options?: WidgetOpenerOptions): Object;
|
|
@@ -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
|
+
}
|
package/src/common/event.ts
CHANGED
|
@@ -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.
|
|
@@ -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
|
-
|
|
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 {
|
|
19
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|