@theia/core 1.37.0-next.3 → 1.37.0-next.30
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 +7 -9
- package/lib/browser/core-preferences.d.ts +4 -0
- package/lib/browser/core-preferences.d.ts.map +1 -1
- package/lib/browser/core-preferences.js +22 -0
- package/lib/browser/core-preferences.js.map +1 -1
- package/lib/browser/hover-service.d.ts +5 -0
- package/lib/browser/hover-service.d.ts.map +1 -1
- package/lib/browser/hover-service.js +7 -1
- package/lib/browser/hover-service.js.map +1 -1
- package/lib/browser/icon-theme-service.js +1 -1
- package/lib/browser/icon-theme-service.js.map +1 -1
- package/lib/browser/shell/application-shell.d.ts +2 -1
- package/lib/browser/shell/application-shell.d.ts.map +1 -1
- package/lib/browser/shell/application-shell.js +30 -3
- package/lib/browser/shell/application-shell.js.map +1 -1
- package/lib/browser/shell/tab-bars.d.ts +21 -5
- package/lib/browser/shell/tab-bars.d.ts.map +1 -1
- package/lib/browser/shell/tab-bars.js +94 -17
- package/lib/browser/shell/tab-bars.js.map +1 -1
- package/lib/browser/test/jsdom.js +1 -1
- package/lib/browser/test/jsdom.js.map +1 -1
- package/lib/browser/tree/tree-iterator.js +4 -4
- package/lib/browser/tree/tree-iterator.js.map +1 -1
- package/lib/browser/tree/tree-selection-state.spec.js +26 -2
- package/lib/browser/tree/tree-selection-state.spec.js.map +1 -1
- package/lib/common/i18n/localization.d.ts +1 -0
- package/lib/common/i18n/localization.d.ts.map +1 -1
- package/lib/common/i18n/localization.js +2 -16
- package/lib/common/i18n/localization.js.map +1 -1
- package/lib/common/nls.d.ts +1 -0
- package/lib/common/nls.d.ts.map +1 -1
- package/lib/common/nls.js +2 -1
- package/lib/common/nls.js.map +1 -1
- package/lib/common/quick-pick-service.d.ts +2 -1
- 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/electron-clipboard-service.d.ts.map +1 -1
- package/lib/electron-browser/electron-clipboard-service.js +2 -3
- package/lib/electron-browser/electron-clipboard-service.js.map +1 -1
- package/lib/electron-browser/keyboard/electron-keyboard-layout-change-notifier.d.ts.map +1 -1
- package/lib/electron-browser/keyboard/electron-keyboard-layout-change-notifier.js +1 -2
- package/lib/electron-browser/keyboard/electron-keyboard-layout-change-notifier.js.map +1 -1
- package/lib/electron-browser/menu/electron-context-menu-renderer.d.ts +2 -3
- package/lib/electron-browser/menu/electron-context-menu-renderer.d.ts.map +1 -1
- package/lib/electron-browser/menu/electron-context-menu-renderer.js +10 -18
- package/lib/electron-browser/menu/electron-context-menu-renderer.js.map +1 -1
- package/lib/electron-browser/menu/electron-main-menu-factory.d.ts +10 -8
- package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
- package/lib/electron-browser/menu/electron-main-menu-factory.js +33 -32
- package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
- package/lib/electron-browser/menu/electron-menu-contribution.d.ts +6 -6
- package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
- package/lib/electron-browser/menu/electron-menu-contribution.js +39 -54
- package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
- package/lib/electron-browser/messaging/electron-ipc-connection-provider.d.ts.map +1 -1
- package/lib/electron-browser/messaging/electron-ipc-connection-provider.js +2 -6
- package/lib/electron-browser/messaging/electron-ipc-connection-provider.js.map +1 -1
- package/lib/electron-browser/preload.d.ts +2 -0
- package/lib/electron-browser/preload.d.ts.map +1 -0
- package/lib/electron-browser/preload.js +183 -0
- package/lib/electron-browser/preload.js.map +1 -0
- package/lib/electron-browser/token/electron-token-frontend-module.d.ts.map +1 -1
- package/lib/electron-browser/token/electron-token-frontend-module.js +1 -2
- package/lib/electron-browser/token/electron-token-frontend-module.js.map +1 -1
- package/lib/electron-browser/window/electron-frontend-application-state.d.ts.map +1 -1
- package/lib/electron-browser/window/electron-frontend-application-state.js +1 -3
- package/lib/electron-browser/window/electron-frontend-application-state.js.map +1 -1
- package/lib/electron-browser/window/electron-secondary-window-service.d.ts +1 -3
- package/lib/electron-browser/window/electron-secondary-window-service.d.ts.map +1 -1
- package/lib/electron-browser/window/electron-secondary-window-service.js +6 -34
- package/lib/electron-browser/window/electron-secondary-window-service.js.map +1 -1
- package/lib/electron-browser/window/electron-window-service.d.ts +1 -8
- package/lib/electron-browser/window/electron-window-service.d.ts.map +1 -1
- package/lib/electron-browser/window/electron-window-service.js +8 -25
- package/lib/electron-browser/window/electron-window-service.js.map +1 -1
- package/lib/electron-common/electron-api.d.ts +94 -0
- package/lib/electron-common/electron-api.d.ts.map +1 -0
- package/lib/electron-common/electron-api.js +53 -0
- package/lib/electron-common/electron-api.js.map +1 -0
- package/lib/electron-common/messaging/electron-connection-handler.d.ts +0 -7
- package/lib/electron-common/messaging/electron-connection-handler.d.ts.map +1 -1
- package/lib/electron-common/messaging/electron-connection-handler.js +1 -5
- package/lib/electron-common/messaging/electron-connection-handler.js.map +1 -1
- package/lib/electron-main/electron-api-main.d.ts +21 -0
- package/lib/electron-main/electron-api-main.d.ts.map +1 -0
- package/lib/electron-main/electron-api-main.js +261 -0
- package/lib/electron-main/electron-api-main.js.map +1 -0
- package/lib/electron-main/electron-main-application-module.d.ts.map +1 -1
- package/lib/electron-main/electron-main-application-module.js +3 -3
- package/lib/electron-main/electron-main-application-module.js.map +1 -1
- package/lib/electron-main/electron-main-application.d.ts +8 -2
- package/lib/electron-main/electron-main-application.d.ts.map +1 -1
- package/lib/electron-main/electron-main-application.js +32 -29
- package/lib/electron-main/electron-main-application.js.map +1 -1
- package/lib/electron-main/electron-security-token-service.d.ts.map +1 -1
- package/lib/electron-main/electron-security-token-service.js +2 -1
- package/lib/electron-main/electron-security-token-service.js.map +1 -1
- package/lib/electron-main/messaging/electron-messaging-contribution.d.ts +4 -5
- package/lib/electron-main/messaging/electron-messaging-contribution.d.ts.map +1 -1
- package/lib/electron-main/messaging/electron-messaging-contribution.js +4 -7
- package/lib/electron-main/messaging/electron-messaging-contribution.js.map +1 -1
- package/lib/electron-main/theia-electron-window.d.ts +2 -4
- package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
- package/lib/electron-main/theia-electron-window.js +11 -34
- package/lib/electron-main/theia-electron-window.js.map +1 -1
- package/lib/node/i18n/localization-backend-contribution.d.ts.map +1 -1
- package/lib/node/i18n/localization-backend-contribution.js +2 -1
- package/lib/node/i18n/localization-backend-contribution.js.map +1 -1
- package/lib/node/i18n/localization-provider.d.ts.map +1 -1
- package/lib/node/i18n/localization-provider.js +2 -1
- package/lib/node/i18n/localization-provider.js.map +1 -1
- package/package.json +7 -4
- package/src/browser/core-preferences.ts +26 -0
- package/src/browser/hover-service.ts +12 -1
- package/src/browser/icon-theme-service.ts +1 -1
- package/src/browser/shell/application-shell.ts +29 -1
- package/src/browser/shell/tab-bars.ts +111 -17
- package/src/browser/style/hover-service.css +4 -0
- package/src/browser/style/tabs.css +25 -0
- package/src/browser/test/jsdom.ts +1 -1
- package/src/browser/tree/tree-iterator.ts +4 -4
- package/src/browser/tree/tree-selection-state.spec.ts +29 -2
- package/src/common/i18n/localization.ts +6 -16
- package/src/common/nls.ts +3 -1
- package/src/common/quick-pick-service.ts +2 -1
- package/src/electron-browser/electron-clipboard-service.ts +2 -3
- package/src/electron-browser/keyboard/electron-keyboard-layout-change-notifier.ts +1 -2
- package/src/electron-browser/menu/electron-context-menu-renderer.ts +10 -17
- package/src/electron-browser/menu/electron-main-menu-factory.ts +51 -44
- package/src/electron-browser/menu/electron-menu-contribution.ts +46 -57
- package/src/electron-browser/messaging/electron-ipc-connection-provider.ts +4 -9
- package/src/electron-browser/preload.ts +208 -0
- package/src/electron-browser/token/electron-token-frontend-module.ts +1 -2
- package/src/electron-browser/window/electron-frontend-application-state.ts +1 -3
- package/src/electron-browser/window/electron-secondary-window-service.ts +7 -31
- package/src/electron-browser/window/electron-window-service.ts +8 -25
- package/src/electron-common/electron-api.ts +134 -0
- package/src/electron-common/messaging/electron-connection-handler.ts +0 -9
- package/src/electron-main/electron-api-main.ts +291 -0
- package/src/electron-main/electron-main-application-module.ts +3 -4
- package/src/electron-main/electron-main-application.ts +33 -37
- package/src/electron-main/electron-security-token-service.ts +2 -1
- package/src/electron-main/messaging/electron-messaging-contribution.ts +8 -10
- package/src/electron-main/theia-electron-window.ts +8 -33
- package/src/node/i18n/localization-backend-contribution.ts +2 -1
- package/src/node/i18n/localization-provider.ts +2 -1
- package/LICENSE +0 -642
- package/electron-shared/@electron/remote/index.d.ts +0 -1
- package/electron-shared/@electron/remote/index.js +0 -1
- package/electron-shared/@electron/remote/main/index.d.ts +0 -1
- package/electron-shared/@electron/remote/main/index.js +0 -1
- package/lib/electron-common/messaging/electron-messages.d.ts +0 -25
- package/lib/electron-common/messaging/electron-messages.d.ts.map +0 -1
- package/lib/electron-common/messaging/electron-messages.js +0 -37
- package/lib/electron-common/messaging/electron-messages.js.map +0 -1
- package/lib/electron-main/electron-native-keymap.d.ts +0 -8
- package/lib/electron-main/electron-native-keymap.d.ts.map +0 -1
- package/lib/electron-main/electron-native-keymap.js +0 -48
- package/lib/electron-main/electron-native-keymap.js.map +0 -1
- package/src/electron-common/messaging/electron-messages.ts +0 -42
- package/src/electron-main/electron-native-keymap.ts +0 -40
|
@@ -80,6 +80,11 @@ export const corePreferenceSchema: PreferenceSchema = {
|
|
|
80
80
|
default: 'code',
|
|
81
81
|
markdownDescription: nls.localizeByDefault('Controls the dispatching logic for key presses to use either `code` (recommended) or `keyCode`.')
|
|
82
82
|
},
|
|
83
|
+
'window.tabbar.enhancedPreview': {
|
|
84
|
+
type: 'boolean',
|
|
85
|
+
default: false,
|
|
86
|
+
description: nls.localize('theia/core/enhancedPreview', 'Controls whether more information about the tab should be displayed in horizontal tab bars.')
|
|
87
|
+
},
|
|
83
88
|
'window.menuBarVisibility': {
|
|
84
89
|
type: 'string',
|
|
85
90
|
enum: ['classic', 'visible', 'hidden', 'compact'],
|
|
@@ -232,6 +237,23 @@ export const corePreferenceSchema: PreferenceSchema = {
|
|
|
232
237
|
type: 'boolean',
|
|
233
238
|
default: false,
|
|
234
239
|
description: nls.localize('theia/core/tabMaximize', 'Controls whether to maximize tabs on double click.')
|
|
240
|
+
},
|
|
241
|
+
'workbench.tab.shrinkToFit.enabled': {
|
|
242
|
+
type: 'boolean',
|
|
243
|
+
default: false,
|
|
244
|
+
description: nls.localize('theia/core/tabShrinkToFit', 'Shrink tabs to fit available space.')
|
|
245
|
+
},
|
|
246
|
+
'workbench.tab.shrinkToFit.minimumSize': {
|
|
247
|
+
type: 'number',
|
|
248
|
+
default: 50,
|
|
249
|
+
minimum: 10,
|
|
250
|
+
description: nls.localize('theia/core/tabMinimumSize', 'Specifies the minimum size for tabs.')
|
|
251
|
+
},
|
|
252
|
+
'workbench.tab.shrinkToFit.defaultSize': {
|
|
253
|
+
type: 'number',
|
|
254
|
+
default: 200,
|
|
255
|
+
minimum: 10,
|
|
256
|
+
description: nls.localize('theia/core/tabDefaultSize', 'Specifies the default size for tabs.')
|
|
235
257
|
}
|
|
236
258
|
}
|
|
237
259
|
};
|
|
@@ -241,6 +263,7 @@ export interface CoreConfiguration {
|
|
|
241
263
|
'breadcrumbs.enabled': boolean;
|
|
242
264
|
'files.encoding': string;
|
|
243
265
|
'keyboard.dispatch': 'code' | 'keyCode';
|
|
266
|
+
'window.tabbar.enhancedPreview': boolean;
|
|
244
267
|
'window.menuBarVisibility': 'classic' | 'visible' | 'hidden' | 'compact';
|
|
245
268
|
'window.title': string;
|
|
246
269
|
'window.titleSeparator': string;
|
|
@@ -259,6 +282,9 @@ export interface CoreConfiguration {
|
|
|
259
282
|
'workbench.sash.hoverDelay': number;
|
|
260
283
|
'workbench.sash.size': number;
|
|
261
284
|
'workbench.tab.maximize': boolean;
|
|
285
|
+
'workbench.tab.shrinkToFit.enabled': boolean;
|
|
286
|
+
'workbench.tab.shrinkToFit.minimumSize': number;
|
|
287
|
+
'workbench.tab.shrinkToFit.defaultSize': number;
|
|
262
288
|
}
|
|
263
289
|
|
|
264
290
|
export const CorePreferenceContribution = Symbol('CorePreferenceContribution');
|
|
@@ -57,6 +57,11 @@ export interface HoverRequest {
|
|
|
57
57
|
* if the specified content does not fit in the window next to the target element
|
|
58
58
|
*/
|
|
59
59
|
position: HoverPosition
|
|
60
|
+
/**
|
|
61
|
+
* Additional css classes that should be added to the hover box.
|
|
62
|
+
* Used to style certain boxes different e.g. for the extended tab preview.
|
|
63
|
+
*/
|
|
64
|
+
cssClasses?: string []
|
|
60
65
|
}
|
|
61
66
|
|
|
62
67
|
@injectable()
|
|
@@ -101,7 +106,10 @@ export class HoverService {
|
|
|
101
106
|
|
|
102
107
|
protected async renderHover(request: HoverRequest): Promise<void> {
|
|
103
108
|
const host = this.hoverHost;
|
|
104
|
-
const { target, content, position } = request;
|
|
109
|
+
const { target, content, position, cssClasses } = request;
|
|
110
|
+
if (cssClasses) {
|
|
111
|
+
host.classList.add(...cssClasses);
|
|
112
|
+
}
|
|
105
113
|
this.hoverTarget = target;
|
|
106
114
|
if (content instanceof HTMLElement) {
|
|
107
115
|
host.appendChild(content);
|
|
@@ -124,6 +132,9 @@ export class HoverService {
|
|
|
124
132
|
dispose: () => {
|
|
125
133
|
this.lastHidHover = Date.now();
|
|
126
134
|
host.classList.remove(updatedPosition);
|
|
135
|
+
if (cssClasses) {
|
|
136
|
+
host.classList.remove(...cssClasses);
|
|
137
|
+
}
|
|
127
138
|
}
|
|
128
139
|
});
|
|
129
140
|
|
|
@@ -168,9 +168,9 @@ export class IconThemeService {
|
|
|
168
168
|
*/
|
|
169
169
|
setCurrent(newCurrent: IconTheme, persistSetting = true): void {
|
|
170
170
|
if (newCurrent !== this.getCurrent()) {
|
|
171
|
+
this.activeTheme = newCurrent;
|
|
171
172
|
this.toDeactivate.dispose();
|
|
172
173
|
this.toDeactivate.push(newCurrent.activate());
|
|
173
|
-
this.activeTheme = newCurrent;
|
|
174
174
|
this.onDidChangeCurrentEmitter.fire(newCurrent.id);
|
|
175
175
|
}
|
|
176
176
|
if (persistSetting) {
|
|
@@ -96,6 +96,7 @@ export class DockPanelRenderer implements DockLayout.IRenderer {
|
|
|
96
96
|
@inject(TabBarToolbarRegistry) protected readonly tabBarToolbarRegistry: TabBarToolbarRegistry,
|
|
97
97
|
@inject(TabBarToolbarFactory) protected readonly tabBarToolbarFactory: TabBarToolbarFactory,
|
|
98
98
|
@inject(BreadcrumbsRendererFactory) protected readonly breadcrumbsRendererFactory: BreadcrumbsRendererFactory,
|
|
99
|
+
@inject(CorePreferences) protected readonly corePreferences: CorePreferences
|
|
99
100
|
) { }
|
|
100
101
|
|
|
101
102
|
get onDidCreateTabBar(): CommonEvent<TabBar<Widget>> {
|
|
@@ -103,6 +104,17 @@ export class DockPanelRenderer implements DockLayout.IRenderer {
|
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
createTabBar(): TabBar<Widget> {
|
|
107
|
+
const getDynamicTabOptions: () => ScrollableTabBar.Options | undefined = () => {
|
|
108
|
+
if (this.corePreferences.get('workbench.tab.shrinkToFit.enabled')) {
|
|
109
|
+
return {
|
|
110
|
+
minimumTabSize: this.corePreferences.get('workbench.tab.shrinkToFit.minimumSize'),
|
|
111
|
+
defaultTabSize: this.corePreferences.get('workbench.tab.shrinkToFit.defaultSize')
|
|
112
|
+
};
|
|
113
|
+
} else {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
106
118
|
const renderer = this.tabBarRendererFactory();
|
|
107
119
|
const tabBar = new ToolbarAwareTabBar(
|
|
108
120
|
this.tabBarToolbarRegistry,
|
|
@@ -115,12 +127,20 @@ export class DockPanelRenderer implements DockLayout.IRenderer {
|
|
|
115
127
|
useBothWheelAxes: true,
|
|
116
128
|
scrollXMarginOffset: 4,
|
|
117
129
|
suppressScrollY: true
|
|
118
|
-
}
|
|
130
|
+
},
|
|
131
|
+
getDynamicTabOptions());
|
|
119
132
|
this.tabBarClasses.forEach(c => tabBar.addClass(c));
|
|
120
133
|
renderer.tabBar = tabBar;
|
|
121
134
|
tabBar.disposed.connect(() => renderer.dispose());
|
|
122
135
|
renderer.contextMenuPath = SHELL_TABBAR_CONTEXT_MENU;
|
|
123
136
|
tabBar.currentChanged.connect(this.onCurrentTabChanged, this);
|
|
137
|
+
this.corePreferences.onPreferenceChanged(change => {
|
|
138
|
+
if (change.preferenceName === 'workbench.tab.shrinkToFit.enabled' ||
|
|
139
|
+
change.preferenceName === 'workbench.tab.shrinkToFit.minimumSize' ||
|
|
140
|
+
change.preferenceName === 'workbench.tab.shrinkToFit.defaultSize') {
|
|
141
|
+
tabBar.dynamicTabOptions = getDynamicTabOptions();
|
|
142
|
+
}
|
|
143
|
+
});
|
|
124
144
|
this.onDidCreateTabBarEmitter.fire(tabBar);
|
|
125
145
|
return tabBar;
|
|
126
146
|
}
|
|
@@ -266,6 +286,14 @@ export class ApplicationShell extends Widget {
|
|
|
266
286
|
}
|
|
267
287
|
});
|
|
268
288
|
}
|
|
289
|
+
|
|
290
|
+
this.corePreferences.onPreferenceChanged(preference => {
|
|
291
|
+
if (preference.preferenceName === 'window.tabbar.enhancedPreview') {
|
|
292
|
+
this.allTabBars.forEach(tabBar => {
|
|
293
|
+
tabBar.update();
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
});
|
|
269
297
|
}
|
|
270
298
|
|
|
271
299
|
protected initializeShell(): void {
|
|
@@ -67,6 +67,10 @@ export interface SideBarRenderData extends TabBar.IRenderData<Widget> {
|
|
|
67
67
|
paddingBottom?: number;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
export interface ScrollableRenderData extends TabBar.IRenderData<Widget> {
|
|
71
|
+
tabWidth?: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
70
74
|
/**
|
|
71
75
|
* A tab bar renderer that offers a context menu. In addition, this renderer is able to
|
|
72
76
|
* set an explicit position and size on the icon and label of each tab in a side bar.
|
|
@@ -157,9 +161,7 @@ export class TabBarRenderer extends TabBar.Renderer {
|
|
|
157
161
|
? nls.localizeByDefault('Unpin')
|
|
158
162
|
: nls.localizeByDefault('Close');
|
|
159
163
|
|
|
160
|
-
const hover = this.tabBar && this.tabBar.orientation === 'horizontal' ? {
|
|
161
|
-
title: title.caption
|
|
162
|
-
} : {
|
|
164
|
+
const hover = this.tabBar && (this.tabBar.orientation === 'horizontal' && !this.corePreferences?.['window.tabbar.enhancedPreview']) ? { title: title.caption } : {
|
|
163
165
|
onmouseenter: this.handleMouseEnterEvent
|
|
164
166
|
};
|
|
165
167
|
|
|
@@ -204,11 +206,12 @@ export class TabBarRenderer extends TabBar.Renderer {
|
|
|
204
206
|
* If size information is available for the label and icon, set an explicit height on the tab.
|
|
205
207
|
* The height value also considers padding, which should be derived from CSS settings.
|
|
206
208
|
*/
|
|
207
|
-
override createTabStyle(data: SideBarRenderData): ElementInlineStyle {
|
|
209
|
+
override createTabStyle(data: SideBarRenderData & ScrollableRenderData): ElementInlineStyle {
|
|
208
210
|
const zIndex = `${data.zIndex}`;
|
|
209
211
|
const labelSize = data.labelSize;
|
|
210
212
|
const iconSize = data.iconSize;
|
|
211
213
|
let height: string | undefined;
|
|
214
|
+
let width: string | undefined;
|
|
212
215
|
if (labelSize || iconSize) {
|
|
213
216
|
const labelHeight = labelSize ? (this.tabBar && this.tabBar.orientation === 'horizontal' ? labelSize.height : labelSize.width) : 0;
|
|
214
217
|
const iconHeight = iconSize ? iconSize.height : 0;
|
|
@@ -220,7 +223,12 @@ export class TabBarRenderer extends TabBar.Renderer {
|
|
|
220
223
|
const paddingBottom = data.paddingBottom || 0;
|
|
221
224
|
height = `${labelHeight + iconHeight + paddingTop + paddingBottom}px`;
|
|
222
225
|
}
|
|
223
|
-
|
|
226
|
+
if (data.tabWidth) {
|
|
227
|
+
width = `${data.tabWidth}px`;
|
|
228
|
+
} else {
|
|
229
|
+
width = '';
|
|
230
|
+
}
|
|
231
|
+
return { zIndex, height, width };
|
|
224
232
|
}
|
|
225
233
|
|
|
226
234
|
/**
|
|
@@ -474,16 +482,41 @@ export class TabBarRenderer extends TabBar.Renderer {
|
|
|
474
482
|
return h.div({ className: baseClassName, style }, data.title.iconLabel);
|
|
475
483
|
}
|
|
476
484
|
|
|
485
|
+
protected renderEnhancedPreview = (title: Title<Widget>) => {
|
|
486
|
+
const hoverBox = document.createElement('div');
|
|
487
|
+
hoverBox.classList.add('theia-horizontal-tabBar-hover-div');
|
|
488
|
+
const labelElement = document.createElement('p');
|
|
489
|
+
labelElement.classList.add('theia-horizontal-tabBar-hover-title');
|
|
490
|
+
labelElement.textContent = title.label;
|
|
491
|
+
hoverBox.append(labelElement);
|
|
492
|
+
if (title.caption) {
|
|
493
|
+
const captionElement = document.createElement('p');
|
|
494
|
+
captionElement.classList.add('theia-horizontal-tabBar-hover-caption');
|
|
495
|
+
captionElement.textContent = title.caption;
|
|
496
|
+
hoverBox.appendChild(captionElement);
|
|
497
|
+
}
|
|
498
|
+
return hoverBox;
|
|
499
|
+
};
|
|
500
|
+
|
|
477
501
|
protected handleMouseEnterEvent = (event: MouseEvent) => {
|
|
478
502
|
if (this.tabBar && this.hoverService && event.currentTarget instanceof HTMLElement) {
|
|
479
503
|
const id = event.currentTarget.id;
|
|
480
504
|
const title = this.tabBar.titles.find(t => this.createTabId(t) === id);
|
|
481
505
|
if (title) {
|
|
482
|
-
this.
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
506
|
+
if (this.tabBar.orientation === 'horizontal') {
|
|
507
|
+
this.hoverService.requestHover({
|
|
508
|
+
content: this.renderEnhancedPreview(title),
|
|
509
|
+
target: event.currentTarget,
|
|
510
|
+
position: 'bottom',
|
|
511
|
+
cssClasses: ['extended-tab-preview']
|
|
512
|
+
});
|
|
513
|
+
} else {
|
|
514
|
+
this.hoverService.requestHover({
|
|
515
|
+
content: title.caption,
|
|
516
|
+
target: event.currentTarget,
|
|
517
|
+
position: 'right'
|
|
518
|
+
});
|
|
519
|
+
}
|
|
487
520
|
}
|
|
488
521
|
}
|
|
489
522
|
};
|
|
@@ -542,6 +575,13 @@ export class TabBarRenderer extends TabBar.Renderer {
|
|
|
542
575
|
|
|
543
576
|
}
|
|
544
577
|
|
|
578
|
+
export namespace ScrollableTabBar {
|
|
579
|
+
export interface Options {
|
|
580
|
+
minimumTabSize: number;
|
|
581
|
+
defaultTabSize: number;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
545
585
|
/**
|
|
546
586
|
* A specialized tab bar for the main and bottom areas.
|
|
547
587
|
*/
|
|
@@ -551,12 +591,26 @@ export class ScrollableTabBar extends TabBar<Widget> {
|
|
|
551
591
|
|
|
552
592
|
private scrollBarFactory: () => PerfectScrollbar;
|
|
553
593
|
private pendingReveal?: Promise<void>;
|
|
594
|
+
private isMouseOver = false;
|
|
595
|
+
protected needsRecompute = false;
|
|
596
|
+
protected tabSize = 0;
|
|
597
|
+
private _dynamicTabOptions?: ScrollableTabBar.Options;
|
|
554
598
|
|
|
555
599
|
protected readonly toDispose = new DisposableCollection();
|
|
556
600
|
|
|
557
|
-
constructor(options?: TabBar.IOptions<Widget> & PerfectScrollbar.Options) {
|
|
601
|
+
constructor(options?: TabBar.IOptions<Widget> & PerfectScrollbar.Options, dynamicTabOptions?: ScrollableTabBar.Options) {
|
|
558
602
|
super(options);
|
|
559
603
|
this.scrollBarFactory = () => new PerfectScrollbar(this.scrollbarHost, options);
|
|
604
|
+
this._dynamicTabOptions = dynamicTabOptions;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
set dynamicTabOptions(options: ScrollableTabBar.Options | undefined) {
|
|
608
|
+
this._dynamicTabOptions = options;
|
|
609
|
+
this.updateTabs();
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
get dynamicTabOptions(): ScrollableTabBar.Options | undefined {
|
|
613
|
+
return this._dynamicTabOptions;
|
|
560
614
|
}
|
|
561
615
|
|
|
562
616
|
override dispose(): void {
|
|
@@ -571,6 +625,14 @@ export class ScrollableTabBar extends TabBar<Widget> {
|
|
|
571
625
|
if (!this.scrollBar) {
|
|
572
626
|
this.scrollBar = this.scrollBarFactory();
|
|
573
627
|
}
|
|
628
|
+
this.node.addEventListener('mouseenter', () => { this.isMouseOver = true; });
|
|
629
|
+
this.node.addEventListener('mouseleave', () => {
|
|
630
|
+
this.isMouseOver = false;
|
|
631
|
+
if (this.needsRecompute) {
|
|
632
|
+
this.updateTabs();
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
|
|
574
636
|
super.onAfterAttach(msg);
|
|
575
637
|
}
|
|
576
638
|
|
|
@@ -583,7 +645,34 @@ export class ScrollableTabBar extends TabBar<Widget> {
|
|
|
583
645
|
}
|
|
584
646
|
|
|
585
647
|
protected override onUpdateRequest(msg: Message): void {
|
|
586
|
-
|
|
648
|
+
this.updateTabs();
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
protected updateTabs(): void {
|
|
652
|
+
|
|
653
|
+
const content = [];
|
|
654
|
+
if (this.dynamicTabOptions) {
|
|
655
|
+
if (this.isMouseOver) {
|
|
656
|
+
this.needsRecompute = true;
|
|
657
|
+
} else {
|
|
658
|
+
this.needsRecompute = false;
|
|
659
|
+
if (this.orientation === 'horizontal') {
|
|
660
|
+
this.tabSize = Math.max(Math.min(this.scrollbarHost.clientWidth / this.titles.length,
|
|
661
|
+
this.dynamicTabOptions.defaultTabSize), this.dynamicTabOptions.minimumTabSize);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
for (let i = 0, n = this.titles.length; i < n; ++i) {
|
|
666
|
+
const title = this.titles[i];
|
|
667
|
+
const current = title === this.currentTitle;
|
|
668
|
+
const zIndex = current ? n : n - i - 1;
|
|
669
|
+
const renderData: ScrollableRenderData = { title: title, current: current, zIndex: zIndex };
|
|
670
|
+
if (this.dynamicTabOptions && this.orientation === 'horizontal') {
|
|
671
|
+
renderData.tabWidth = this.tabSize;
|
|
672
|
+
}
|
|
673
|
+
content[i] = this.renderer.renderTab(renderData);
|
|
674
|
+
}
|
|
675
|
+
VirtualDOM.render(content, this.contentNode);
|
|
587
676
|
if (this.scrollBar) {
|
|
588
677
|
this.scrollBar.update();
|
|
589
678
|
}
|
|
@@ -591,6 +680,9 @@ export class ScrollableTabBar extends TabBar<Widget> {
|
|
|
591
680
|
|
|
592
681
|
protected override onResize(msg: Widget.ResizeMessage): void {
|
|
593
682
|
super.onResize(msg);
|
|
683
|
+
if (this.dynamicTabOptions) {
|
|
684
|
+
this.updateTabs();
|
|
685
|
+
}
|
|
594
686
|
if (this.scrollBar) {
|
|
595
687
|
if (this.currentIndex >= 0) {
|
|
596
688
|
this.revealTab(this.currentIndex);
|
|
@@ -680,9 +772,10 @@ export class ToolbarAwareTabBar extends ScrollableTabBar {
|
|
|
680
772
|
protected readonly tabBarToolbarRegistry: TabBarToolbarRegistry,
|
|
681
773
|
protected readonly tabBarToolbarFactory: () => TabBarToolbar,
|
|
682
774
|
protected readonly breadcrumbsRendererFactory: BreadcrumbsRendererFactory,
|
|
683
|
-
|
|
775
|
+
options?: TabBar.IOptions<Widget> & PerfectScrollbar.Options,
|
|
776
|
+
dynamicTabOptions?: ScrollableTabBar.Options
|
|
684
777
|
) {
|
|
685
|
-
super(options);
|
|
778
|
+
super(options, dynamicTabOptions);
|
|
686
779
|
this.breadcrumbsRenderer = this.breadcrumbsRendererFactory();
|
|
687
780
|
this.rewireDOM();
|
|
688
781
|
this.toDispose.push(this.tabBarToolbarRegistry.onDidChange(() => this.update()));
|
|
@@ -756,6 +849,7 @@ export class ToolbarAwareTabBar extends ScrollableTabBar {
|
|
|
756
849
|
}
|
|
757
850
|
const widget = this.currentTitle?.owner ?? undefined;
|
|
758
851
|
this.toolbar.updateTarget(widget);
|
|
852
|
+
this.updateTabs();
|
|
759
853
|
}
|
|
760
854
|
|
|
761
855
|
override handleEvent(event: Event): void {
|
|
@@ -859,7 +953,7 @@ export class SideTabBar extends ScrollableTabBar {
|
|
|
859
953
|
|
|
860
954
|
protected override onAfterAttach(msg: Message): void {
|
|
861
955
|
super.onAfterAttach(msg);
|
|
862
|
-
this.
|
|
956
|
+
this.updateTabs();
|
|
863
957
|
this.node.addEventListener('p-dragenter', this);
|
|
864
958
|
this.node.addEventListener('p-dragover', this);
|
|
865
959
|
this.node.addEventListener('p-dragleave', this);
|
|
@@ -875,7 +969,7 @@ export class SideTabBar extends ScrollableTabBar {
|
|
|
875
969
|
}
|
|
876
970
|
|
|
877
971
|
protected override onUpdateRequest(msg: Message): void {
|
|
878
|
-
this.
|
|
972
|
+
this.updateTabs();
|
|
879
973
|
if (this.scrollBar) {
|
|
880
974
|
this.scrollBar.update();
|
|
881
975
|
}
|
|
@@ -885,7 +979,7 @@ export class SideTabBar extends ScrollableTabBar {
|
|
|
885
979
|
* Render the tab bar in the _hidden content node_ (see `hiddenContentNode` for explanation),
|
|
886
980
|
* then gather size information for labels and render it again in the proper content node.
|
|
887
981
|
*/
|
|
888
|
-
protected
|
|
982
|
+
protected override updateTabs(): void {
|
|
889
983
|
if (this.isAttached) {
|
|
890
984
|
// Render into the invisible node
|
|
891
985
|
this.renderTabs(this.hiddenContentNode);
|
|
@@ -410,3 +410,28 @@
|
|
|
410
410
|
flex-flow: row nowrap;
|
|
411
411
|
min-width: 100%;
|
|
412
412
|
}
|
|
413
|
+
|
|
414
|
+
.p-TabBar-tab .theia-tab-icon-label {
|
|
415
|
+
flex: 1;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.p-TabBar[data-orientation='horizontal'] .p-TabBar-tab.p-mod-closable:hover .theia-tab-icon-label,
|
|
419
|
+
.p-TabBar[data-orientation='horizontal'] .p-TabBar-tab.p-mod-current .theia-tab-icon-label {
|
|
420
|
+
overflow: hidden;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.theia-horizontal-tabBar-hover-div {
|
|
424
|
+
margin: 0px 4px;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.theia-horizontal-tabBar-hover-title {
|
|
428
|
+
font-weight: bolder;
|
|
429
|
+
font-size: medium;
|
|
430
|
+
margin: 0px 0px;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.theia-horizontal-tabBar-hover-caption {
|
|
434
|
+
font-size: small;
|
|
435
|
+
margin: 0px 0px;
|
|
436
|
+
margin-top: 4px;
|
|
437
|
+
}
|
|
@@ -47,7 +47,7 @@ export function enableJSDOM(): () => void {
|
|
|
47
47
|
|
|
48
48
|
const toCleanup: string[] = [];
|
|
49
49
|
Object.getOwnPropertyNames((dom.window as any)).forEach(property => {
|
|
50
|
-
if (
|
|
50
|
+
if (!(property in global)) {
|
|
51
51
|
(global as any)[property] = (dom.window as any)[property];
|
|
52
52
|
toCleanup.push(property);
|
|
53
53
|
}
|
|
@@ -202,12 +202,12 @@ export namespace Iterators {
|
|
|
202
202
|
* Generator for depth first, pre-order tree traversal iteration.
|
|
203
203
|
*/
|
|
204
204
|
export function* depthFirst<T>(root: T, children: (node: T) => T[] | undefined, include: (node: T) => boolean = () => true): IterableIterator<T> {
|
|
205
|
-
|
|
205
|
+
let stack: T[] = [];
|
|
206
206
|
stack.push(root);
|
|
207
207
|
while (stack.length > 0) {
|
|
208
208
|
const top = stack.pop()!;
|
|
209
209
|
yield top;
|
|
210
|
-
stack.
|
|
210
|
+
stack = stack.concat((children(top) || []).filter(include).reverse());
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
|
|
@@ -215,12 +215,12 @@ export namespace Iterators {
|
|
|
215
215
|
* Generator for breadth first tree traversal iteration.
|
|
216
216
|
*/
|
|
217
217
|
export function* breadthFirst<T>(root: T, children: (node: T) => T[] | undefined, include: (node: T) => boolean = () => true): IterableIterator<T> {
|
|
218
|
-
|
|
218
|
+
let queue: T[] = [];
|
|
219
219
|
queue.push(root);
|
|
220
220
|
while (queue.length > 0) {
|
|
221
221
|
const head = queue.shift()!;
|
|
222
222
|
yield head;
|
|
223
|
-
queue.
|
|
223
|
+
queue = queue.concat((children(head) || []).filter(include));
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
226
|
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
|
|
17
17
|
import { expect } from 'chai';
|
|
18
18
|
import { MockTreeModel } from './test/mock-tree-model';
|
|
19
|
-
import { TreeSelectionState } from './tree-selection-state';
|
|
20
19
|
import { createTreeTestContainer } from './test/tree-test-container';
|
|
21
|
-
import { SelectableTreeNode, TreeSelection } from './tree-selection';
|
|
22
20
|
import { TreeModel } from './tree-model';
|
|
21
|
+
import { SelectableTreeNode, TreeSelection } from './tree-selection';
|
|
22
|
+
import { TreeSelectionState } from './tree-selection-state';
|
|
23
23
|
|
|
24
24
|
namespace TreeSelectionState {
|
|
25
25
|
|
|
@@ -34,6 +34,16 @@ namespace TreeSelectionState {
|
|
|
34
34
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
const LARGE_FLAT_MOCK_ROOT = (length = 250000) => {
|
|
38
|
+
const children = Array.from({ length }, (_, idx) => ({ 'id': (idx + 1).toString() }));
|
|
39
|
+
return MockTreeModel.Node.toTreeNode({
|
|
40
|
+
'id': 'ROOT',
|
|
41
|
+
'children': [
|
|
42
|
+
...children
|
|
43
|
+
]
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
37
47
|
describe('tree-selection-state', () => {
|
|
38
48
|
|
|
39
49
|
const model = createTreeModel();
|
|
@@ -391,6 +401,23 @@ describe('tree-selection-state', () => {
|
|
|
391
401
|
});
|
|
392
402
|
});
|
|
393
403
|
|
|
404
|
+
it('should be able to handle range selection on large tree', () => {
|
|
405
|
+
model.root = LARGE_FLAT_MOCK_ROOT();
|
|
406
|
+
expect(model.selectedNodes).to.be.empty;
|
|
407
|
+
|
|
408
|
+
const start = 10;
|
|
409
|
+
const end = 20;
|
|
410
|
+
newState()
|
|
411
|
+
.nextState('toggle', start.toString(), {
|
|
412
|
+
focus: start.toString(),
|
|
413
|
+
selection: [start.toString()]
|
|
414
|
+
})
|
|
415
|
+
.nextState('range', end.toString(), {
|
|
416
|
+
focus: start.toString(),
|
|
417
|
+
selection: Array.from({ length: end - start + 1 }, (_, idx) => (start + idx).toString())
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
394
421
|
function newState(): TreeSelectionState.Assert {
|
|
395
422
|
return nextState(new TreeSelectionState(model));
|
|
396
423
|
}
|
|
@@ -39,22 +39,12 @@ export type FormatType = string | number | boolean | undefined;
|
|
|
39
39
|
|
|
40
40
|
export namespace Localization {
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
let replacement = match;
|
|
49
|
-
if (typeof arg === 'string') {
|
|
50
|
-
replacement = arg;
|
|
51
|
-
} else if (typeof arg === 'number' || typeof arg === 'boolean' || !arg) {
|
|
52
|
-
replacement = String(arg);
|
|
53
|
-
}
|
|
54
|
-
return replacement;
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
return result;
|
|
42
|
+
const formatRegexp = /{([^}]+)}/g;
|
|
43
|
+
|
|
44
|
+
export function format(message: string, args: FormatType[]): string;
|
|
45
|
+
export function format(message: string, args: Record<string | number, FormatType>): string;
|
|
46
|
+
export function format(message: string, args: Record<string | number, FormatType> | FormatType[]): string {
|
|
47
|
+
return message.replace(formatRegexp, (match, group) => (args[group] ?? match) as string);
|
|
58
48
|
}
|
|
59
49
|
|
|
60
50
|
export function localize(localization: Localization | undefined, key: string, defaultValue: string, ...args: FormatType[]): string {
|
package/src/common/nls.ts
CHANGED
|
@@ -20,6 +20,8 @@ export namespace nls {
|
|
|
20
20
|
|
|
21
21
|
export let localization: Localization | undefined;
|
|
22
22
|
|
|
23
|
+
export const defaultLocale = 'en';
|
|
24
|
+
|
|
23
25
|
export const localeId = 'localeId';
|
|
24
26
|
|
|
25
27
|
export const locale = typeof window === 'object' && window && window.localStorage.getItem(localeId) || undefined;
|
|
@@ -57,7 +59,7 @@ export namespace nls {
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
export function isSelectedLocale(id: string): boolean {
|
|
60
|
-
if (locale === undefined && id ===
|
|
62
|
+
if (locale === undefined && id === defaultLocale) {
|
|
61
63
|
return true;
|
|
62
64
|
}
|
|
63
65
|
return locale === id;
|
|
@@ -67,6 +67,7 @@ export interface QuickPickSeparator {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export type QuickPickItemOrSeparator = QuickPickItem | QuickPickSeparator;
|
|
70
|
+
export type QuickPickInput<T = QuickPickItem> = T | QuickPickSeparator;
|
|
70
71
|
|
|
71
72
|
export namespace QuickPickItem {
|
|
72
73
|
export function is(item: QuickPickSeparator | QuickPickItem): item is QuickPickItem {
|
|
@@ -278,7 +279,7 @@ export interface QuickInputService {
|
|
|
278
279
|
open(filter: string): void;
|
|
279
280
|
createInputBox(): InputBox;
|
|
280
281
|
input(options?: InputOptions, token?: CancellationToken): Promise<string | undefined>;
|
|
281
|
-
pick<T extends QuickPickItem, O extends PickOptions<T>>(picks: Promise<T[]> | T[], options?: O, token?: CancellationToken):
|
|
282
|
+
pick<T extends QuickPickItem, O extends PickOptions<T>>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: O, token?: CancellationToken):
|
|
282
283
|
Promise<(O extends { canPickMany: true } ? T[] : T) | undefined>;
|
|
283
284
|
showQuickPick<T extends QuickPickItem>(items: Array<T | QuickPickSeparator>, options?: QuickPickOptions<T>): Promise<T | undefined>;
|
|
284
285
|
hide(): void;
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
18
|
-
import { clipboard } from 'electron';
|
|
19
18
|
import { injectable } from 'inversify';
|
|
20
19
|
import { ClipboardService } from '../browser/clipboard-service';
|
|
21
20
|
|
|
@@ -23,11 +22,11 @@ import { ClipboardService } from '../browser/clipboard-service';
|
|
|
23
22
|
export class ElectronClipboardService implements ClipboardService {
|
|
24
23
|
|
|
25
24
|
readText(): string {
|
|
26
|
-
return
|
|
25
|
+
return window.electronTheiaCore.readClipboard();
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
writeText(value: string): void {
|
|
30
|
-
|
|
29
|
+
window.electronTheiaCore.writeClipboard(value);
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
}
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import { ipcRenderer } from '@theia/electron/shared/electron';
|
|
18
17
|
import { postConstruct, injectable } from 'inversify';
|
|
19
18
|
import { KeyboardLayoutChangeNotifier, NativeKeyboardLayout } from '../../common/keyboard/keyboard-layout-provider';
|
|
20
19
|
import { Emitter, Event } from '../../common/event';
|
|
@@ -34,7 +33,7 @@ export class ElectronKeyboardLayoutChangeNotifier implements KeyboardLayoutChang
|
|
|
34
33
|
|
|
35
34
|
@postConstruct()
|
|
36
35
|
protected initialize(): void {
|
|
37
|
-
|
|
36
|
+
window.electronTheiaCore.onKeyboardLayoutChanged((newLayout: NativeKeyboardLayout) => this.nativeLayoutChanged.fire(newLayout));
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
}
|