@theia/core 1.30.0-next.7 → 1.30.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 +6 -6
- package/i18n/nls.cs.json +16 -0
- package/i18n/nls.de.json +16 -0
- package/i18n/nls.es.json +16 -0
- package/i18n/nls.fr.json +16 -0
- package/i18n/nls.hu.json +16 -0
- package/i18n/nls.it.json +16 -0
- package/i18n/nls.ja.json +16 -0
- package/i18n/nls.json +16 -0
- package/i18n/nls.pl.json +16 -0
- package/i18n/nls.pt-br.json +16 -0
- package/i18n/nls.pt-pt.json +16 -0
- package/i18n/nls.ru.json +16 -0
- package/i18n/nls.zh-cn.json +20 -4
- package/lib/browser/about-dialog.d.ts +9 -0
- package/lib/browser/about-dialog.d.ts.map +1 -1
- package/lib/browser/about-dialog.js +34 -4
- package/lib/browser/about-dialog.js.map +1 -1
- package/lib/browser/core-preferences.d.ts +3 -1
- package/lib/browser/core-preferences.d.ts.map +1 -1
- package/lib/browser/core-preferences.js +38 -2
- package/lib/browser/core-preferences.js.map +1 -1
- package/lib/browser/dialogs/react-dialog.d.ts +1 -0
- package/lib/browser/dialogs/react-dialog.d.ts.map +1 -1
- package/lib/browser/dialogs/react-dialog.js +10 -2
- package/lib/browser/dialogs/react-dialog.js.map +1 -1
- package/lib/browser/frontend-application-config-provider.spec.js +1 -1
- package/lib/browser/frontend-application-config-provider.spec.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/icon-theme-service.d.ts +5 -1
- package/lib/browser/icon-theme-service.d.ts.map +1 -1
- package/lib/browser/icon-theme-service.js +21 -1
- package/lib/browser/icon-theme-service.js.map +1 -1
- package/lib/browser/label-provider.d.ts +13 -1
- package/lib/browser/label-provider.d.ts.map +1 -1
- package/lib/browser/label-provider.js +34 -28
- package/lib/browser/label-provider.js.map +1 -1
- package/lib/browser/preferences/preference-contribution.d.ts +2 -0
- package/lib/browser/preferences/preference-contribution.d.ts.map +1 -1
- package/lib/browser/preferences/preference-contribution.js +7 -0
- package/lib/browser/preferences/preference-contribution.js.map +1 -1
- package/lib/browser/preloader.d.ts.map +1 -1
- package/lib/browser/preloader.js +4 -1
- package/lib/browser/preloader.js.map +1 -1
- package/lib/browser/shell/application-shell.d.ts +1 -0
- package/lib/browser/shell/application-shell.d.ts.map +1 -1
- package/lib/browser/shell/application-shell.js +8 -0
- package/lib/browser/shell/application-shell.js.map +1 -1
- package/lib/browser/shell/tab-bars.d.ts +10 -2
- package/lib/browser/shell/tab-bars.d.ts.map +1 -1
- package/lib/browser/shell/tab-bars.js +14 -5
- package/lib/browser/shell/tab-bars.js.map +1 -1
- package/lib/browser/shell/theia-dock-panel.d.ts +4 -2
- package/lib/browser/shell/theia-dock-panel.d.ts.map +1 -1
- package/lib/browser/shell/theia-dock-panel.js +5 -0
- package/lib/browser/shell/theia-dock-panel.js.map +1 -1
- package/lib/browser/theming.d.ts +5 -1
- package/lib/browser/theming.d.ts.map +1 -1
- package/lib/browser/theming.js +19 -1
- package/lib/browser/theming.js.map +1 -1
- package/lib/browser/view-container.js +1 -1
- package/lib/browser/view-container.js.map +1 -1
- package/lib/browser/window/window-title-service.d.ts +32 -0
- package/lib/browser/window/window-title-service.d.ts.map +1 -0
- package/lib/browser/window/window-title-service.js +121 -0
- package/lib/browser/window/window-title-service.js.map +1 -0
- package/lib/browser/window/window-title-updater.d.ts +19 -0
- package/lib/browser/window/window-title-updater.d.ts.map +1 -0
- package/lib/browser/window/window-title-updater.js +108 -0
- package/lib/browser/window/window-title-updater.js.map +1 -0
- package/lib/common/event.d.ts +8 -3
- package/lib/common/event.d.ts.map +1 -1
- package/lib/common/event.js +3 -1
- package/lib/common/event.js.map +1 -1
- package/lib/common/json-schema.d.ts +1 -0
- package/lib/common/json-schema.d.ts.map +1 -1
- package/lib/common/message-rpc/rpc-message-encoder.d.ts.map +1 -1
- package/lib/common/message-rpc/rpc-message-encoder.js +1 -1
- package/lib/common/message-rpc/rpc-message-encoder.js.map +1 -1
- package/lib/common/message-rpc/rpc-protocol.d.ts +0 -1
- package/lib/common/message-rpc/rpc-protocol.d.ts.map +1 -1
- package/lib/common/message-rpc/rpc-protocol.js +6 -13
- package/lib/common/message-rpc/rpc-protocol.js.map +1 -1
- package/lib/common/progress-service.d.ts +1 -1
- package/lib/common/progress-service.d.ts.map +1 -1
- package/lib/common/progress-service.js +2 -2
- package/lib/common/progress-service.js.map +1 -1
- package/lib/common/quick-pick-service.d.ts +2 -2
- package/lib/common/quick-pick-service.d.ts.map +1 -1
- package/lib/electron-browser/menu/electron-menu-contribution.d.ts +17 -1
- package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
- package/lib/electron-browser/menu/electron-menu-contribution.js +87 -1
- package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
- package/lib/electron-browser/menu/electron-menu-module.d.ts.map +1 -1
- package/lib/electron-browser/menu/electron-menu-module.js +2 -0
- package/lib/electron-browser/menu/electron-menu-module.js.map +1 -1
- package/lib/electron-main/electron-main-application-module.d.ts.map +1 -1
- package/lib/electron-main/electron-main-application-module.js +3 -0
- package/lib/electron-main/electron-main-application-module.js.map +1 -1
- package/package.json +6 -6
- package/src/browser/about-dialog.tsx +45 -2
- package/src/browser/core-preferences.ts +43 -4
- package/src/browser/dialogs/react-dialog.tsx +10 -2
- package/src/browser/frontend-application-config-provider.spec.ts +1 -1
- package/src/browser/frontend-application-module.ts +5 -0
- package/src/browser/icon-theme-service.ts +21 -2
- package/src/browser/label-provider.ts +38 -29
- package/src/browser/preferences/preference-contribution.ts +9 -0
- package/src/browser/preloader.ts +4 -1
- package/src/browser/shell/application-shell.ts +9 -0
- package/src/browser/shell/tab-bars.ts +14 -5
- package/src/browser/shell/theia-dock-panel.ts +6 -1
- package/src/browser/style/about.css +13 -4
- package/src/browser/theming.ts +21 -3
- package/src/browser/view-container.ts +2 -2
- package/src/browser/window/window-title-service.ts +107 -0
- package/src/browser/window/window-title-updater.ts +94 -0
- package/src/common/event.ts +13 -4
- package/src/common/json-schema.ts +1 -0
- package/src/common/message-rpc/rpc-message-encoder.ts +1 -1
- package/src/common/message-rpc/rpc-protocol.ts +8 -14
- package/src/common/progress-service.ts +2 -2
- package/src/common/quick-pick-service.ts +2 -2
- package/src/electron-browser/menu/electron-menu-contribution.ts +87 -7
- package/src/electron-browser/menu/electron-menu-module.ts +3 -1
- package/src/electron-browser/menu/electron-menu-style.css +25 -0
- package/src/electron-main/electron-main-application-module.ts +4 -0
|
@@ -68,6 +68,11 @@ export interface LabelProviderContribution {
|
|
|
68
68
|
*/
|
|
69
69
|
getLongName?(element: object): string | undefined;
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* A compromise between {@link getName} and {@link getLongName}. Can be used to supplement getName in contexts that allow both a primary display field and extra detail.
|
|
73
|
+
*/
|
|
74
|
+
getDetails?(element: object): string | undefined;
|
|
75
|
+
|
|
71
76
|
/**
|
|
72
77
|
* Emit when something has changed that may result in this label provider returning a different
|
|
73
78
|
* value for one or more properties (name, icon etc).
|
|
@@ -168,6 +173,14 @@ export class DefaultUriLabelProviderContribution implements LabelProviderContrib
|
|
|
168
173
|
return uri && uri.path.fsPath();
|
|
169
174
|
}
|
|
170
175
|
|
|
176
|
+
getDetails(element: URI | URIIconReference): string | undefined {
|
|
177
|
+
const uri = this.getUri(element);
|
|
178
|
+
if (uri) {
|
|
179
|
+
return this.getLongName(uri.parent);
|
|
180
|
+
}
|
|
181
|
+
return this.getLongName(element);
|
|
182
|
+
}
|
|
183
|
+
|
|
171
184
|
protected getUri(element: URI | URIIconReference): URI | undefined {
|
|
172
185
|
return URIIconReference.is(element) ? element.uri : element;
|
|
173
186
|
}
|
|
@@ -325,15 +338,7 @@ export class LabelProvider implements FrontendApplicationContribution {
|
|
|
325
338
|
* @return the icon class
|
|
326
339
|
*/
|
|
327
340
|
getIcon(element: object): string {
|
|
328
|
-
|
|
329
|
-
for (const contribution of contributions) {
|
|
330
|
-
const value = contribution.getIcon && contribution.getIcon(element);
|
|
331
|
-
if (value === undefined) {
|
|
332
|
-
continue;
|
|
333
|
-
}
|
|
334
|
-
return value;
|
|
335
|
-
}
|
|
336
|
-
return '';
|
|
341
|
+
return this.handleRequest(element, 'getIcon') ?? '';
|
|
337
342
|
}
|
|
338
343
|
|
|
339
344
|
/**
|
|
@@ -341,15 +346,7 @@ export class LabelProvider implements FrontendApplicationContribution {
|
|
|
341
346
|
* @return the short name
|
|
342
347
|
*/
|
|
343
348
|
getName(element: object): string {
|
|
344
|
-
|
|
345
|
-
for (const contribution of contributions) {
|
|
346
|
-
const value = contribution.getName && contribution.getName(element);
|
|
347
|
-
if (value === undefined) {
|
|
348
|
-
continue;
|
|
349
|
-
}
|
|
350
|
-
return value;
|
|
351
|
-
}
|
|
352
|
-
return '<unknown>';
|
|
349
|
+
return this.handleRequest(element, 'getName') ?? '<unknown>';
|
|
353
350
|
}
|
|
354
351
|
|
|
355
352
|
/**
|
|
@@ -357,21 +354,33 @@ export class LabelProvider implements FrontendApplicationContribution {
|
|
|
357
354
|
* @return the long name
|
|
358
355
|
*/
|
|
359
356
|
getLongName(element: object): string {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
357
|
+
return this.handleRequest(element, 'getLongName') ?? '';
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Get details from the list of available {@link LabelProviderContribution} for the given element.
|
|
362
|
+
* @return the details
|
|
363
|
+
* Can be used to supplement {@link getName} in contexts that allow both a primary display field and extra detail.
|
|
364
|
+
*/
|
|
365
|
+
getDetails(element: object): string {
|
|
366
|
+
return this.handleRequest(element, 'getDetails') ?? '';
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
protected handleRequest(element: object, method: keyof Omit<LabelProviderContribution, 'canHandle' | 'onDidChange' | 'affects'>): string | undefined {
|
|
370
|
+
for (const contribution of this.findContribution(element, method)) {
|
|
371
|
+
const value = contribution[method]?.(element);
|
|
372
|
+
if (value !== undefined) {
|
|
373
|
+
return value;
|
|
365
374
|
}
|
|
366
|
-
return value;
|
|
367
375
|
}
|
|
368
|
-
return '';
|
|
369
376
|
}
|
|
370
377
|
|
|
371
|
-
protected findContribution(element: object): LabelProviderContribution[] {
|
|
372
|
-
const
|
|
378
|
+
protected findContribution(element: object, method?: keyof Omit<LabelProviderContribution, 'canHandle' | 'onDidChange' | 'affects'>): LabelProviderContribution[] {
|
|
379
|
+
const candidates = method
|
|
380
|
+
? this.contributionProvider.getContributions().filter(candidate => candidate[method])
|
|
381
|
+
: this.contributionProvider.getContributions();
|
|
382
|
+
return Prioritizeable.prioritizeAllSync(candidates, contrib =>
|
|
373
383
|
contrib.canHandle(element)
|
|
374
|
-
);
|
|
375
|
-
return prioritized.map(c => c.value);
|
|
384
|
+
).map(entry => entry.value);
|
|
376
385
|
}
|
|
377
386
|
}
|
|
@@ -356,6 +356,15 @@ export class PreferenceSchemaProvider extends PreferenceProvider {
|
|
|
356
356
|
return [][Symbol.iterator]();
|
|
357
357
|
}
|
|
358
358
|
|
|
359
|
+
getSchemaProperty(key: string): PreferenceDataProperty | undefined {
|
|
360
|
+
return this.combinedSchema.properties[key];
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
updateSchemaProperty(key: string, property: PreferenceDataProperty): void {
|
|
364
|
+
this.updateSchemaProps(key, property);
|
|
365
|
+
this.fireDidPreferenceSchemaChanged();
|
|
366
|
+
}
|
|
367
|
+
|
|
359
368
|
protected updateSchemaProps(key: string, property: PreferenceDataProperty): void {
|
|
360
369
|
this.combinedSchema.properties[key] = property;
|
|
361
370
|
|
package/src/browser/preloader.ts
CHANGED
|
@@ -58,7 +58,10 @@ async function loadBackendOS(): Promise<void> {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
function initBackground(): void {
|
|
61
|
-
|
|
61
|
+
// The default light background color is based on the `colors#editor.background` value from
|
|
62
|
+
// `packages/monaco/data/monaco-themes/vscode/dark_vs.json` and the dark background comes from the `light_vs.json`.
|
|
63
|
+
const dark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
64
|
+
const value = window.localStorage.getItem(DEFAULT_BACKGROUND_COLOR_STORAGE_KEY) || (dark ? '#1E1E1E' : '#FFFFFF');
|
|
62
65
|
const documentElement = document.documentElement;
|
|
63
66
|
documentElement.style.setProperty('--theia-editor-background', value);
|
|
64
67
|
}
|
|
@@ -1957,6 +1957,15 @@ export namespace ApplicationShell {
|
|
|
1957
1957
|
*/
|
|
1958
1958
|
export type Area = 'main' | 'top' | 'left' | 'right' | 'bottom' | 'secondaryWindow';
|
|
1959
1959
|
|
|
1960
|
+
export const areaLabels: Record<Area, string> = {
|
|
1961
|
+
main: nls.localizeByDefault('Main'),
|
|
1962
|
+
top: nls.localize('theia/shell-area/top', 'Top'),
|
|
1963
|
+
left: nls.localize('theia/shell-area/left', 'Left'),
|
|
1964
|
+
right: nls.localize('theia/shell-area/right', 'Right'),
|
|
1965
|
+
bottom: nls.localize('theia/shell-area/bottom', 'Bottom'),
|
|
1966
|
+
secondaryWindow: nls.localize('theia/shell-area/secondary', 'Secondary Window'),
|
|
1967
|
+
};
|
|
1968
|
+
|
|
1960
1969
|
/**
|
|
1961
1970
|
* The _side areas_ are those shell areas that can be collapsed and expanded,
|
|
1962
1971
|
* i.e. `left`, `right`, and `bottom`.
|
|
@@ -141,11 +141,12 @@ export class TabBarRenderer extends TabBar.Renderer {
|
|
|
141
141
|
* Render tabs with the default DOM structure, but additionally register a context menu listener.
|
|
142
142
|
* @param {SideBarRenderData} data Data used to render the tab.
|
|
143
143
|
* @param {boolean} isInSidePanel An optional check which determines if the tab is in the side-panel.
|
|
144
|
+
* @param {boolean} isPartOfHiddenTabBar An optional check which determines if the tab is in the hidden horizontal tab bar.
|
|
144
145
|
* @returns {VirtualElement} The virtual element of the rendered tab.
|
|
145
146
|
*/
|
|
146
|
-
override renderTab(data: SideBarRenderData, isInSidePanel?: boolean): VirtualElement {
|
|
147
|
+
override renderTab(data: SideBarRenderData, isInSidePanel?: boolean, isPartOfHiddenTabBar?: boolean): VirtualElement {
|
|
147
148
|
const title = data.title;
|
|
148
|
-
const id = this.createTabId(data.title);
|
|
149
|
+
const id = this.createTabId(data.title, isPartOfHiddenTabBar);
|
|
149
150
|
const key = this.createTabKey(data);
|
|
150
151
|
const style = this.createTabStyle(data);
|
|
151
152
|
const className = this.createTabClass(data);
|
|
@@ -177,8 +178,15 @@ export class TabBarRenderer extends TabBar.Renderer {
|
|
|
177
178
|
);
|
|
178
179
|
}
|
|
179
180
|
|
|
180
|
-
|
|
181
|
-
|
|
181
|
+
/**
|
|
182
|
+
* Generate ID for an entry in the tab bar
|
|
183
|
+
* @param {Title<Widget>} title Title of the widget controlled by this tab bar
|
|
184
|
+
* @param {boolean} isPartOfHiddenTabBar Tells us if this entry is part of the hidden horizontal tab bar.
|
|
185
|
+
* If yes, add a suffix to differentiate it's ID from the entry in the visible tab bar
|
|
186
|
+
* @returns {string} DOM element ID
|
|
187
|
+
*/
|
|
188
|
+
createTabId(title: Title<Widget>, isPartOfHiddenTabBar = false): string {
|
|
189
|
+
return 'shell-tab-' + title.owner.id + (isPartOfHiddenTabBar ? '-hidden' : '');
|
|
182
190
|
}
|
|
183
191
|
|
|
184
192
|
/**
|
|
@@ -904,7 +912,8 @@ export class SideTabBar extends ScrollableTabBar {
|
|
|
904
912
|
} else {
|
|
905
913
|
rd = { title, current, zIndex };
|
|
906
914
|
}
|
|
907
|
-
|
|
915
|
+
// Based on how renderTabs() is called, assume renderData will be undefined when invoked for this.hiddenContentNode
|
|
916
|
+
content[i] = renderer.renderTab(rd, true, renderData === undefined);
|
|
908
917
|
}
|
|
909
918
|
VirtualDOM.render(content, host);
|
|
910
919
|
}
|
|
@@ -20,7 +20,7 @@ import { Signal } from '@phosphor/signaling';
|
|
|
20
20
|
import { Disposable, DisposableCollection } from '../../common/disposable';
|
|
21
21
|
import { UnsafeWidgetUtilities } from '../widgets';
|
|
22
22
|
import { CorePreferences } from '../core-preferences';
|
|
23
|
-
import { Emitter, environment } from '../../common';
|
|
23
|
+
import { Emitter, Event, environment } from '../../common';
|
|
24
24
|
|
|
25
25
|
export const MAXIMIZED_CLASS = 'theia-maximized';
|
|
26
26
|
export const ACTIVE_TABBAR_CLASS = 'theia-tabBar-active';
|
|
@@ -50,6 +50,10 @@ export class TheiaDockPanel extends DockPanel {
|
|
|
50
50
|
|
|
51
51
|
protected readonly onDidToggleMaximizedEmitter = new Emitter<Widget>();
|
|
52
52
|
readonly onDidToggleMaximized = this.onDidToggleMaximizedEmitter.event;
|
|
53
|
+
protected readonly onDidChangeCurrentEmitter = new Emitter<Title<Widget> | undefined>();
|
|
54
|
+
get onDidChangeCurrent(): Event<Title<Widget> | undefined> {
|
|
55
|
+
return this.onDidChangeCurrentEmitter.event;
|
|
56
|
+
}
|
|
53
57
|
|
|
54
58
|
constructor(options?: DockPanel.IOptions,
|
|
55
59
|
protected readonly preferences?: CorePreferences
|
|
@@ -114,6 +118,7 @@ export class TheiaDockPanel extends DockPanel {
|
|
|
114
118
|
title.owner.disposed.disconnect(resetCurrent)
|
|
115
119
|
));
|
|
116
120
|
}
|
|
121
|
+
this.onDidChangeCurrentEmitter.fire(title);
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
markActiveTabBar(title?: Title<Widget>): void {
|
|
@@ -14,14 +14,23 @@
|
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
.theia-aboutDialog .about-details {
|
|
18
|
+
padding-left: 10px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.theia-aboutDialog .about-details a {
|
|
22
|
+
cursor: pointer;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
ul.theia-aboutDialog {
|
|
18
26
|
flex: 1 100%;
|
|
19
27
|
padding-bottom: calc(var(--theia-ui-padding) * 3);
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
ul.theia-aboutExtensions {
|
|
22
31
|
height: 200px;
|
|
23
32
|
overflow: hidden;
|
|
24
33
|
overflow-y: scroll;
|
|
25
34
|
list-style-type: none;
|
|
26
35
|
padding: 0;
|
|
27
|
-
|
|
36
|
+
}
|
package/src/browser/theming.ts
CHANGED
|
@@ -17,11 +17,12 @@
|
|
|
17
17
|
import { Emitter, Event } from '../common/event';
|
|
18
18
|
import { Disposable } from '../common/disposable';
|
|
19
19
|
import { FrontendApplicationConfigProvider } from './frontend-application-config-provider';
|
|
20
|
-
import { ApplicationProps } from '@theia/application-package/lib/application-props';
|
|
20
|
+
import { ApplicationProps, DefaultTheme } from '@theia/application-package/lib/application-props';
|
|
21
21
|
import { Theme, ThemeChangeEvent } from '../common/theme';
|
|
22
22
|
import { inject, injectable, postConstruct } from 'inversify';
|
|
23
23
|
import { Deferred } from '../common/promise-util';
|
|
24
|
-
import { PreferenceService } from './preferences';
|
|
24
|
+
import { PreferenceSchemaProvider, PreferenceService } from './preferences';
|
|
25
|
+
import debounce = require('lodash.debounce');
|
|
25
26
|
|
|
26
27
|
const COLOR_THEME_PREFERENCE_KEY = 'workbench.colorTheme';
|
|
27
28
|
const NO_THEME = { id: 'no-theme', label: 'Not a real theme.', type: 'dark' } as const;
|
|
@@ -31,6 +32,7 @@ export class ThemeService {
|
|
|
31
32
|
static readonly STORAGE_KEY = 'theme';
|
|
32
33
|
|
|
33
34
|
@inject(PreferenceService) protected readonly preferences: PreferenceService;
|
|
35
|
+
@inject(PreferenceSchemaProvider) protected readonly schemaProvider: PreferenceSchemaProvider;
|
|
34
36
|
|
|
35
37
|
protected themes: { [id: string]: Theme } = {};
|
|
36
38
|
protected activeTheme: Theme = NO_THEME;
|
|
@@ -48,6 +50,7 @@ export class ThemeService {
|
|
|
48
50
|
this.loadUserTheme();
|
|
49
51
|
this.preferences.ready.then(() => {
|
|
50
52
|
this.validateActiveTheme();
|
|
53
|
+
this.updateColorThemePreference();
|
|
51
54
|
this.preferences.onPreferencesChanged(changes => {
|
|
52
55
|
if (COLOR_THEME_PREFERENCE_KEY in changes) {
|
|
53
56
|
this.validateActiveTheme();
|
|
@@ -61,6 +64,7 @@ export class ThemeService {
|
|
|
61
64
|
this.themes[theme.id] = theme;
|
|
62
65
|
}
|
|
63
66
|
this.validateActiveTheme();
|
|
67
|
+
this.updateColorThemePreference();
|
|
64
68
|
return Disposable.create(() => {
|
|
65
69
|
for (const theme of themes) {
|
|
66
70
|
delete this.themes[theme.id];
|
|
@@ -68,6 +72,7 @@ export class ThemeService {
|
|
|
68
72
|
this.setCurrentTheme(this.defaultTheme.id, false);
|
|
69
73
|
}
|
|
70
74
|
}
|
|
75
|
+
this.updateColorThemePreference();
|
|
71
76
|
});
|
|
72
77
|
}
|
|
73
78
|
|
|
@@ -80,6 +85,18 @@ export class ThemeService {
|
|
|
80
85
|
}
|
|
81
86
|
}
|
|
82
87
|
|
|
88
|
+
protected updateColorThemePreference = debounce(() => this.doUpdateColorThemePreference(), 500);
|
|
89
|
+
|
|
90
|
+
protected doUpdateColorThemePreference(): void {
|
|
91
|
+
const preference = this.schemaProvider.getSchemaProperty(COLOR_THEME_PREFERENCE_KEY);
|
|
92
|
+
if (preference) {
|
|
93
|
+
const sortedThemes = this.getThemes().sort((a, b) => a.label.localeCompare(b.label));
|
|
94
|
+
preference.enum = sortedThemes.map(e => e.id);
|
|
95
|
+
preference.enumItemLabels = sortedThemes.map(e => e.label);
|
|
96
|
+
this.schemaProvider.updateSchemaProperty(COLOR_THEME_PREFERENCE_KEY, preference);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
83
100
|
getThemes(): Theme[] {
|
|
84
101
|
const result = [];
|
|
85
102
|
for (const o in this.themes) {
|
|
@@ -136,7 +153,8 @@ export class ThemeService {
|
|
|
136
153
|
* The default theme. If that is not applicable, returns with the fallback theme.
|
|
137
154
|
*/
|
|
138
155
|
get defaultTheme(): Theme {
|
|
139
|
-
return this.tryGetTheme(FrontendApplicationConfigProvider.get().defaultTheme)
|
|
156
|
+
return this.tryGetTheme(DefaultTheme.defaultForOSTheme(FrontendApplicationConfigProvider.get().defaultTheme))
|
|
157
|
+
?? this.getTheme(DefaultTheme.defaultForOSTheme(ApplicationProps.DEFAULT.frontend.config.defaultTheme));
|
|
140
158
|
}
|
|
141
159
|
|
|
142
160
|
/**
|
|
@@ -30,7 +30,7 @@ import { FrontendApplicationStateService } from './frontend-application-state';
|
|
|
30
30
|
import { ContextMenuRenderer, Anchor } from './context-menu-renderer';
|
|
31
31
|
import { parseCssMagnitude } from './browser';
|
|
32
32
|
import { TabBarToolbarRegistry, TabBarToolbarFactory, TabBarToolbar, TabBarDelegator, TabBarToolbarItem } from './shell/tab-bar-toolbar';
|
|
33
|
-
import { isEmpty } from '../common';
|
|
33
|
+
import { isEmpty, nls } from '../common';
|
|
34
34
|
import { WidgetManager } from './widget-manager';
|
|
35
35
|
import { Key } from './keys';
|
|
36
36
|
import { ProgressBarFactory } from './progress-bar-factory';
|
|
@@ -175,7 +175,7 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica
|
|
|
175
175
|
}),
|
|
176
176
|
menuRegistry.registerMenuAction([...this.contextMenuPath, '0_global'], {
|
|
177
177
|
commandId: this.globalHideCommandId,
|
|
178
|
-
label: 'Hide'
|
|
178
|
+
label: nls.localize('theia/core/hideViewContainer', 'Hide')
|
|
179
179
|
}),
|
|
180
180
|
this.onDidChangeTrackableWidgetsEmitter,
|
|
181
181
|
this.onDidChangeTrackableWidgets(() => this.decoratorService.fireDidChangeDecorations())
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2022 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 WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { inject, injectable, postConstruct } from 'inversify';
|
|
18
|
+
import { escapeRegExpCharacters } from '../../common/strings';
|
|
19
|
+
import { Emitter, Event } from '../../common/event';
|
|
20
|
+
import { CorePreferences } from '../core-preferences';
|
|
21
|
+
import { FrontendApplicationConfigProvider } from '../frontend-application-config-provider';
|
|
22
|
+
|
|
23
|
+
export const InitialWindowTitleParts = {
|
|
24
|
+
activeEditorShort: undefined,
|
|
25
|
+
activeEditorMedium: undefined,
|
|
26
|
+
activeEditorLong: undefined,
|
|
27
|
+
activeFolderShort: undefined,
|
|
28
|
+
activeFolderMedium: undefined,
|
|
29
|
+
activeFolderLong: undefined,
|
|
30
|
+
folderName: undefined,
|
|
31
|
+
folderPath: undefined,
|
|
32
|
+
rootName: undefined,
|
|
33
|
+
rootPath: undefined,
|
|
34
|
+
appName: FrontendApplicationConfigProvider.get().applicationName,
|
|
35
|
+
remoteName: undefined,
|
|
36
|
+
dirty: undefined,
|
|
37
|
+
developmentHost: undefined
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
@injectable()
|
|
41
|
+
export class WindowTitleService {
|
|
42
|
+
|
|
43
|
+
@inject(CorePreferences)
|
|
44
|
+
protected readonly preferences: CorePreferences;
|
|
45
|
+
|
|
46
|
+
protected _title = '';
|
|
47
|
+
protected titleTemplate?: string;
|
|
48
|
+
|
|
49
|
+
protected onDidChangeTitleEmitter = new Emitter<string>();
|
|
50
|
+
protected titleParts = new Map<string, string | undefined>(Object.entries(InitialWindowTitleParts));
|
|
51
|
+
protected separator = ' - ';
|
|
52
|
+
|
|
53
|
+
@postConstruct()
|
|
54
|
+
protected init(): void {
|
|
55
|
+
this.titleTemplate = this.preferences['window.title'];
|
|
56
|
+
this.separator = this.preferences['window.titleSeparator'];
|
|
57
|
+
this.updateTitle();
|
|
58
|
+
this.preferences.onPreferenceChanged(e => {
|
|
59
|
+
if (e.preferenceName === 'window.title') {
|
|
60
|
+
this.titleTemplate = e.newValue;
|
|
61
|
+
this.updateTitle();
|
|
62
|
+
} else if (e.preferenceName === 'window.titleSeparator') {
|
|
63
|
+
this.separator = e.newValue;
|
|
64
|
+
this.updateTitle();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get onDidChangeTitle(): Event<string> {
|
|
70
|
+
return this.onDidChangeTitleEmitter.event;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
get title(): string {
|
|
74
|
+
return this._title;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
update(parts: Record<string, string | undefined>): void {
|
|
78
|
+
for (const [key, value] of Object.entries(parts)) {
|
|
79
|
+
this.titleParts.set(key, value);
|
|
80
|
+
}
|
|
81
|
+
this.updateTitle();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
protected updateTitle(): void {
|
|
85
|
+
if (!this.titleTemplate) {
|
|
86
|
+
this._title = '';
|
|
87
|
+
} else {
|
|
88
|
+
let title = this.titleTemplate;
|
|
89
|
+
for (const [key, value] of this.titleParts.entries()) {
|
|
90
|
+
if (key !== 'developmentHost') {
|
|
91
|
+
const label = `$\{${key}\}`;
|
|
92
|
+
const regex = new RegExp(escapeRegExpCharacters(label), 'g');
|
|
93
|
+
title = title.replace(regex, value ?? '');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const separatedTitle = title.split('${separator}').filter(e => e.trim().length > 0);
|
|
97
|
+
this._title = separatedTitle.join(this.separator);
|
|
98
|
+
}
|
|
99
|
+
const developmentHost = this.titleParts.get('developmentHost');
|
|
100
|
+
if (developmentHost) {
|
|
101
|
+
this._title = developmentHost + this.separator + this._title;
|
|
102
|
+
}
|
|
103
|
+
document.title = this._title;
|
|
104
|
+
this.onDidChangeTitleEmitter.fire(this._title);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2022 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 WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { Widget } from '../widgets';
|
|
18
|
+
import { FrontendApplication, FrontendApplicationContribution } from '../frontend-application';
|
|
19
|
+
import { NavigatableWidget } from '../navigatable-types';
|
|
20
|
+
import { inject, injectable } from 'inversify';
|
|
21
|
+
import { WindowTitleService } from './window-title-service';
|
|
22
|
+
import { LabelProvider } from '../label-provider';
|
|
23
|
+
import { Saveable } from '../saveable';
|
|
24
|
+
import { Disposable } from '../../common';
|
|
25
|
+
|
|
26
|
+
@injectable()
|
|
27
|
+
export class WindowTitleUpdater implements FrontendApplicationContribution {
|
|
28
|
+
|
|
29
|
+
@inject(WindowTitleService)
|
|
30
|
+
protected readonly windowTitleService: WindowTitleService;
|
|
31
|
+
|
|
32
|
+
@inject(LabelProvider)
|
|
33
|
+
protected readonly labelProvider: LabelProvider;
|
|
34
|
+
|
|
35
|
+
onStart(app: FrontendApplication): void {
|
|
36
|
+
app.shell.mainPanel.onDidChangeCurrent(title => this.handleWidgetChange(title?.owner));
|
|
37
|
+
this.handleWidgetChange(app.shell.getCurrentWidget('main'));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
protected toDisposeOnWidgetChanged: Disposable = Disposable.NULL;
|
|
41
|
+
protected handleWidgetChange(widget?: Widget): void {
|
|
42
|
+
this.toDisposeOnWidgetChanged.dispose();
|
|
43
|
+
const saveable = Saveable.get(widget);
|
|
44
|
+
if (saveable) {
|
|
45
|
+
this.toDisposeOnWidgetChanged = saveable.onDirtyChanged(() => this.windowTitleService.update({ dirty: saveable.dirty ? '●' : '' }));
|
|
46
|
+
} else {
|
|
47
|
+
this.toDisposeOnWidgetChanged = Disposable.NULL;
|
|
48
|
+
}
|
|
49
|
+
this.updateTitleWidget(widget);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Updates the title of the application based on the currently opened widget.
|
|
54
|
+
*
|
|
55
|
+
* @param widget The current widget in the `main` application area. `undefined` if no widget is currently open in that area.
|
|
56
|
+
*/
|
|
57
|
+
protected updateTitleWidget(widget?: Widget): void {
|
|
58
|
+
let activeEditorLong: string | undefined;
|
|
59
|
+
let activeEditorMedium: string | undefined;
|
|
60
|
+
let activeEditorShort: string | undefined;
|
|
61
|
+
let activeFolderLong: string | undefined;
|
|
62
|
+
let activeFolderMedium: string | undefined;
|
|
63
|
+
let activeFolderShort: string | undefined;
|
|
64
|
+
let dirty: string | undefined;
|
|
65
|
+
const uri = NavigatableWidget.getUri(widget);
|
|
66
|
+
if (uri) {
|
|
67
|
+
activeEditorLong = uri.path.fsPath();
|
|
68
|
+
activeEditorMedium = this.labelProvider.getLongName(uri);
|
|
69
|
+
activeEditorShort = this.labelProvider.getName(uri);
|
|
70
|
+
const parent = uri.parent;
|
|
71
|
+
activeFolderLong = parent.path.fsPath();
|
|
72
|
+
activeFolderMedium = this.labelProvider.getLongName(parent);
|
|
73
|
+
activeFolderShort = this.labelProvider.getName(parent);
|
|
74
|
+
} else if (widget) {
|
|
75
|
+
const widgetTitle = widget.title.label;
|
|
76
|
+
activeEditorLong = widgetTitle;
|
|
77
|
+
activeEditorMedium = widgetTitle;
|
|
78
|
+
activeEditorShort = widgetTitle;
|
|
79
|
+
}
|
|
80
|
+
if (Saveable.isDirty(widget)) {
|
|
81
|
+
dirty = '●';
|
|
82
|
+
}
|
|
83
|
+
this.windowTitleService.update({
|
|
84
|
+
activeEditorLong,
|
|
85
|
+
activeEditorMedium,
|
|
86
|
+
activeEditorShort,
|
|
87
|
+
activeFolderLong,
|
|
88
|
+
activeFolderMedium,
|
|
89
|
+
activeFolderShort,
|
|
90
|
+
dirty
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
}
|
package/src/common/event.ts
CHANGED
|
@@ -307,7 +307,13 @@ export class Emitter<T = any> {
|
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
309
|
|
|
310
|
+
export type WaitUntilData<T> = Omit<T, 'waitUntil' | 'token'>;
|
|
311
|
+
|
|
310
312
|
export interface WaitUntilEvent {
|
|
313
|
+
/**
|
|
314
|
+
* A cancellation token.
|
|
315
|
+
*/
|
|
316
|
+
token: CancellationToken;
|
|
311
317
|
/**
|
|
312
318
|
* Allows to pause the event loop until the provided thenable resolved.
|
|
313
319
|
*
|
|
@@ -325,11 +331,13 @@ export namespace WaitUntilEvent {
|
|
|
325
331
|
*/
|
|
326
332
|
export async function fire<T extends WaitUntilEvent>(
|
|
327
333
|
emitter: Emitter<T>,
|
|
328
|
-
event:
|
|
329
|
-
timeout
|
|
334
|
+
event: WaitUntilData<T>,
|
|
335
|
+
timeout?: number,
|
|
336
|
+
token = CancellationToken.None
|
|
330
337
|
): Promise<void> {
|
|
331
338
|
const waitables: Promise<void>[] = [];
|
|
332
339
|
const asyncEvent = Object.assign(event, {
|
|
340
|
+
token,
|
|
333
341
|
waitUntil: (thenable: Promise<any>) => {
|
|
334
342
|
if (Object.isFrozen(waitables)) {
|
|
335
343
|
throw new Error('waitUntil cannot be called asynchronously.');
|
|
@@ -364,7 +372,7 @@ export class AsyncEmitter<T extends WaitUntilEvent> extends Emitter<T> {
|
|
|
364
372
|
/**
|
|
365
373
|
* Fire listeners async one after another.
|
|
366
374
|
*/
|
|
367
|
-
override fire(event:
|
|
375
|
+
override fire(event: WaitUntilData<T>, token: CancellationToken = CancellationToken.None,
|
|
368
376
|
promiseJoin?: (p: Promise<any>, listener: Function) => Promise<any>): Promise<void> {
|
|
369
377
|
const callbacks = this._callbacks;
|
|
370
378
|
if (!callbacks) {
|
|
@@ -377,7 +385,7 @@ export class AsyncEmitter<T extends WaitUntilEvent> extends Emitter<T> {
|
|
|
377
385
|
return this.deliveryQueue = this.deliver(listeners, event, token, promiseJoin);
|
|
378
386
|
}
|
|
379
387
|
|
|
380
|
-
protected async deliver(listeners: Callback[], event:
|
|
388
|
+
protected async deliver(listeners: Callback[], event: WaitUntilData<T>, token: CancellationToken,
|
|
381
389
|
promiseJoin?: (p: Promise<any>, listener: Function) => Promise<any>): Promise<void> {
|
|
382
390
|
for (const listener of listeners) {
|
|
383
391
|
if (token.isCancellationRequested) {
|
|
@@ -385,6 +393,7 @@ export class AsyncEmitter<T extends WaitUntilEvent> extends Emitter<T> {
|
|
|
385
393
|
}
|
|
386
394
|
const waitables: Promise<void>[] = [];
|
|
387
395
|
const asyncEvent = Object.assign(event, {
|
|
396
|
+
token,
|
|
388
397
|
waitUntil: (thenable: Promise<any>) => {
|
|
389
398
|
if (Object.isFrozen(waitables)) {
|
|
390
399
|
throw new Error('waitUntil cannot be called asynchronously.');
|
|
@@ -85,6 +85,7 @@ export interface IJSONSchema {
|
|
|
85
85
|
errorMessage?: string; // VSCode extension
|
|
86
86
|
patternErrorMessage?: string; // VSCode extension
|
|
87
87
|
deprecationMessage?: string; // VSCode extension
|
|
88
|
+
enumItemLabels?: string[]; // VSCode extension
|
|
88
89
|
enumDescriptions?: string[]; // VSCode extension
|
|
89
90
|
markdownEnumDescriptions?: string[]; // VSCode extension
|
|
90
91
|
markdownDescription?: string; // VSCode extension
|
|
@@ -120,7 +120,7 @@ export interface RpcMessageEncoder {
|
|
|
120
120
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
export const defaultMsgPack = new MsgPack({ moreTypes: true, encodeUndefinedAsNil: false, bundleStrings:
|
|
123
|
+
export const defaultMsgPack = new MsgPack({ moreTypes: true, encodeUndefinedAsNil: false, bundleStrings: false });
|
|
124
124
|
// Add custom msgpackR extension for ResponseErrors.
|
|
125
125
|
addExtension({
|
|
126
126
|
Class: ResponseError,
|
|
@@ -132,23 +132,23 @@ export class RpcProtocol {
|
|
|
132
132
|
// The last element of the request args might be a cancellation token. As these tokens are not serializable we have to remove it from the
|
|
133
133
|
// args array and the `CANCELLATION_TOKEN_KEY` string instead.
|
|
134
134
|
const cancellationToken: CancellationToken | undefined = args.length && CancellationToken.is(args[args.length - 1]) ? args.pop() : undefined;
|
|
135
|
-
if (cancellationToken && cancellationToken.isCancellationRequested) {
|
|
136
|
-
return Promise.reject(this.cancelError());
|
|
137
|
-
}
|
|
138
135
|
|
|
139
136
|
if (cancellationToken) {
|
|
140
137
|
args.push(RpcProtocol.CANCELLATION_TOKEN_KEY);
|
|
141
|
-
cancellationToken.onCancellationRequested(() => {
|
|
142
|
-
this.sendCancel(id);
|
|
143
|
-
this.pendingRequests.get(id)?.reject(this.cancelError());
|
|
144
|
-
}
|
|
145
|
-
);
|
|
146
138
|
}
|
|
139
|
+
|
|
147
140
|
this.pendingRequests.set(id, reply);
|
|
148
141
|
|
|
149
142
|
const output = this.channel.getWriteBuffer();
|
|
150
143
|
this.encoder.request(output, id, method, args);
|
|
151
144
|
output.commit();
|
|
145
|
+
|
|
146
|
+
if (cancellationToken?.isCancellationRequested) {
|
|
147
|
+
this.sendCancel(id);
|
|
148
|
+
} else {
|
|
149
|
+
cancellationToken?.onCancellationRequested(() => this.sendCancel(id));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
152
|
return reply.promise;
|
|
153
153
|
}
|
|
154
154
|
|
|
@@ -164,12 +164,6 @@ export class RpcProtocol {
|
|
|
164
164
|
output.commit();
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
cancelError(): Error {
|
|
168
|
-
const error = new Error('"Request has already been canceled by the sender"');
|
|
169
|
-
error.name = 'Cancel';
|
|
170
|
-
return error;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
167
|
protected handleCancel(id: number): void {
|
|
174
168
|
const cancellationTokenSource = this.cancellationTokenSources.get(id);
|
|
175
169
|
if (cancellationTokenSource) {
|