@theia/core 1.24.0 → 1.25.0-next.10
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 +3 -3
- package/lib/browser/common-frontend-contribution.d.ts +4 -0
- package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
- package/lib/browser/common-frontend-contribution.js +44 -4
- package/lib/browser/common-frontend-contribution.js.map +1 -1
- package/lib/browser/decorations-service.d.ts.map +1 -1
- package/lib/browser/frontend-application-module.d.ts.map +1 -1
- package/lib/browser/frontend-application-module.js +2 -0
- package/lib/browser/frontend-application-module.js.map +1 -1
- package/lib/browser/save-resource-service.d.ts +10 -5
- package/lib/browser/save-resource-service.d.ts.map +1 -1
- package/lib/browser/save-resource-service.js +28 -8
- package/lib/browser/save-resource-service.js.map +1 -1
- package/lib/browser/saveable.d.ts +1 -2
- package/lib/browser/saveable.d.ts.map +1 -1
- package/lib/browser/saveable.js +5 -10
- package/lib/browser/saveable.js.map +1 -1
- package/lib/browser/shell/application-shell.d.ts +3 -1
- package/lib/browser/shell/application-shell.d.ts.map +1 -1
- package/lib/browser/shell/application-shell.js +22 -10
- package/lib/browser/shell/application-shell.js.map +1 -1
- package/lib/browser/shell/theia-dock-panel.d.ts +2 -0
- package/lib/browser/shell/theia-dock-panel.d.ts.map +1 -1
- package/lib/browser/shell/theia-dock-panel.js +17 -1
- package/lib/browser/shell/theia-dock-panel.js.map +1 -1
- package/lib/browser/status-bar/status-bar.d.ts +4 -7
- package/lib/browser/status-bar/status-bar.d.ts.map +1 -1
- package/lib/browser/status-bar/status-bar.js +11 -4
- package/lib/browser/status-bar/status-bar.js.map +1 -1
- package/lib/browser/user-working-directory-provider.d.ts +17 -0
- package/lib/browser/user-working-directory-provider.d.ts.map +1 -0
- package/lib/browser/user-working-directory-provider.js +64 -0
- package/lib/browser/user-working-directory-provider.js.map +1 -0
- package/lib/common/accessibility.d.ts +17 -0
- package/lib/common/accessibility.d.ts.map +1 -0
- package/lib/common/accessibility.js +18 -0
- package/lib/common/accessibility.js.map +1 -0
- package/lib/common/quick-pick-service.d.ts +2 -0
- package/lib/common/quick-pick-service.d.ts.map +1 -1
- package/lib/common/quick-pick-service.js.map +1 -1
- package/lib/common/resource.d.ts +26 -0
- package/lib/common/resource.d.ts.map +1 -1
- package/lib/common/resource.js +76 -1
- package/lib/common/resource.js.map +1 -1
- package/package.json +3 -3
- package/src/browser/common-frontend-contribution.ts +44 -6
- package/src/browser/decorations-service.ts +2 -2
- package/src/browser/frontend-application-module.ts +2 -0
- package/src/browser/save-resource-service.ts +24 -10
- package/src/browser/saveable.ts +11 -9
- package/src/browser/shell/application-shell.ts +23 -9
- package/src/browser/shell/theia-dock-panel.ts +16 -0
- package/src/browser/status-bar/status-bar.tsx +14 -14
- package/src/browser/style/sidepanel.css +7 -12
- package/src/browser/style/tabs.css +14 -45
- package/src/browser/user-working-directory-provider.ts +48 -0
- package/src/common/accessibility.ts +33 -0
- package/src/common/quick-pick-service.ts +2 -0
- package/src/common/resource.ts +79 -0
|
@@ -38,6 +38,7 @@ import { waitForRevealed, waitForClosed } from '../widgets';
|
|
|
38
38
|
import { CorePreferences } from '../core-preferences';
|
|
39
39
|
import { BreadcrumbsRendererFactory } from '../breadcrumbs/breadcrumbs-renderer';
|
|
40
40
|
import { Deferred } from '../../common/promise-util';
|
|
41
|
+
import { SaveResourceService } from '../save-resource-service';
|
|
41
42
|
|
|
42
43
|
/** The class name added to ApplicationShell instances. */
|
|
43
44
|
const APPLICATION_SHELL_CLASS = 'theia-ApplicationShell';
|
|
@@ -216,7 +217,8 @@ export class ApplicationShell extends Widget {
|
|
|
216
217
|
@inject(SplitPositionHandler) protected splitPositionHandler: SplitPositionHandler,
|
|
217
218
|
@inject(FrontendApplicationStateService) protected readonly applicationStateService: FrontendApplicationStateService,
|
|
218
219
|
@inject(ApplicationShellOptions) @optional() options: RecursivePartial<ApplicationShell.Options> = {},
|
|
219
|
-
@inject(CorePreferences) protected readonly corePreferences: CorePreferences
|
|
220
|
+
@inject(CorePreferences) protected readonly corePreferences: CorePreferences,
|
|
221
|
+
@inject(SaveResourceService) protected readonly saveResourceService: SaveResourceService,
|
|
220
222
|
) {
|
|
221
223
|
super(options as Widget.IOptions);
|
|
222
224
|
}
|
|
@@ -688,6 +690,7 @@ export class ApplicationShell extends Widget {
|
|
|
688
690
|
this.collapseBottomPanel();
|
|
689
691
|
}
|
|
690
692
|
const widgets = toArray(this.bottomPanel.widgets());
|
|
693
|
+
this.bottomPanel.markActiveTabBar(widgets[0]?.title);
|
|
691
694
|
if (bottomPanel.pinned && bottomPanel.pinned.length === widgets.length) {
|
|
692
695
|
widgets.forEach((a, i) => {
|
|
693
696
|
if (bottomPanel.pinned![i]) {
|
|
@@ -704,6 +707,9 @@ export class ApplicationShell extends Widget {
|
|
|
704
707
|
this.mainPanel.restoreLayout(mainPanel);
|
|
705
708
|
this.registerWithFocusTracker(mainPanel.main);
|
|
706
709
|
const widgets = toArray(this.mainPanel.widgets());
|
|
710
|
+
// We don't store information about the last active tabbar
|
|
711
|
+
// So we simply mark the first as being active
|
|
712
|
+
this.mainPanel.markActiveTabBar(widgets[0]?.title);
|
|
707
713
|
if (mainPanelPinned && mainPanelPinned.length === widgets.length) {
|
|
708
714
|
widgets.forEach((a, i) => {
|
|
709
715
|
if (mainPanelPinned[i]) {
|
|
@@ -1070,7 +1076,11 @@ export class ApplicationShell extends Widget {
|
|
|
1070
1076
|
}
|
|
1071
1077
|
this.tracker.add(widget);
|
|
1072
1078
|
this.checkActivation(widget);
|
|
1073
|
-
Saveable.apply(
|
|
1079
|
+
Saveable.apply(
|
|
1080
|
+
widget,
|
|
1081
|
+
() => this.widgets.filter((maybeSaveable): maybeSaveable is Widget & SaveableSource => !!Saveable.get(maybeSaveable)),
|
|
1082
|
+
(toSave, options) => this.saveResourceService.save(toSave, options),
|
|
1083
|
+
);
|
|
1074
1084
|
if (ApplicationShell.TrackableWidgetProvider.is(widget)) {
|
|
1075
1085
|
for (const toTrack of widget.getTrackableWidgets()) {
|
|
1076
1086
|
this.track(toTrack);
|
|
@@ -1412,6 +1422,10 @@ export class ApplicationShell extends Widget {
|
|
|
1412
1422
|
alignment: StatusBarAlignment.RIGHT,
|
|
1413
1423
|
tooltip: 'Toggle Bottom Panel',
|
|
1414
1424
|
command: 'core.toggle.bottom.panel',
|
|
1425
|
+
accessibilityInformation: {
|
|
1426
|
+
label: 'Toggle Bottom Panel',
|
|
1427
|
+
role: 'button'
|
|
1428
|
+
},
|
|
1415
1429
|
priority: -1000
|
|
1416
1430
|
};
|
|
1417
1431
|
this.statusBar.setElement(BOTTOM_PANEL_TOGGLE_ID, element);
|
|
@@ -1831,32 +1845,32 @@ export class ApplicationShell extends Widget {
|
|
|
1831
1845
|
* Test whether the current widget is dirty.
|
|
1832
1846
|
*/
|
|
1833
1847
|
canSave(): boolean {
|
|
1834
|
-
return
|
|
1848
|
+
return this.saveResourceService.canSave(this.currentWidget);
|
|
1835
1849
|
}
|
|
1836
1850
|
|
|
1837
1851
|
/**
|
|
1838
1852
|
* Save the current widget if it is dirty.
|
|
1839
1853
|
*/
|
|
1840
1854
|
async save(options?: SaveOptions): Promise<void> {
|
|
1841
|
-
await
|
|
1855
|
+
await this.saveResourceService.save(this.currentWidget, options);
|
|
1842
1856
|
}
|
|
1843
1857
|
|
|
1844
1858
|
/**
|
|
1845
1859
|
* Test whether there is a dirty widget.
|
|
1846
1860
|
*/
|
|
1847
1861
|
canSaveAll(): boolean {
|
|
1848
|
-
return this.tracker.widgets.some(
|
|
1862
|
+
return this.tracker.widgets.some(widget => this.saveResourceService.canSave(widget));
|
|
1849
1863
|
}
|
|
1850
1864
|
|
|
1851
1865
|
/**
|
|
1852
1866
|
* Save all dirty widgets.
|
|
1853
1867
|
*/
|
|
1854
1868
|
async saveAll(options?: SaveOptions): Promise<void> {
|
|
1855
|
-
|
|
1856
|
-
if (
|
|
1857
|
-
|
|
1869
|
+
for (const widget of this.widgets) {
|
|
1870
|
+
if (this.saveResourceService.canSaveNotSaveAs(widget)) {
|
|
1871
|
+
await this.saveResourceService.save(widget, options);
|
|
1858
1872
|
}
|
|
1859
|
-
}
|
|
1873
|
+
}
|
|
1860
1874
|
}
|
|
1861
1875
|
|
|
1862
1876
|
/**
|
|
@@ -24,6 +24,7 @@ import { inject } from 'inversify';
|
|
|
24
24
|
import { Emitter, environment } from '../../common';
|
|
25
25
|
|
|
26
26
|
export const MAXIMIZED_CLASS = 'theia-maximized';
|
|
27
|
+
export const ACTIVE_TABBAR_CLASS = 'theia-tabBar-active';
|
|
27
28
|
const VISIBLE_MENU_MAXIMIZED_CLASS = 'theia-visible-menu-maximized';
|
|
28
29
|
|
|
29
30
|
export const MAIN_AREA_ID = 'theia-main-content-panel';
|
|
@@ -106,6 +107,7 @@ export class TheiaDockPanel extends DockPanel {
|
|
|
106
107
|
markAsCurrent(title: Title<Widget> | undefined): void {
|
|
107
108
|
this.toDisposeOnMarkAsCurrent.dispose();
|
|
108
109
|
this._currentTitle = title;
|
|
110
|
+
this.markActiveTabBar(title);
|
|
109
111
|
if (title) {
|
|
110
112
|
const resetCurrent = () => this.markAsCurrent(undefined);
|
|
111
113
|
title.owner.disposed.connect(resetCurrent);
|
|
@@ -115,17 +117,31 @@ export class TheiaDockPanel extends DockPanel {
|
|
|
115
117
|
}
|
|
116
118
|
}
|
|
117
119
|
|
|
120
|
+
markActiveTabBar(title?: Title<Widget>): void {
|
|
121
|
+
const tabBars = toArray(this.tabBars());
|
|
122
|
+
tabBars.forEach(tabBar => tabBar.removeClass(ACTIVE_TABBAR_CLASS));
|
|
123
|
+
const activeTabBar = title && this.findTabBar(title);
|
|
124
|
+
if (activeTabBar) {
|
|
125
|
+
activeTabBar.addClass(ACTIVE_TABBAR_CLASS);
|
|
126
|
+
} else if (tabBars.length > 0) {
|
|
127
|
+
// At least one tabbar needs to be active
|
|
128
|
+
tabBars[0].addClass(ACTIVE_TABBAR_CLASS);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
118
132
|
override addWidget(widget: Widget, options?: DockPanel.IAddOptions): void {
|
|
119
133
|
if (this.mode === 'single-document' && widget.parent === this) {
|
|
120
134
|
return;
|
|
121
135
|
}
|
|
122
136
|
super.addWidget(widget, options);
|
|
123
137
|
this.widgetAdded.emit(widget);
|
|
138
|
+
this.markActiveTabBar(widget.title);
|
|
124
139
|
}
|
|
125
140
|
|
|
126
141
|
override activateWidget(widget: Widget): void {
|
|
127
142
|
super.activateWidget(widget);
|
|
128
143
|
this.widgetActivated.emit(widget);
|
|
144
|
+
this.markActiveTabBar(widget.title);
|
|
129
145
|
}
|
|
130
146
|
|
|
131
147
|
protected override onChildRemoved(msg: Widget.ChildMessage): void {
|
|
@@ -22,6 +22,7 @@ import { ReactWidget } from '../widgets/react-widget';
|
|
|
22
22
|
import { FrontendApplicationStateService } from '../frontend-application-state';
|
|
23
23
|
import { LabelParser, LabelIcon } from '../label-parser';
|
|
24
24
|
import { PreferenceService } from '../preferences';
|
|
25
|
+
import { AccessibilityInformation } from '../../common/accessibility';
|
|
25
26
|
|
|
26
27
|
export interface StatusBarEntry {
|
|
27
28
|
/**
|
|
@@ -44,6 +45,7 @@ export interface StatusBarEntry {
|
|
|
44
45
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
45
46
|
arguments?: any[];
|
|
46
47
|
priority?: number;
|
|
48
|
+
accessibilityInformation?: AccessibilityInformation;
|
|
47
49
|
onclick?: (e: MouseEvent) => void;
|
|
48
50
|
}
|
|
49
51
|
|
|
@@ -51,13 +53,6 @@ export enum StatusBarAlignment {
|
|
|
51
53
|
LEFT, RIGHT
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
export interface StatusBarEntryAttributes {
|
|
55
|
-
className?: string;
|
|
56
|
-
title?: string;
|
|
57
|
-
style?: object;
|
|
58
|
-
onClick?: (e: MouseEvent) => void;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
56
|
export const STATUSBAR_WIDGET_FACTORY_ID = 'statusBar';
|
|
62
57
|
|
|
63
58
|
export const StatusBar = Symbol('StatusBar');
|
|
@@ -169,15 +164,15 @@ export class StatusBarImpl extends ReactWidget implements StatusBar {
|
|
|
169
164
|
};
|
|
170
165
|
}
|
|
171
166
|
|
|
172
|
-
protected createAttributes(entry: StatusBarEntry):
|
|
173
|
-
const attrs:
|
|
167
|
+
protected createAttributes(entry: StatusBarEntry): React.Attributes & React.HTMLAttributes<HTMLElement> {
|
|
168
|
+
const attrs: React.Attributes & React.HTMLAttributes<HTMLElement> = {};
|
|
174
169
|
|
|
175
170
|
if (entry.command) {
|
|
176
171
|
attrs.onClick = this.onclick(entry);
|
|
177
172
|
attrs.className = 'element hasCommand';
|
|
178
173
|
} else if (entry.onclick) {
|
|
179
174
|
attrs.onClick = e => {
|
|
180
|
-
if (entry.onclick) {
|
|
175
|
+
if (entry.onclick && e instanceof MouseEvent) {
|
|
181
176
|
entry.onclick(e);
|
|
182
177
|
}
|
|
183
178
|
};
|
|
@@ -189,15 +184,20 @@ export class StatusBarImpl extends ReactWidget implements StatusBar {
|
|
|
189
184
|
if (entry.tooltip) {
|
|
190
185
|
attrs.title = entry.tooltip;
|
|
191
186
|
}
|
|
187
|
+
if (entry.className) {
|
|
188
|
+
attrs.className += ' ' + entry.className;
|
|
189
|
+
}
|
|
190
|
+
if (entry.accessibilityInformation) {
|
|
191
|
+
attrs['aria-label'] = entry.accessibilityInformation.label;
|
|
192
|
+
attrs.role = entry.accessibilityInformation.role;
|
|
193
|
+
} else {
|
|
194
|
+
attrs['aria-label'] = [entry.text, entry.tooltip].join(', ');
|
|
195
|
+
}
|
|
192
196
|
|
|
193
197
|
attrs.style = {
|
|
194
198
|
color: entry.color || this.color
|
|
195
199
|
};
|
|
196
200
|
|
|
197
|
-
if (entry.className) {
|
|
198
|
-
attrs.className += ' ' + entry.className;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
201
|
return attrs;
|
|
202
202
|
}
|
|
203
203
|
|
|
@@ -90,19 +90,11 @@
|
|
|
90
90
|
border-top-color: transparent;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
.p-TabBar.theia-app-left .p-TabBar-tab.p-mod-current.theia-mod-active {
|
|
94
|
-
border-left: var(--theia-panel-border-width) solid var(--theia-focusBorder);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
93
|
.p-TabBar.theia-app-right .p-TabBar-tab.p-mod-current {
|
|
98
94
|
border-right: var(--theia-panel-border-width) solid var(--theia-activityBar-activeBorder);
|
|
99
95
|
border-top-color: transparent;
|
|
100
96
|
}
|
|
101
97
|
|
|
102
|
-
.p-TabBar.theia-app-right .p-TabBar-tab.p-mod-current.theia-mod-active {
|
|
103
|
-
border-right: var(--theia-panel-border-width) solid var(--theia-focusBorder);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
98
|
.p-TabBar.theia-app-sides .p-TabBar-tabLabel,
|
|
107
99
|
.p-TabBar.theia-app-sides .p-TabBar-tabCloseIcon {
|
|
108
100
|
display: none;
|
|
@@ -285,16 +277,19 @@
|
|
|
285
277
|
|
|
286
278
|
#theia-bottom-content-panel .p-TabBar-tab:not(.p-mod-current) {
|
|
287
279
|
color: var(--theia-panelTitle-inactiveForeground);
|
|
288
|
-
border-top: var(--theia-border-width) solid var(--theia-panel-background);
|
|
289
280
|
}
|
|
290
281
|
|
|
291
282
|
#theia-bottom-content-panel .p-TabBar-tab.p-mod-current {
|
|
292
283
|
color: var(--theia-panelTitle-activeForeground);
|
|
293
|
-
|
|
284
|
+
box-shadow: 0 var(--theia-border-width) 0 var(--theia-panelTitle-activeBorder) inset;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
#theia-bottom-content-panel .p-TabBar:not(.theia-tabBar-active) .p-TabBar-tab .theia-tab-icon-label {
|
|
288
|
+
color: var(--theia-tab-unfocusedInactiveForeground);
|
|
294
289
|
}
|
|
295
290
|
|
|
296
|
-
#theia-bottom-content-panel .p-TabBar-tab.p-mod-current.theia-
|
|
297
|
-
|
|
291
|
+
#theia-bottom-content-panel .p-TabBar:not(.theia-tabBar-active) .p-TabBar-tab.p-mod-current .theia-tab-icon-label {
|
|
292
|
+
color: var(--theia-tab-unfocusedActiveForeground);
|
|
298
293
|
}
|
|
299
294
|
|
|
300
295
|
/*-----------------------------------------------------------------------------
|
|
@@ -80,65 +80,34 @@
|
|
|
80
80
|
|
|
81
81
|
#theia-main-content-panel .p-TabBar .p-TabBar-tab {
|
|
82
82
|
border-right: 1px solid var(--theia-tab-border);
|
|
83
|
+
background: var(--theia-tab-inactiveBackground);
|
|
84
|
+
color: var(--theia-tab-inactiveForeground);
|
|
83
85
|
}
|
|
84
86
|
|
|
85
|
-
#theia-main-content-panel .p-TabBar .p-TabBar-tab:hover
|
|
86
|
-
background: var(--theia-tab-hoverBackground)
|
|
87
|
-
box-shadow: var(--theia-tab-hoverBorder)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
#theia-main-content-panel .p-TabBar .p-TabBar-tab:hover:not(.theia-mod-active) {
|
|
91
|
-
background: var(--theia-tab-unfocusedHoverBackground) !important;
|
|
92
|
-
box-shadow: var(--theia-tab-unfocusedHoverBorder) 0 -1px inset !important;
|
|
87
|
+
#theia-main-content-panel .p-TabBar .p-TabBar-tab:hover {
|
|
88
|
+
background: var(--theia-tab-hoverBackground);
|
|
89
|
+
box-shadow: 0 1px 0 var(--theia-tab-hoverBorder) inset;
|
|
93
90
|
}
|
|
94
91
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
border-top: 1px solid var(--theia-tab-activeModifiedBorder);
|
|
92
|
+
#theia-main-content-panel .p-TabBar:not(.theia-tabBar-active) .p-TabBar-tab:hover {
|
|
93
|
+
background: var(--theia-tab-unfocusedHoverBackground);
|
|
94
|
+
box-shadow: 0 1px 0 var(--theia-tab-unfocusedHoverBorder) inset;
|
|
99
95
|
}
|
|
100
96
|
|
|
101
|
-
#theia-main-content-panel .p-TabBar .p-TabBar-tab.p-mod-current
|
|
97
|
+
#theia-main-content-panel .p-TabBar .p-TabBar-tab.p-mod-current {
|
|
102
98
|
background: var(--theia-tab-activeBackground);
|
|
103
99
|
color: var(--theia-tab-activeForeground);
|
|
104
|
-
|
|
105
|
-
border-bottom: 1px solid var(--theia-tab-activeBorder);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/* inactive tab in an active group */
|
|
109
|
-
body.theia-editor-highlightModifiedTabs
|
|
110
|
-
#theia-main-content-panel .p-TabBar .p-TabBar-tab:not(.p-mod-current).theia-mod-active.theia-mod-dirty {
|
|
111
|
-
border-top: 1px solid var(--theia-tab-inactiveModifiedBorder);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
#theia-main-content-panel .p-TabBar .p-TabBar-tab:not(.p-mod-current).theia-mod-active {
|
|
115
|
-
background: var(--theia-tab-inactiveBackground);
|
|
116
|
-
color: var(--theia-tab-inactiveForeground);
|
|
100
|
+
box-shadow: 0 1px 0 var(--theia-tab-activeBorderTop) inset, 0 -1px 0 var(--theia-tab-activeBorder) inset;
|
|
117
101
|
}
|
|
118
102
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
#theia-main-content-panel .p-TabBar .p-TabBar-tab.p-mod-current:not(.theia-mod-active).theia-mod-dirty {
|
|
122
|
-
border-top: 1px solid var(--theia-tab-unfocusedActiveModifiedBorder);
|
|
103
|
+
#theia-main-content-panel .p-TabBar:not(.theia-tabBar-active) .p-TabBar-tab {
|
|
104
|
+
color: var(--theia-tab-unfocusedInactiveForeground);
|
|
123
105
|
}
|
|
124
106
|
|
|
125
|
-
#theia-main-content-panel .p-TabBar .p-TabBar-tab.p-mod-current
|
|
107
|
+
#theia-main-content-panel .p-TabBar:not(.theia-tabBar-active) .p-TabBar-tab.p-mod-current {
|
|
126
108
|
background: var(--theia-tab-unfocusedActiveBackground);
|
|
127
109
|
color: var(--theia-tab-unfocusedActiveForeground);
|
|
128
|
-
|
|
129
|
-
border-bottom: 1px solid var(--theia-tab-unfocusedActiveBorder);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/* inactive tab in an unfocused group */
|
|
133
|
-
body.theia-editor-highlightModifiedTabs
|
|
134
|
-
#theia-main-content-panel .p-TabBar .p-TabBar-tab:not(.p-mod-current):not(.theia-mod-active).theia-mod-dirty {
|
|
135
|
-
border-top: 1px solid var(--theia-tab-unfocusedInactiveModifiedBorder);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
#theia-main-content-panel .p-TabBar .p-TabBar-tab:not(.p-mod-current):not(.theia-mod-active) {
|
|
139
|
-
background: var(--theia-tab-inactiveBackground);
|
|
140
|
-
color: var(--theia-tab-inactiveForeground);
|
|
141
|
-
border-top: 1px solid var(--theia-tab-inactiveBackground);
|
|
110
|
+
box-shadow: 0 1px 0 var(--theia-tab-unfocusedActiveBorderTop) inset, 0 -1px 0 var(--theia-tab-unfocusedActiveBorder) inset;
|
|
142
111
|
}
|
|
143
112
|
|
|
144
113
|
.p-TabBar.theia-app-centers {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2022 Ericsson 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 } from 'inversify';
|
|
18
|
+
import URI from '../common/uri';
|
|
19
|
+
import { MaybePromise, SelectionService, UriSelection } from '../common';
|
|
20
|
+
import { EnvVariablesServer } from '../common/env-variables';
|
|
21
|
+
|
|
22
|
+
@injectable()
|
|
23
|
+
export class UserWorkingDirectoryProvider {
|
|
24
|
+
@inject(SelectionService) protected readonly selectionService: SelectionService;
|
|
25
|
+
@inject(EnvVariablesServer) protected readonly envVariables: EnvVariablesServer;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @returns A {@link URI} that represents a good guess about the directory in which the user is currently operating.
|
|
29
|
+
*
|
|
30
|
+
* Factors considered may include the current widget, current selection, user home directory, or other application state.
|
|
31
|
+
*/
|
|
32
|
+
async getUserWorkingDir(): Promise<URI> {
|
|
33
|
+
return await this.getFromSelection()
|
|
34
|
+
?? this.getFromUserHome();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
protected getFromSelection(): MaybePromise<URI | undefined> {
|
|
38
|
+
return this.ensureIsDirectory(UriSelection.getUri(this.selectionService.selection));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
protected getFromUserHome(): MaybePromise<URI> {
|
|
42
|
+
return this.envVariables.getHomeDirUri().then(home => new URI(home));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
protected ensureIsDirectory(uri?: URI): MaybePromise<URI | undefined> {
|
|
46
|
+
return uri?.parent;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2022 STMicroelectronics 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
|
+
/**
|
|
18
|
+
* Accessibility information which controls screen reader behavior.
|
|
19
|
+
*/
|
|
20
|
+
export interface AccessibilityInformation {
|
|
21
|
+
/**
|
|
22
|
+
* Label to be read out by a screen reader once the item has focus.
|
|
23
|
+
*/
|
|
24
|
+
readonly label: string;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Role of the widget which defines how a screen reader interacts with it.
|
|
28
|
+
* The role should be set in special cases when for example a tree-like element behaves like a checkbox.
|
|
29
|
+
* If role is not specified the editor will pick the appropriate role automatically.
|
|
30
|
+
* More about aria roles can be found here https://w3c.github.io/aria/#widget_roles
|
|
31
|
+
*/
|
|
32
|
+
readonly role?: string;
|
|
33
|
+
}
|
|
@@ -201,6 +201,7 @@ export interface QuickPick<T extends QuickPickItemOrSeparator> extends QuickInpu
|
|
|
201
201
|
canSelectMany: boolean;
|
|
202
202
|
matchOnDescription: boolean;
|
|
203
203
|
matchOnDetail: boolean;
|
|
204
|
+
keepScrollPosition: boolean;
|
|
204
205
|
readonly onDidAccept: Event<{ inBackground: boolean } | undefined>;
|
|
205
206
|
readonly onDidChangeValue: Event<string>;
|
|
206
207
|
readonly onDidTriggerButton: Event<QuickInputButton>;
|
|
@@ -261,6 +262,7 @@ export interface QuickPickOptions<T extends QuickPickItemOrSeparator> {
|
|
|
261
262
|
matchOnDetail?: boolean;
|
|
262
263
|
matchOnLabel?: boolean;
|
|
263
264
|
sortByLabel?: boolean;
|
|
265
|
+
keepScrollPosition?: boolean;
|
|
264
266
|
autoFocusOnList?: boolean;
|
|
265
267
|
ignoreFocusOut?: boolean;
|
|
266
268
|
valueSelection?: Readonly<[number, number]>;
|
package/src/common/resource.ts
CHANGED
|
@@ -317,3 +317,82 @@ export class InMemoryTextResourceResolver implements ResourceResolver {
|
|
|
317
317
|
return new InMemoryTextResource(uri);
|
|
318
318
|
}
|
|
319
319
|
}
|
|
320
|
+
|
|
321
|
+
export const UNTITLED_SCHEME = 'untitled';
|
|
322
|
+
|
|
323
|
+
let untitledResourceSequenceIndex = 0;
|
|
324
|
+
|
|
325
|
+
@injectable()
|
|
326
|
+
export class UntitledResourceResolver implements ResourceResolver {
|
|
327
|
+
|
|
328
|
+
protected readonly resources = new Map<string, UntitledResource>();
|
|
329
|
+
|
|
330
|
+
async resolve(uri: URI): Promise<UntitledResource> {
|
|
331
|
+
if (uri.scheme !== UNTITLED_SCHEME) {
|
|
332
|
+
throw new Error('The given uri is not untitled file uri: ' + uri);
|
|
333
|
+
} else {
|
|
334
|
+
const untitledResource = this.resources.get(uri.toString());
|
|
335
|
+
if (!untitledResource) {
|
|
336
|
+
return this.createUntitledResource('', '', uri);
|
|
337
|
+
} else {
|
|
338
|
+
return untitledResource;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async createUntitledResource(content?: string, extension?: string, uri?: URI): Promise<UntitledResource> {
|
|
344
|
+
return new UntitledResource(this.resources, uri ? uri : new URI().withScheme(UNTITLED_SCHEME).withPath(`/Untitled-${untitledResourceSequenceIndex++}${extension ?? ''}`),
|
|
345
|
+
content);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export class UntitledResource implements Resource {
|
|
350
|
+
|
|
351
|
+
protected readonly onDidChangeContentsEmitter = new Emitter<void>();
|
|
352
|
+
get onDidChangeContents(): Event<void> {
|
|
353
|
+
return this.onDidChangeContentsEmitter.event;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
constructor(private resources: Map<string, UntitledResource>, public uri: URI, private content?: string) {
|
|
357
|
+
this.resources.set(this.uri.toString(), this);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
dispose(): void {
|
|
361
|
+
this.resources.delete(this.uri.toString());
|
|
362
|
+
this.onDidChangeContentsEmitter.dispose();
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
async readContents(options?: { encoding?: string | undefined; } | undefined): Promise<string> {
|
|
366
|
+
if (this.content) {
|
|
367
|
+
return this.content;
|
|
368
|
+
} else {
|
|
369
|
+
return '';
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
async saveContents(content: string, options?: { encoding?: string, overwriteEncoding?: boolean }): Promise<void> {
|
|
374
|
+
// This function must exist to ensure readOnly is false for the Monaco editor.
|
|
375
|
+
// However it should not be called because saving 'untitled' is always processed as 'Save As'.
|
|
376
|
+
throw Error('Untitled resources cannot be saved.');
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
protected fireDidChangeContents(): void {
|
|
380
|
+
this.onDidChangeContentsEmitter.fire(undefined);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
get version(): ResourceVersion | undefined {
|
|
384
|
+
return undefined;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
get encoding(): string | undefined {
|
|
388
|
+
return undefined;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
export function createUntitledURI(extension?: string, parent?: URI): URI {
|
|
393
|
+
const name = `Untitled-${untitledResourceSequenceIndex++}${extension ?? ''}`;
|
|
394
|
+
if (parent) {
|
|
395
|
+
return parent.resolve(name).withScheme(UNTITLED_SCHEME);
|
|
396
|
+
}
|
|
397
|
+
return new URI().resolve(name).withScheme(UNTITLED_SCHEME);
|
|
398
|
+
}
|