@theia/core 1.50.1 → 1.52.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.
- package/README.md +11 -7
- package/i18n/nls.cs.json +4 -7
- package/i18n/nls.de.json +4 -7
- package/i18n/nls.es.json +4 -7
- package/i18n/nls.fr.json +4 -7
- package/i18n/nls.hu.json +4 -7
- package/i18n/nls.it.json +4 -7
- package/i18n/nls.ja.json +4 -7
- package/i18n/nls.json +4 -7
- package/i18n/nls.pl.json +4 -7
- package/i18n/nls.pt-br.json +4 -7
- package/i18n/nls.pt-pt.json +4 -7
- package/i18n/nls.ru.json +4 -7
- package/i18n/nls.zh-cn.json +4 -7
- package/lib/browser/authentication-service.d.ts +6 -3
- package/lib/browser/authentication-service.d.ts.map +1 -1
- package/lib/browser/authentication-service.js +11 -1
- package/lib/browser/authentication-service.js.map +1 -1
- package/lib/browser/browser.d.ts +6 -1
- package/lib/browser/browser.d.ts.map +1 -1
- package/lib/browser/browser.js +7 -2
- package/lib/browser/browser.js.map +1 -1
- package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
- package/lib/browser/common-frontend-contribution.js +6 -5
- 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 +3 -3
- package/lib/browser/frontend-application-module.js.map +1 -1
- package/lib/browser/http-open-handler.d.ts +1 -0
- package/lib/browser/http-open-handler.d.ts.map +1 -1
- package/lib/browser/http-open-handler.js +5 -3
- package/lib/browser/http-open-handler.js.map +1 -1
- package/lib/browser/menu/browser-menu-plugin.d.ts +2 -1
- package/lib/browser/menu/browser-menu-plugin.d.ts.map +1 -1
- package/lib/browser/menu/browser-menu-plugin.js +22 -19
- package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
- package/lib/browser/messaging/service-connection-provider.d.ts +15 -1
- package/lib/browser/messaging/service-connection-provider.d.ts.map +1 -1
- package/lib/browser/messaging/service-connection-provider.js +15 -1
- package/lib/browser/messaging/service-connection-provider.js.map +1 -1
- package/lib/browser/saveable.d.ts +14 -1
- package/lib/browser/saveable.d.ts.map +1 -1
- package/lib/browser/saveable.js +10 -1
- package/lib/browser/saveable.js.map +1 -1
- package/lib/browser/shell/additional-views-menu-widget.d.ts +2 -2
- package/lib/browser/shell/additional-views-menu-widget.d.ts.map +1 -1
- package/lib/browser/shell/additional-views-menu-widget.js +8 -4
- package/lib/browser/shell/additional-views-menu-widget.js.map +1 -1
- package/lib/browser/shell/application-shell.d.ts +7 -2
- package/lib/browser/shell/application-shell.d.ts.map +1 -1
- package/lib/browser/shell/application-shell.js +14 -1
- package/lib/browser/shell/application-shell.js.map +1 -1
- package/lib/browser/shell/side-panel-handler.d.ts.map +1 -1
- package/lib/browser/shell/side-panel-handler.js +2 -1
- package/lib/browser/shell/side-panel-handler.js.map +1 -1
- package/lib/browser/shell/sidebar-menu-widget.d.ts +14 -1
- package/lib/browser/shell/sidebar-menu-widget.d.ts.map +1 -1
- package/lib/browser/shell/sidebar-menu-widget.js +51 -13
- package/lib/browser/shell/sidebar-menu-widget.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.d.ts +5 -4
- package/lib/browser/shell/tab-bars.d.ts.map +1 -1
- package/lib/browser/shell/tab-bars.js +41 -52
- package/lib/browser/shell/tab-bars.js.map +1 -1
- package/lib/browser/shell/theia-dock-panel.d.ts +7 -1
- package/lib/browser/shell/theia-dock-panel.d.ts.map +1 -1
- package/lib/browser/shell/theia-dock-panel.js +5 -1
- package/lib/browser/shell/theia-dock-panel.js.map +1 -1
- 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.js +1 -1
- package/lib/browser/widget-open-handler.js.map +1 -1
- package/lib/browser/widgets/react-renderer.d.ts.map +1 -1
- package/lib/browser/widgets/react-renderer.js +4 -1
- package/lib/browser/widgets/react-renderer.js.map +1 -1
- package/lib/browser-only/frontend-only-application-module.d.ts.map +1 -1
- package/lib/browser-only/frontend-only-application-module.js +1 -0
- package/lib/browser-only/frontend-only-application-module.js.map +1 -1
- package/lib/common/application-protocol.d.ts +1 -0
- package/lib/common/application-protocol.d.ts.map +1 -1
- package/lib/common/menu/menu-model-registry.d.ts +6 -0
- package/lib/common/menu/menu-model-registry.d.ts.map +1 -1
- package/lib/common/menu/menu-model-registry.js +31 -5
- package/lib/common/menu/menu-model-registry.js.map +1 -1
- package/lib/common/preferences/preference-schema.d.ts +6 -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/menu/electron-main-menu-factory.d.ts.map +1 -1
- package/lib/electron-browser/menu/electron-main-menu-factory.js +3 -0
- package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
- package/lib/electron-browser/preload.js +3 -3
- package/lib/electron-browser/preload.js.map +1 -1
- package/lib/electron-browser/window/electron-window-module.d.ts.map +1 -1
- package/lib/electron-browser/window/electron-window-module.js +11 -7
- package/lib/electron-browser/window/electron-window-module.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-browser/window/external-app-open-handler.d.ts +12 -0
- package/lib/electron-browser/window/external-app-open-handler.d.ts.map +1 -0
- package/lib/electron-browser/window/external-app-open-handler.js +42 -0
- package/lib/electron-browser/window/external-app-open-handler.js.map +1 -0
- package/lib/electron-common/electron-api.d.ts +5 -2
- package/lib/electron-common/electron-api.d.ts.map +1 -1
- package/lib/electron-common/electron-api.js.map +1 -1
- package/lib/electron-main/electron-main-application.d.ts +1 -2
- package/lib/electron-main/electron-main-application.d.ts.map +1 -1
- package/lib/electron-main/electron-main-application.js +66 -32
- package/lib/electron-main/electron-main-application.js.map +1 -1
- package/lib/electron-main/electron-main-constants.d.ts +1 -0
- package/lib/electron-main/electron-main-constants.d.ts.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/application-server.d.ts +1 -0
- package/lib/node/application-server.d.ts.map +1 -1
- package/lib/node/application-server.js +3 -0
- package/lib/node/application-server.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/authentication-service.ts +16 -4
- package/src/browser/browser.ts +6 -1
- package/src/browser/common-frontend-contribution.ts +9 -7
- package/src/browser/frontend-application-module.ts +6 -5
- package/src/browser/http-open-handler.ts +3 -1
- package/src/browser/menu/browser-menu-plugin.ts +27 -20
- package/src/browser/messaging/service-connection-provider.ts +15 -1
- package/src/browser/saveable.ts +17 -1
- package/src/browser/shell/additional-views-menu-widget.tsx +5 -5
- package/src/browser/shell/application-shell.ts +21 -4
- package/src/browser/shell/side-panel-handler.ts +2 -1
- package/src/browser/shell/sidebar-menu-widget.tsx +63 -20
- package/src/browser/shell/split-panels.ts +4 -3
- package/src/browser/shell/tab-bars.ts +40 -57
- package/src/browser/shell/theia-dock-panel.ts +13 -3
- package/src/browser/style/sidepanel.css +6 -3
- package/src/browser/style/tabs.css +12 -1
- package/src/browser/widget-manager.ts +19 -11
- package/src/browser/widget-open-handler.ts +3 -3
- package/src/browser/widgets/react-renderer.tsx +4 -1
- package/src/browser-only/frontend-only-application-module.ts +1 -0
- package/src/common/application-protocol.ts +1 -0
- package/src/common/menu/menu-model-registry.ts +36 -5
- package/src/common/preferences/preference-schema.ts +6 -0
- package/src/common/quick-pick-service.ts +0 -3
- package/src/electron-browser/menu/electron-main-menu-factory.ts +3 -0
- package/src/electron-browser/preload.ts +3 -3
- package/src/electron-browser/window/electron-window-module.ts +11 -7
- package/src/electron-browser/window/electron-window-service.ts +1 -1
- package/src/electron-browser/window/external-app-open-handler.ts +42 -0
- package/src/electron-common/electron-api.ts +6 -2
- package/src/electron-main/electron-main-application.ts +76 -35
- package/src/electron-main/electron-main-constants.ts +4 -3
- package/src/electron-main/theia-electron-window.ts +7 -3
- package/src/node/application-server.ts +4 -0
- package/src/node/messaging/websocket-frontend-connection-service.ts +11 -1
|
@@ -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,
|
|
@@ -1084,8 +1084,6 @@ export class SideTabBar extends ScrollableTabBar {
|
|
|
1084
1084
|
startIndex: number
|
|
1085
1085
|
};
|
|
1086
1086
|
|
|
1087
|
-
protected _rowGap: number;
|
|
1088
|
-
|
|
1089
1087
|
constructor(options?: TabBar.IOptions<Widget> & PerfectScrollbar.Options) {
|
|
1090
1088
|
super(options);
|
|
1091
1089
|
|
|
@@ -1142,31 +1140,6 @@ export class SideTabBar extends ScrollableTabBar {
|
|
|
1142
1140
|
}
|
|
1143
1141
|
}
|
|
1144
1142
|
|
|
1145
|
-
// Queries the tabRowGap value of the content node. Needed to properly compute overflowing
|
|
1146
|
-
// tabs that should be hidden
|
|
1147
|
-
protected get tabRowGap(): number {
|
|
1148
|
-
// We assume that the tab row gap is static i.e. we compute it once an then cache it
|
|
1149
|
-
if (!this._rowGap) {
|
|
1150
|
-
this._rowGap = this.computeTabRowGap();
|
|
1151
|
-
}
|
|
1152
|
-
return this._rowGap;
|
|
1153
|
-
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
protected computeTabRowGap(): number {
|
|
1157
|
-
const style = window.getComputedStyle(this.contentNode);
|
|
1158
|
-
const rowGapStyle = style.getPropertyValue('row-gap');
|
|
1159
|
-
const numericValue = parseFloat(rowGapStyle);
|
|
1160
|
-
const unit = rowGapStyle.match(/[a-zA-Z]+/)?.[0];
|
|
1161
|
-
|
|
1162
|
-
const tempDiv = document.createElement('div');
|
|
1163
|
-
tempDiv.style.height = '1' + unit;
|
|
1164
|
-
document.body.appendChild(tempDiv);
|
|
1165
|
-
const rowGapValue = numericValue * tempDiv.offsetHeight;
|
|
1166
|
-
document.body.removeChild(tempDiv);
|
|
1167
|
-
return rowGapValue;
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
1143
|
/**
|
|
1171
1144
|
* Reveal the tab with the given index by moving it into the non-overflowing tabBar section
|
|
1172
1145
|
* if necessary.
|
|
@@ -1207,18 +1180,13 @@ export class SideTabBar extends ScrollableTabBar {
|
|
|
1207
1180
|
const hiddenContent = this.hiddenContentNode;
|
|
1208
1181
|
const n = hiddenContent.children.length;
|
|
1209
1182
|
const renderData = new Array<Partial<SideBarRenderData>>(n);
|
|
1210
|
-
const availableWidth = this.node.clientHeight - this.tabRowGap;
|
|
1211
|
-
let actualWidth = 0;
|
|
1212
|
-
let overflowStartIndex = -1;
|
|
1213
1183
|
for (let i = 0; i < n; i++) {
|
|
1214
1184
|
const hiddenTab = hiddenContent.children[i];
|
|
1215
|
-
// Extract tab padding from the computed style
|
|
1185
|
+
// Extract tab padding, and margin from the computed style
|
|
1216
1186
|
const tabStyle = window.getComputedStyle(hiddenTab);
|
|
1217
|
-
const paddingTop = parseFloat(tabStyle.paddingTop!);
|
|
1218
|
-
const paddingBottom = parseFloat(tabStyle.paddingBottom!);
|
|
1219
1187
|
const rd: Partial<SideBarRenderData> = {
|
|
1220
|
-
paddingTop,
|
|
1221
|
-
paddingBottom
|
|
1188
|
+
paddingTop: parseFloat(tabStyle.paddingTop!),
|
|
1189
|
+
paddingBottom: parseFloat(tabStyle.paddingBottom!)
|
|
1222
1190
|
};
|
|
1223
1191
|
// Extract label size from the DOM
|
|
1224
1192
|
const labelElements = hiddenTab.getElementsByClassName('p-TabBar-tabLabel');
|
|
@@ -1231,38 +1199,21 @@ export class SideTabBar extends ScrollableTabBar {
|
|
|
1231
1199
|
if (iconElements.length === 1) {
|
|
1232
1200
|
const icon = iconElements[0];
|
|
1233
1201
|
rd.iconSize = { width: icon.clientWidth, height: icon.clientHeight };
|
|
1234
|
-
actualWidth += icon.clientHeight + paddingTop + paddingBottom + this.tabRowGap;
|
|
1235
|
-
|
|
1236
|
-
if (actualWidth > availableWidth && i !== 0) {
|
|
1237
|
-
rd.visible = false;
|
|
1238
|
-
if (overflowStartIndex === -1) {
|
|
1239
|
-
overflowStartIndex = i;
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
renderData[i] = rd;
|
|
1243
1202
|
}
|
|
1244
|
-
}
|
|
1245
1203
|
|
|
1246
|
-
|
|
1247
|
-
if (overflowStartIndex === n - 1 && renderData[overflowStartIndex]) {
|
|
1248
|
-
if (!this.tabsOverflowData) {
|
|
1249
|
-
overflowStartIndex--;
|
|
1250
|
-
renderData[overflowStartIndex].visible = false;
|
|
1251
|
-
} else {
|
|
1252
|
-
renderData[overflowStartIndex].visible = true;
|
|
1253
|
-
overflowStartIndex = -1;
|
|
1254
|
-
}
|
|
1204
|
+
renderData[i] = rd;
|
|
1255
1205
|
}
|
|
1256
1206
|
// Render into the visible node
|
|
1257
1207
|
this.renderTabs(this.contentNode, renderData);
|
|
1258
|
-
this.computeOverflowingTabsData(
|
|
1208
|
+
this.computeOverflowingTabsData();
|
|
1259
1209
|
});
|
|
1260
1210
|
}
|
|
1261
1211
|
}
|
|
1262
1212
|
|
|
1263
|
-
protected computeOverflowingTabsData(
|
|
1213
|
+
protected computeOverflowingTabsData(): void {
|
|
1264
1214
|
// ensure that render tabs has completed
|
|
1265
1215
|
window.requestAnimationFrame(() => {
|
|
1216
|
+
const startIndex = this.hideOverflowingTabs();
|
|
1266
1217
|
if (startIndex === -1) {
|
|
1267
1218
|
if (this.tabsOverflowData) {
|
|
1268
1219
|
this.tabsOverflowData = undefined;
|
|
@@ -1286,6 +1237,38 @@ export class SideTabBar extends ScrollableTabBar {
|
|
|
1286
1237
|
});
|
|
1287
1238
|
}
|
|
1288
1239
|
|
|
1240
|
+
/**
|
|
1241
|
+
* Hide overflowing tabs and return the index of the first hidden tab.
|
|
1242
|
+
*/
|
|
1243
|
+
protected hideOverflowingTabs(): number {
|
|
1244
|
+
const availableHeight = this.node.clientHeight;
|
|
1245
|
+
const invisibleClass = 'p-mod-invisible';
|
|
1246
|
+
let startIndex = -1;
|
|
1247
|
+
const n = this.contentNode.children.length;
|
|
1248
|
+
for (let i = 0; i < n; i++) {
|
|
1249
|
+
const tab = this.contentNode.children[i] as HTMLLIElement;
|
|
1250
|
+
if (tab.offsetTop + tab.offsetHeight >= availableHeight) {
|
|
1251
|
+
tab.classList.add(invisibleClass);
|
|
1252
|
+
if (startIndex === -1) {
|
|
1253
|
+
startIndex = i;
|
|
1254
|
+
/* If only one element is overflowing and the additional menu widget is visible (i.e. this.tabsOverflowData is set)
|
|
1255
|
+
* there might already be enough space to show the last tab. In this case, we need to include the size of the
|
|
1256
|
+
* additional menu widget and recheck if the last tab is visible */
|
|
1257
|
+
if (startIndex === n - 1 && this.tabsOverflowData) {
|
|
1258
|
+
const additionalViewsMenu = this.node.parentElement?.querySelector('.theia-additional-views-menu') as HTMLDivElement;
|
|
1259
|
+
if (tab.offsetTop + tab.offsetHeight < availableHeight + additionalViewsMenu.offsetHeight) {
|
|
1260
|
+
tab.classList.remove(invisibleClass);
|
|
1261
|
+
startIndex = -1;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
} else {
|
|
1266
|
+
tab.classList.remove(invisibleClass);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
return startIndex;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1289
1272
|
/**
|
|
1290
1273
|
* Render the tab bar using the given DOM element as host. The optional `renderData` is forwarded
|
|
1291
1274
|
* to the TabBarRenderer.
|
|
@@ -14,7 +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 { find, toArray
|
|
17
|
+
import { find, toArray } from '@phosphor/algorithm';
|
|
18
18
|
import { TabBar, Widget, DockPanel, Title, DockLayout } from '@phosphor/widgets';
|
|
19
19
|
import { Signal } from '@phosphor/signaling';
|
|
20
20
|
import { Disposable, DisposableCollection } from '../../common/disposable';
|
|
@@ -103,7 +103,7 @@ export class TheiaDockPanel extends DockPanel {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
findTabBar(title: Title<Widget>): TabBar<Widget> | undefined {
|
|
106
|
-
return find(this.tabBars(), bar =>
|
|
106
|
+
return find(this.tabBars(), bar => bar.titles.includes(title));
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
protected readonly toDisposeOnMarkAsCurrent = new DisposableCollection();
|
|
@@ -133,11 +133,14 @@ export class TheiaDockPanel extends DockPanel {
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
override addWidget(widget: Widget, options?:
|
|
136
|
+
override addWidget(widget: Widget, options?: TheiaDockPanel.AddOptions): void {
|
|
137
137
|
if (this.mode === 'single-document' && widget.parent === this) {
|
|
138
138
|
return;
|
|
139
139
|
}
|
|
140
140
|
super.addWidget(widget, options);
|
|
141
|
+
if (options?.closeRef) {
|
|
142
|
+
options.ref?.close();
|
|
143
|
+
}
|
|
141
144
|
this.widgetAdded.emit(widget);
|
|
142
145
|
this.markActiveTabBar(widget.title);
|
|
143
146
|
}
|
|
@@ -252,4 +255,11 @@ export namespace TheiaDockPanel {
|
|
|
252
255
|
export interface Factory {
|
|
253
256
|
(options?: DockPanel.IOptions): TheiaDockPanel;
|
|
254
257
|
}
|
|
258
|
+
|
|
259
|
+
export interface AddOptions extends DockPanel.IAddOptions {
|
|
260
|
+
/**
|
|
261
|
+
* Whether to also close the widget referenced by `ref`.
|
|
262
|
+
*/
|
|
263
|
+
closeRef?: boolean
|
|
264
|
+
}
|
|
255
265
|
}
|
|
@@ -186,23 +186,26 @@
|
|
|
186
186
|
flex-direction: column-reverse;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
.p-Widget .theia-sidebar-menu-item {
|
|
190
|
+
cursor: pointer;
|
|
191
|
+
}
|
|
192
|
+
|
|
189
193
|
.p-Widget.theia-sidebar-menu i {
|
|
190
194
|
padding: var(--theia-private-sidebar-tab-padding-top-and-bottom)
|
|
191
195
|
var(--theia-private-sidebar-tab-padding-left-and-right);
|
|
192
196
|
display: flex;
|
|
193
197
|
justify-content: center;
|
|
194
198
|
align-items: center;
|
|
195
|
-
cursor: pointer;
|
|
196
199
|
color: var(--theia-activityBar-inactiveForeground);
|
|
197
200
|
background-color: var(--theia-activityBar-background);
|
|
198
201
|
font-size: var(--theia-private-sidebar-icon-size);
|
|
199
202
|
}
|
|
200
203
|
|
|
201
|
-
.theia-sidebar-menu
|
|
204
|
+
.theia-sidebar-menu .theia-sidebar-menu-item:hover i {
|
|
202
205
|
color: var(--theia-activityBar-foreground);
|
|
203
206
|
}
|
|
204
207
|
|
|
205
|
-
.theia-sidebar-menu
|
|
208
|
+
.theia-sidebar-menu i.theia-compact-menu {
|
|
206
209
|
font-size: 16px;
|
|
207
210
|
}
|
|
208
211
|
|
|
@@ -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 {
|
|
@@ -305,7 +316,7 @@
|
|
|
305
316
|
display: none !important;
|
|
306
317
|
}
|
|
307
318
|
|
|
308
|
-
.
|
|
319
|
+
.theia-badge-decorator-sidebar {
|
|
309
320
|
background-color: var(--theia-activityBarBadge-background);
|
|
310
321
|
border-radius: 20px;
|
|
311
322
|
color: var(--theia-activityBarBadge-foreground);
|
|
@@ -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
|
/**
|
|
@@ -96,7 +96,7 @@ export abstract class WidgetOpenHandler<W extends BaseWidget> implements OpenHan
|
|
|
96
96
|
...options
|
|
97
97
|
};
|
|
98
98
|
if (!widget.isAttached) {
|
|
99
|
-
this.shell.addWidget(widget, op.widgetOptions || { area: 'main' });
|
|
99
|
+
await this.shell.addWidget(widget, op.widgetOptions || { area: 'main' });
|
|
100
100
|
}
|
|
101
101
|
if (op.mode === 'activate') {
|
|
102
102
|
await this.shell.activateWidget(widget.id);
|
|
@@ -143,12 +143,12 @@ export abstract class WidgetOpenHandler<W extends BaseWidget> implements OpenHan
|
|
|
143
143
|
|
|
144
144
|
protected getWidget(uri: URI, options?: WidgetOpenerOptions): Promise<W | undefined> {
|
|
145
145
|
const widgetOptions = this.createWidgetOptions(uri, options);
|
|
146
|
-
return this.widgetManager.getWidget
|
|
146
|
+
return this.widgetManager.getWidget(this.id, widgetOptions);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
protected getOrCreateWidget(uri: URI, options?: WidgetOpenerOptions): Promise<W> {
|
|
150
150
|
const widgetOptions = this.createWidgetOptions(uri, options);
|
|
151
|
-
return this.widgetManager.getOrCreateWidget
|
|
151
|
+
return this.widgetManager.getOrCreateWidget(this.id, widgetOptions);
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
protected abstract createWidgetOptions(uri: URI, options?: WidgetOpenerOptions): Object;
|
|
@@ -41,7 +41,10 @@ export class ReactRenderer implements Disposable {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
render(): void {
|
|
44
|
-
|
|
44
|
+
// Ignore all render calls after the host element has unmounted
|
|
45
|
+
if (!this.toDispose.disposed) {
|
|
46
|
+
this.hostRoot.render(<React.Fragment>{this.doRender()}</React.Fragment>);
|
|
47
|
+
}
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
protected doRender(): React.ReactNode {
|
|
@@ -56,6 +56,7 @@ export const frontendOnlyApplicationModule = new ContainerModule((bind, unbind,
|
|
|
56
56
|
getExtensionsInfos: async (): Promise<ExtensionInfo[]> => [],
|
|
57
57
|
getApplicationInfo: async (): Promise<ApplicationInfo | undefined> => undefined,
|
|
58
58
|
getApplicationRoot: async (): Promise<string> => '',
|
|
59
|
+
getApplicationPlatform: () => Promise.resolve('web'),
|
|
59
60
|
getBackendOS: async (): Promise<OS.Type> => OS.Type.Linux
|
|
60
61
|
};
|
|
61
62
|
if (isBound(ApplicationServer)) {
|
|
@@ -24,6 +24,7 @@ export interface ApplicationServer {
|
|
|
24
24
|
getExtensionsInfos(): Promise<ExtensionInfo[]>;
|
|
25
25
|
getApplicationInfo(): Promise<ApplicationInfo | undefined>;
|
|
26
26
|
getApplicationRoot(): Promise<string>;
|
|
27
|
+
getApplicationPlatform(): Promise<string>;
|
|
27
28
|
/**
|
|
28
29
|
* @deprecated since 1.25.0. Use `OS.backend.type()` instead.
|
|
29
30
|
*/
|
|
@@ -18,6 +18,7 @@ import { inject, injectable, named } from 'inversify';
|
|
|
18
18
|
import { Command, CommandRegistry } from '../command';
|
|
19
19
|
import { ContributionProvider } from '../contribution-provider';
|
|
20
20
|
import { Disposable } from '../disposable';
|
|
21
|
+
import { Emitter, Event } from '../event';
|
|
21
22
|
import { ActionMenuNode } from './action-menu-node';
|
|
22
23
|
import { CompositeMenuNode, CompositeMenuNodeWrapper } from './composite-menu-node';
|
|
23
24
|
import { CompoundMenuNode, MenuAction, MenuNode, MenuNodeMetadata, MenuPath, MutableCompoundMenuNode, SubMenuOptions } from './menu-types';
|
|
@@ -68,6 +69,14 @@ export class MenuModelRegistry {
|
|
|
68
69
|
protected readonly root = new CompositeMenuNode('');
|
|
69
70
|
protected readonly independentSubmenus = new Map<string, MutableCompoundMenuNode>();
|
|
70
71
|
|
|
72
|
+
protected readonly onDidChangeEmitter = new Emitter<void>();
|
|
73
|
+
|
|
74
|
+
get onDidChange(): Event<void> {
|
|
75
|
+
return this.onDidChangeEmitter.event;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
protected isReady = false;
|
|
79
|
+
|
|
71
80
|
constructor(
|
|
72
81
|
@inject(ContributionProvider) @named(MenuContribution)
|
|
73
82
|
protected readonly contributions: ContributionProvider<MenuContribution>,
|
|
@@ -78,6 +87,7 @@ export class MenuModelRegistry {
|
|
|
78
87
|
for (const contrib of this.contributions.getContributions()) {
|
|
79
88
|
contrib.registerMenus(this);
|
|
80
89
|
}
|
|
90
|
+
this.isReady = true;
|
|
81
91
|
}
|
|
82
92
|
|
|
83
93
|
/**
|
|
@@ -97,7 +107,9 @@ export class MenuModelRegistry {
|
|
|
97
107
|
*/
|
|
98
108
|
registerMenuNode(menuPath: MenuPath | string, menuNode: MenuNode, group?: string): Disposable {
|
|
99
109
|
const parent = this.getMenuNode(menuPath, group);
|
|
100
|
-
|
|
110
|
+
const disposable = parent.addNode(menuNode);
|
|
111
|
+
this.fireChangeEvent();
|
|
112
|
+
return this.changeEventOnDispose(disposable);
|
|
101
113
|
}
|
|
102
114
|
|
|
103
115
|
getMenuNode(menuPath: MenuPath | string, group?: string): MutableCompoundMenuNode {
|
|
@@ -137,13 +149,15 @@ export class MenuModelRegistry {
|
|
|
137
149
|
const groupPath = index === 0 ? [] : menuPath.slice(0, index);
|
|
138
150
|
const parent = this.findGroup(groupPath, options);
|
|
139
151
|
let groupNode = this.findSubMenu(parent, menuId, options);
|
|
152
|
+
let disposable = Disposable.NULL;
|
|
140
153
|
if (!groupNode) {
|
|
141
154
|
groupNode = new CompositeMenuNode(menuId, label, options, parent);
|
|
142
|
-
|
|
155
|
+
disposable = this.changeEventOnDispose(parent.addNode(groupNode));
|
|
143
156
|
} else {
|
|
144
157
|
groupNode.updateOptions({ ...options, label });
|
|
145
|
-
return Disposable.NULL;
|
|
146
158
|
}
|
|
159
|
+
this.fireChangeEvent();
|
|
160
|
+
return disposable;
|
|
147
161
|
}
|
|
148
162
|
|
|
149
163
|
registerIndependentSubmenu(id: string, label: string, options?: SubMenuOptions): Disposable {
|
|
@@ -151,7 +165,7 @@ export class MenuModelRegistry {
|
|
|
151
165
|
console.debug(`Independent submenu with path ${id} registered, but given ID already exists.`);
|
|
152
166
|
}
|
|
153
167
|
this.independentSubmenus.set(id, new CompositeMenuNode(id, label, options));
|
|
154
|
-
return
|
|
168
|
+
return this.changeEventOnDispose(Disposable.create(() => this.independentSubmenus.delete(id)));
|
|
155
169
|
}
|
|
156
170
|
|
|
157
171
|
linkSubmenu(parentPath: MenuPath | string, childId: string | MenuPath, options?: SubMenuOptions, group?: string): Disposable {
|
|
@@ -175,7 +189,9 @@ export class MenuModelRegistry {
|
|
|
175
189
|
}
|
|
176
190
|
|
|
177
191
|
const wrapper = new CompositeMenuNodeWrapper(child, parent, options);
|
|
178
|
-
|
|
192
|
+
const disposable = parent.addNode(wrapper);
|
|
193
|
+
this.fireChangeEvent();
|
|
194
|
+
return this.changeEventOnDispose(disposable);
|
|
179
195
|
}
|
|
180
196
|
|
|
181
197
|
/**
|
|
@@ -207,6 +223,7 @@ export class MenuModelRegistry {
|
|
|
207
223
|
if (menuPath) {
|
|
208
224
|
const parent = this.findGroup(menuPath);
|
|
209
225
|
parent.removeNode(id);
|
|
226
|
+
this.fireChangeEvent();
|
|
210
227
|
return;
|
|
211
228
|
}
|
|
212
229
|
|
|
@@ -228,6 +245,7 @@ export class MenuModelRegistry {
|
|
|
228
245
|
});
|
|
229
246
|
};
|
|
230
247
|
recurse(this.root);
|
|
248
|
+
this.fireChangeEvent();
|
|
231
249
|
}
|
|
232
250
|
|
|
233
251
|
/**
|
|
@@ -321,6 +339,19 @@ export class MenuModelRegistry {
|
|
|
321
339
|
return true;
|
|
322
340
|
}
|
|
323
341
|
|
|
342
|
+
protected changeEventOnDispose(disposable: Disposable): Disposable {
|
|
343
|
+
return Disposable.create(() => {
|
|
344
|
+
disposable.dispose();
|
|
345
|
+
this.fireChangeEvent();
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
protected fireChangeEvent(): void {
|
|
350
|
+
if (this.isReady) {
|
|
351
|
+
this.onDidChangeEmitter.fire();
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
324
355
|
/**
|
|
325
356
|
* Returns the {@link MenuPath path} at which a given menu node can be accessed from this registry, if it can be determined.
|
|
326
357
|
* Returns `undefined` if the `parent` of any node in the chain is unknown.
|
|
@@ -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 {
|
|
@@ -75,6 +80,7 @@ export interface PreferenceSchemaProperty extends PreferenceItem {
|
|
|
75
80
|
description?: string;
|
|
76
81
|
markdownDescription?: string;
|
|
77
82
|
scope?: 'application' | 'machine' | 'window' | 'resource' | 'language-overridable' | 'machine-overridable' | PreferenceScope;
|
|
83
|
+
tags?: string[];
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
export interface PreferenceDataProperty extends PreferenceItem {
|
|
@@ -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
|
/**
|
|
@@ -101,6 +101,9 @@ export class ElectronMainMenuFactory extends BrowserMainMenuFactory {
|
|
|
101
101
|
this.keybindingRegistry.onKeybindingsChanged(() => {
|
|
102
102
|
this.setMenuBar();
|
|
103
103
|
});
|
|
104
|
+
this.menuProvider.onDidChange(() => {
|
|
105
|
+
this.setMenuBar();
|
|
106
|
+
});
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
async setMenuBar(): Promise<void> {
|
|
@@ -79,8 +79,8 @@ const api: TheiaCoreAPI = {
|
|
|
79
79
|
showItemInFolder: fsPath => {
|
|
80
80
|
ipcRenderer.send(CHANNEL_SHOW_ITEM_IN_FOLDER, fsPath);
|
|
81
81
|
},
|
|
82
|
-
openWithSystemApp:
|
|
83
|
-
ipcRenderer.send(CHANNEL_OPEN_WITH_SYSTEM_APP,
|
|
82
|
+
openWithSystemApp: location => {
|
|
83
|
+
ipcRenderer.send(CHANNEL_OPEN_WITH_SYSTEM_APP, location);
|
|
84
84
|
},
|
|
85
85
|
attachSecurityToken: (endpoint: string) => ipcRenderer.invoke(CHANNEL_ATTACH_SECURITY_TOKEN, endpoint),
|
|
86
86
|
|
|
@@ -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 => {
|
|
@@ -15,18 +15,20 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import { ContainerModule } from 'inversify';
|
|
18
|
-
import {
|
|
19
|
-
import { ElectronWindowService } from './electron-window-service';
|
|
20
|
-
import { FrontendApplicationContribution } from '../../browser/frontend-application-contribution';
|
|
21
|
-
import { ElectronClipboardService } from '../electron-clipboard-service';
|
|
18
|
+
import { OpenHandler } from '../../browser';
|
|
22
19
|
import { ClipboardService } from '../../browser/clipboard-service';
|
|
20
|
+
import { FrontendApplicationContribution } from '../../browser/frontend-application-contribution';
|
|
21
|
+
import { FrontendApplicationStateService } from '../../browser/frontend-application-state';
|
|
22
|
+
import { SecondaryWindowService } from '../../browser/window/secondary-window-service';
|
|
23
|
+
import { WindowService } from '../../browser/window/window-service';
|
|
23
24
|
import { ElectronMainWindowService, electronMainWindowServicePath } from '../../electron-common/electron-main-window-service';
|
|
25
|
+
import { ElectronClipboardService } from '../electron-clipboard-service';
|
|
24
26
|
import { ElectronIpcConnectionProvider } from '../messaging/electron-ipc-connection-source';
|
|
25
|
-
import { bindWindowPreferences } from './electron-window-preferences';
|
|
26
|
-
import { FrontendApplicationStateService } from '../../browser/frontend-application-state';
|
|
27
27
|
import { ElectronFrontendApplicationStateService } from './electron-frontend-application-state';
|
|
28
28
|
import { ElectronSecondaryWindowService } from './electron-secondary-window-service';
|
|
29
|
-
import {
|
|
29
|
+
import { bindWindowPreferences } from './electron-window-preferences';
|
|
30
|
+
import { ElectronWindowService } from './electron-window-service';
|
|
31
|
+
import { ExternalAppOpenHandler } from './external-app-open-handler';
|
|
30
32
|
|
|
31
33
|
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
|
32
34
|
bind(ElectronMainWindowService).toDynamicValue(context =>
|
|
@@ -38,4 +40,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
|
|
38
40
|
bind(ClipboardService).to(ElectronClipboardService).inSingletonScope();
|
|
39
41
|
rebind(FrontendApplicationStateService).to(ElectronFrontendApplicationStateService).inSingletonScope();
|
|
40
42
|
bind(SecondaryWindowService).to(ElectronSecondaryWindowService).inSingletonScope();
|
|
43
|
+
bind(ExternalAppOpenHandler).toSelf().inSingletonScope();
|
|
44
|
+
bind(OpenHandler).toService(ExternalAppOpenHandler);
|
|
41
45
|
});
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
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 { injectable } from 'inversify';
|
|
18
|
+
import { OpenHandler } from '../../browser/opener-service';
|
|
19
|
+
import URI from '../../common/uri';
|
|
20
|
+
import { HttpOpenHandler } from '../../browser/http-open-handler';
|
|
21
|
+
|
|
22
|
+
export interface ExternalAppOpenHandlerOptions {
|
|
23
|
+
openExternalApp?: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@injectable()
|
|
27
|
+
export class ExternalAppOpenHandler implements OpenHandler {
|
|
28
|
+
|
|
29
|
+
static readonly PRIORITY: number = HttpOpenHandler.PRIORITY + 100;
|
|
30
|
+
readonly id = 'external-app';
|
|
31
|
+
|
|
32
|
+
canHandle(uri: URI, options?: ExternalAppOpenHandlerOptions): number {
|
|
33
|
+
return (options && options.openExternalApp) ? ExternalAppOpenHandler.PRIORITY : -1;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async open(uri: URI): Promise<undefined> {
|
|
37
|
+
// For files 'file:' scheme, system accepts only the path.
|
|
38
|
+
// For other protocols e.g. 'vscode:' we use the full URI to propagate target app information.
|
|
39
|
+
window.electronTheiaCore.openWithSystemApp(uri.scheme === 'file' ? uri.path.fsPath() : uri.toString(true));
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|