@theia/core 1.53.0-next.6 → 1.53.0-next.64
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 -7
- package/i18n/nls.cs.json +30 -0
- package/i18n/nls.de.json +30 -0
- package/i18n/nls.es.json +30 -0
- package/i18n/nls.fr.json +30 -0
- package/i18n/nls.hu.json +30 -0
- package/i18n/nls.it.json +30 -0
- package/i18n/nls.ja.json +30 -0
- package/i18n/nls.json +31 -1
- package/i18n/nls.ko.json +582 -0
- package/i18n/nls.pl.json +30 -0
- package/i18n/nls.pt-br.json +30 -0
- package/i18n/nls.ru.json +30 -0
- package/i18n/nls.tr.json +582 -0
- package/i18n/nls.zh-cn.json +30 -0
- package/i18n/nls.zh-tw.json +582 -0
- package/lib/browser/authentication-service.d.ts +15 -14
- package/lib/browser/authentication-service.d.ts.map +1 -1
- package/lib/browser/authentication-service.js +5 -5
- package/lib/browser/authentication-service.js.map +1 -1
- package/lib/browser/catalog.json +6937 -0
- package/lib/browser/context-key-service.d.ts +3 -2
- package/lib/browser/context-key-service.d.ts.map +1 -1
- package/lib/browser/context-key-service.js.map +1 -1
- package/lib/browser/core-preferences.d.ts.map +1 -1
- package/lib/browser/core-preferences.js +9 -0
- package/lib/browser/core-preferences.js.map +1 -1
- package/lib/browser/frontend-application-module.d.ts.map +1 -1
- package/lib/browser/frontend-application-module.js.map +1 -1
- package/lib/browser/json-schema-store.d.ts +0 -3
- package/lib/browser/json-schema-store.d.ts.map +1 -1
- package/lib/browser/json-schema-store.js +2 -12
- package/lib/browser/json-schema-store.js.map +1 -1
- package/lib/browser/open-with-service.d.ts +13 -1
- package/lib/browser/open-with-service.d.ts.map +1 -1
- package/lib/browser/open-with-service.js +48 -9
- package/lib/browser/open-with-service.js.map +1 -1
- package/lib/browser/opener-service.d.ts +8 -0
- package/lib/browser/opener-service.d.ts.map +1 -1
- package/lib/browser/opener-service.js +18 -3
- package/lib/browser/opener-service.js.map +1 -1
- package/lib/browser/saveable-service.d.ts.map +1 -1
- package/lib/browser/saveable-service.js +6 -2
- package/lib/browser/saveable-service.js.map +1 -1
- package/lib/browser/saveable.d.ts +17 -1
- package/lib/browser/saveable.d.ts.map +1 -1
- package/lib/browser/saveable.js +62 -1
- package/lib/browser/saveable.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.d.ts +5 -4
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.d.ts.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js +2 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.d.ts +6 -16
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.d.ts.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js +12 -29
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.d.ts +43 -78
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.d.ts.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.js +8 -39
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.js.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts +10 -10
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.d.ts.map +1 -1
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js +43 -32
- package/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar.js.map +1 -1
- package/lib/browser/view-container.d.ts +2 -2
- package/lib/browser/view-container.d.ts.map +1 -1
- package/lib/browser/view-container.js.map +1 -1
- package/lib/browser/widget-open-handler.d.ts +4 -1
- package/lib/browser/widget-open-handler.d.ts.map +1 -1
- package/lib/browser/widget-open-handler.js.map +1 -1
- package/lib/browser/widgets/extractable-widget.js +1 -1
- package/lib/browser/widgets/extractable-widget.js.map +1 -1
- package/lib/browser/widgets/index.d.ts +1 -0
- package/lib/browser/widgets/index.d.ts.map +1 -1
- package/lib/browser/widgets/index.js +1 -0
- package/lib/browser/widgets/index.js.map +1 -1
- package/lib/browser/widgets/split-widget.d.ts +45 -0
- package/lib/browser/widgets/split-widget.d.ts.map +1 -0
- package/lib/browser/widgets/split-widget.js +126 -0
- package/lib/browser/widgets/split-widget.js.map +1 -0
- package/lib/common/event.d.ts +2 -0
- package/lib/common/event.d.ts.map +1 -1
- package/lib/common/event.js +4 -0
- package/lib/common/event.js.map +1 -1
- package/lib/common/glob.d.ts +4 -4
- package/lib/common/json-schema.d.ts +2 -0
- package/lib/common/json-schema.d.ts.map +1 -1
- package/lib/common/menu/menu-types.d.ts.map +1 -1
- package/lib/common/menu/menu-types.js.map +1 -1
- package/lib/electron-browser/electron-uri-handler.d.ts +6 -0
- package/lib/electron-browser/electron-uri-handler.d.ts.map +1 -0
- package/lib/electron-browser/electron-uri-handler.js +49 -0
- package/lib/electron-browser/electron-uri-handler.js.map +1 -0
- package/lib/electron-browser/menu/electron-main-menu-factory.d.ts +1 -1
- package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
- package/lib/electron-browser/menu/electron-main-menu-factory.js +6 -6
- package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
- package/lib/electron-browser/preload.d.ts.map +1 -1
- package/lib/electron-browser/preload.js +12 -0
- package/lib/electron-browser/preload.js.map +1 -1
- package/lib/electron-browser/window/electron-window-module.d.ts.map +1 -1
- package/lib/electron-browser/window/electron-window-module.js +3 -0
- package/lib/electron-browser/window/electron-window-module.js.map +1 -1
- package/lib/electron-browser/window/external-app-open-handler.js +1 -1
- package/lib/electron-browser/window/external-app-open-handler.js.map +1 -1
- package/lib/electron-common/electron-api.d.ts +2 -0
- package/lib/electron-common/electron-api.d.ts.map +1 -1
- package/lib/electron-common/electron-api.js +2 -1
- package/lib/electron-common/electron-api.js.map +1 -1
- package/lib/electron-main/electron-api-main.d.ts +2 -0
- package/lib/electron-main/electron-api-main.d.ts.map +1 -1
- package/lib/electron-main/electron-api-main.js +27 -3
- package/lib/electron-main/electron-api-main.js.map +1 -1
- package/lib/electron-main/electron-main-application.d.ts +5 -3
- package/lib/electron-main/electron-main-application.d.ts.map +1 -1
- package/lib/electron-main/electron-main-application.js +57 -14
- package/lib/electron-main/electron-main-application.js.map +1 -1
- package/lib/electron-main/theia-electron-window.d.ts +1 -0
- package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
- package/lib/electron-main/theia-electron-window.js +3 -0
- package/lib/electron-main/theia-electron-window.js.map +1 -1
- package/lib/node/i18n/theia-localization-contribution.d.ts.map +1 -1
- package/lib/node/i18n/theia-localization-contribution.js +12 -8
- package/lib/node/i18n/theia-localization-contribution.js.map +1 -1
- package/package.json +10 -8
- package/src/browser/authentication-service.ts +18 -19
- package/src/browser/context-key-service.ts +3 -3
- package/src/browser/core-preferences.ts +9 -0
- package/src/browser/frontend-application-module.ts +0 -1
- package/src/browser/json-schema-store.ts +2 -11
- package/src/browser/open-with-service.ts +54 -7
- package/src/browser/opener-service.ts +25 -2
- package/src/browser/saveable-service.ts +6 -2
- package/src/browser/saveable.ts +69 -1
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-menu-adapters.ts +3 -3
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-registry.ts +19 -33
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar-types.ts +66 -124
- package/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.tsx +42 -27
- package/src/browser/style/index.css +1 -0
- package/src/browser/style/split-widget.css +38 -0
- package/src/browser/style/tabs.css +13 -24
- package/src/browser/style/view-container.css +0 -7
- package/src/browser/view-container.ts +2 -2
- package/src/browser/widget-open-handler.ts +4 -1
- package/src/browser/widgets/extractable-widget.ts +1 -1
- package/src/browser/widgets/index.ts +1 -0
- package/src/browser/widgets/split-widget.ts +163 -0
- package/src/common/event.ts +6 -0
- package/src/common/glob.ts +4 -4
- package/src/common/json-schema.ts +2 -0
- package/src/common/menu/menu-types.ts +1 -0
- package/src/electron-browser/electron-uri-handler.ts +42 -0
- package/src/electron-browser/menu/electron-main-menu-factory.ts +7 -6
- package/src/electron-browser/preload.ts +16 -1
- package/src/electron-browser/window/electron-window-module.ts +3 -0
- package/src/electron-browser/window/external-app-open-handler.ts +1 -1
- package/src/electron-common/electron-api.ts +3 -0
- package/src/electron-main/electron-api-main.ts +31 -5
- package/src/electron-main/electron-main-application.ts +62 -20
- package/src/electron-main/theia-electron-window.ts +5 -0
- package/src/node/i18n/theia-localization-contribution.ts +12 -8
- package/i18n/nls.pt-pt.json +0 -552
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { injectable } from 'inversify';
|
|
18
18
|
import { Emitter, Event } from '../common/event';
|
|
19
|
+
import { Disposable } from '../common';
|
|
19
20
|
|
|
20
21
|
export type ContextKeyValue = null | undefined | boolean | number | string
|
|
21
22
|
| Array<null | undefined | boolean | number | string>
|
|
@@ -83,11 +84,10 @@ export interface ContextKeyService extends ContextMatcher {
|
|
|
83
84
|
setContext(key: string, value: unknown): void;
|
|
84
85
|
}
|
|
85
86
|
|
|
86
|
-
export type ScopedValueStore = Omit<ContextKeyService, 'onDidChange' | 'match' | 'parseKeys' | 'with' | 'createOverlay'
|
|
87
|
+
export type ScopedValueStore = Omit<ContextKeyService, 'onDidChange' | 'match' | 'parseKeys' | 'with' | 'createOverlay'> & Disposable;
|
|
87
88
|
|
|
88
89
|
@injectable()
|
|
89
90
|
export class ContextKeyServiceDummyImpl implements ContextKeyService {
|
|
90
|
-
|
|
91
91
|
protected readonly onDidChangeEmitter = new Emitter<ContextKeyChangeEvent>();
|
|
92
92
|
readonly onDidChange = this.onDidChangeEmitter.event;
|
|
93
93
|
protected fireDidChange(event: ContextKeyChangeEvent): void {
|
|
@@ -122,7 +122,7 @@ export class ContextKeyServiceDummyImpl implements ContextKeyService {
|
|
|
122
122
|
/**
|
|
123
123
|
* Details should implemented by an extension, e.g. by the monaco extension.
|
|
124
124
|
*/
|
|
125
|
-
createScoped(target: HTMLElement):
|
|
125
|
+
createScoped(target: HTMLElement): ScopedValueStore {
|
|
126
126
|
return this;
|
|
127
127
|
}
|
|
128
128
|
|
|
@@ -281,6 +281,15 @@ export const corePreferenceSchema: PreferenceSchema = {
|
|
|
281
281
|
default: 200,
|
|
282
282
|
minimum: 10,
|
|
283
283
|
description: nls.localize('theia/core/tabDefaultSize', 'Specifies the default size for tabs.')
|
|
284
|
+
},
|
|
285
|
+
'workbench.editorAssociations': {
|
|
286
|
+
type: 'object',
|
|
287
|
+
markdownDescription: nls.localizeByDefault('Configure [glob patterns](https://aka.ms/vscode-glob-patterns) to editors (for example `"*.hex": "hexEditor.hexedit"`). These have precedence over the default behavior.'),
|
|
288
|
+
patternProperties: {
|
|
289
|
+
'.*': {
|
|
290
|
+
type: 'string'
|
|
291
|
+
}
|
|
292
|
+
}
|
|
284
293
|
}
|
|
285
294
|
}
|
|
286
295
|
};
|
|
@@ -465,7 +465,6 @@ export const frontendApplicationModule = new ContainerModule((bind, _unbind, _is
|
|
|
465
465
|
bind(FrontendApplicationContribution).toService(StylingService);
|
|
466
466
|
|
|
467
467
|
bind(SecondaryWindowHandler).toSelf().inSingletonScope();
|
|
468
|
-
|
|
469
468
|
bind(ViewColumnService).toSelf().inSingletonScope();
|
|
470
469
|
|
|
471
470
|
bind(UndoRedoHandlerService).toSelf().inSingletonScope();
|
|
@@ -18,9 +18,7 @@ import { injectable, inject, named } from 'inversify';
|
|
|
18
18
|
import { ContributionProvider } from '../common/contribution-provider';
|
|
19
19
|
import { FrontendApplicationContribution } from './frontend-application-contribution';
|
|
20
20
|
import { MaybePromise } from '../common';
|
|
21
|
-
import { Endpoint } from './endpoint';
|
|
22
21
|
import { timeout, Deferred } from '../common/promise-util';
|
|
23
|
-
import { RequestContext, RequestService } from '@theia/request';
|
|
24
22
|
|
|
25
23
|
export interface JsonSchemaConfiguration {
|
|
26
24
|
fileMatch: string | string[];
|
|
@@ -95,16 +93,9 @@ export class JsonSchemaStore implements FrontendApplicationContribution {
|
|
|
95
93
|
|
|
96
94
|
@injectable()
|
|
97
95
|
export class DefaultJsonSchemaContribution implements JsonSchemaContribution {
|
|
98
|
-
|
|
99
|
-
@inject(RequestService)
|
|
100
|
-
protected readonly requestService: RequestService;
|
|
101
|
-
|
|
102
|
-
protected readonly jsonSchemaUrl = `${new Endpoint().httpScheme}//schemastore.org/api/json/catalog.json`;
|
|
103
|
-
|
|
104
96
|
async registerSchemas(context: JsonSchemaRegisterContext): Promise<void> {
|
|
105
|
-
const
|
|
106
|
-
const
|
|
107
|
-
for (const s of schemas) {
|
|
97
|
+
const catalog = require('./catalog.json') as { schemas: DefaultJsonSchemaContribution.SchemaData[] };
|
|
98
|
+
for (const s of catalog.schemas) {
|
|
108
99
|
if (s.fileMatch) {
|
|
109
100
|
context.registerSchema({
|
|
110
101
|
fileMatch: s.fileMatch,
|
|
@@ -19,7 +19,9 @@ import { Disposable } from '../common/disposable';
|
|
|
19
19
|
import { nls } from '../common/nls';
|
|
20
20
|
import { MaybePromise } from '../common/types';
|
|
21
21
|
import { URI } from '../common/uri';
|
|
22
|
-
import { QuickInputService } from './quick-input';
|
|
22
|
+
import { QuickInputService, QuickPickItem, QuickPickItemOrSeparator } from './quick-input';
|
|
23
|
+
import { PreferenceScope, PreferenceService } from './preferences';
|
|
24
|
+
import { getDefaultHandler } from './opener-service';
|
|
23
25
|
|
|
24
26
|
export interface OpenWithHandler {
|
|
25
27
|
/**
|
|
@@ -46,6 +48,11 @@ export interface OpenWithHandler {
|
|
|
46
48
|
* A returned value indicating a priority of this handler.
|
|
47
49
|
*/
|
|
48
50
|
canHandle(uri: URI): number;
|
|
51
|
+
/**
|
|
52
|
+
* Test whether this handler and open the given URI
|
|
53
|
+
* and return the order of this handler in the list.
|
|
54
|
+
*/
|
|
55
|
+
getOrder?(uri: URI): number;
|
|
49
56
|
/**
|
|
50
57
|
* Open a widget for the given URI and options.
|
|
51
58
|
* Resolve to an opened widget or undefined, e.g. if a page is opened.
|
|
@@ -54,12 +61,19 @@ export interface OpenWithHandler {
|
|
|
54
61
|
open(uri: URI): MaybePromise<object | undefined>;
|
|
55
62
|
}
|
|
56
63
|
|
|
64
|
+
export interface OpenWithQuickPickItem extends QuickPickItem {
|
|
65
|
+
handler: OpenWithHandler;
|
|
66
|
+
}
|
|
67
|
+
|
|
57
68
|
@injectable()
|
|
58
69
|
export class OpenWithService {
|
|
59
70
|
|
|
60
71
|
@inject(QuickInputService)
|
|
61
72
|
protected readonly quickInputService: QuickInputService;
|
|
62
73
|
|
|
74
|
+
@inject(PreferenceService)
|
|
75
|
+
protected readonly preferenceService: PreferenceService;
|
|
76
|
+
|
|
63
77
|
protected readonly handlers: OpenWithHandler[] = [];
|
|
64
78
|
|
|
65
79
|
registerHandler(handler: OpenWithHandler): Disposable {
|
|
@@ -73,17 +87,50 @@ export class OpenWithService {
|
|
|
73
87
|
}
|
|
74
88
|
|
|
75
89
|
async openWith(uri: URI): Promise<object | undefined> {
|
|
90
|
+
// Clone the object, because all objects returned by the preferences service are frozen.
|
|
91
|
+
const associations: Record<string, unknown> = { ...this.preferenceService.get('workbench.editorAssociations') };
|
|
92
|
+
const ext = `*${uri.path.ext}`;
|
|
76
93
|
const handlers = this.getHandlers(uri);
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
94
|
+
const ordered = handlers.slice().sort((a, b) => this.getOrder(b, uri) - this.getOrder(a, uri));
|
|
95
|
+
const defaultHandler = getDefaultHandler(uri, this.preferenceService) ?? handlers[0]?.id;
|
|
96
|
+
const items = this.getQuickPickItems(ordered, defaultHandler);
|
|
97
|
+
// Only offer to select a default editor when the file has a file extension
|
|
98
|
+
const extraItems: QuickPickItemOrSeparator[] = uri.path.ext ? [{
|
|
99
|
+
type: 'separator'
|
|
100
|
+
}, {
|
|
101
|
+
label: nls.localizeByDefault("Configure default editor for '{0}'...", ext)
|
|
102
|
+
}] : [];
|
|
103
|
+
const result = await this.quickInputService.pick<OpenWithQuickPickItem | { label: string }>([...items, ...extraItems], {
|
|
82
104
|
placeHolder: nls.localizeByDefault("Select editor for '{0}'", uri.path.base)
|
|
83
105
|
});
|
|
84
106
|
if (result) {
|
|
85
|
-
|
|
107
|
+
if ('handler' in result) {
|
|
108
|
+
return result.handler.open(uri);
|
|
109
|
+
} else if (result.label) {
|
|
110
|
+
const configureResult = await this.quickInputService.pick(items, {
|
|
111
|
+
placeHolder: nls.localizeByDefault("Select new default editor for '{0}'", ext)
|
|
112
|
+
});
|
|
113
|
+
if (configureResult) {
|
|
114
|
+
associations[ext] = configureResult.handler.id;
|
|
115
|
+
this.preferenceService.set('workbench.editorAssociations', associations, PreferenceScope.User);
|
|
116
|
+
return configureResult.handler.open(uri);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
86
119
|
}
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
protected getQuickPickItems(handlers: OpenWithHandler[], defaultHandler?: string): OpenWithQuickPickItem[] {
|
|
124
|
+
return handlers.map(handler => ({
|
|
125
|
+
handler,
|
|
126
|
+
label: handler.label ?? handler.id,
|
|
127
|
+
detail: handler.providerName ?? '',
|
|
128
|
+
description: handler.id === defaultHandler ? nls.localizeByDefault('Default') : undefined
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
protected getOrder(handler: OpenWithHandler, uri: URI): number {
|
|
133
|
+
return handler.getOrder ? handler.getOrder(uri) : handler.canHandle(uri);
|
|
87
134
|
}
|
|
88
135
|
|
|
89
136
|
getHandlers(uri: URI): OpenWithHandler[] {
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
import { named, injectable, inject } from 'inversify';
|
|
18
18
|
import URI from '../common/uri';
|
|
19
19
|
import { ContributionProvider, Prioritizeable, MaybePromise, Emitter, Event, Disposable } from '../common';
|
|
20
|
+
import { PreferenceService } from './preferences';
|
|
21
|
+
import { match } from '../common/glob';
|
|
20
22
|
|
|
21
23
|
export interface OpenerOptions {
|
|
22
24
|
}
|
|
@@ -79,6 +81,12 @@ export interface OpenerService {
|
|
|
79
81
|
* Add open handler i.e. for custom editors
|
|
80
82
|
*/
|
|
81
83
|
addHandler?(openHandler: OpenHandler): Disposable;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Remove open handler
|
|
87
|
+
*/
|
|
88
|
+
removeHandler?(openHandler: OpenHandler): void;
|
|
89
|
+
|
|
82
90
|
/**
|
|
83
91
|
* Event that fires when a new opener is added or removed.
|
|
84
92
|
*/
|
|
@@ -90,6 +98,17 @@ export async function open(openerService: OpenerService, uri: URI, options?: Ope
|
|
|
90
98
|
return opener.open(uri, options);
|
|
91
99
|
}
|
|
92
100
|
|
|
101
|
+
export function getDefaultHandler(uri: URI, preferenceService: PreferenceService): string | undefined {
|
|
102
|
+
const associations = preferenceService.get('workbench.editorAssociations', {});
|
|
103
|
+
const defaultHandler = Object.entries(associations).find(([key]) => match(key, uri.path.base))?.[1];
|
|
104
|
+
if (typeof defaultHandler === 'string') {
|
|
105
|
+
return defaultHandler;
|
|
106
|
+
}
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export const defaultHandlerPriority = 100_000;
|
|
111
|
+
|
|
93
112
|
@injectable()
|
|
94
113
|
export class DefaultOpenerService implements OpenerService {
|
|
95
114
|
// Collection of open-handlers for custom-editor contributions.
|
|
@@ -108,11 +127,15 @@ export class DefaultOpenerService implements OpenerService {
|
|
|
108
127
|
this.onDidChangeOpenersEmitter.fire();
|
|
109
128
|
|
|
110
129
|
return Disposable.create(() => {
|
|
111
|
-
this.
|
|
112
|
-
this.onDidChangeOpenersEmitter.fire();
|
|
130
|
+
this.removeHandler(openHandler);
|
|
113
131
|
});
|
|
114
132
|
}
|
|
115
133
|
|
|
134
|
+
removeHandler(openHandler: OpenHandler): void {
|
|
135
|
+
this.customEditorOpenHandlers.splice(this.customEditorOpenHandlers.indexOf(openHandler), 1);
|
|
136
|
+
this.onDidChangeOpenersEmitter.fire();
|
|
137
|
+
}
|
|
138
|
+
|
|
116
139
|
async getOpener(uri: URI, options?: OpenerOptions): Promise<OpenHandler> {
|
|
117
140
|
const handlers = await this.prioritize(uri, options);
|
|
118
141
|
if (handlers.length >= 1) {
|
|
@@ -174,7 +174,10 @@ export class SaveableService implements FrontendApplicationContribution {
|
|
|
174
174
|
setDirty(saveableWidget, saveable.dirty);
|
|
175
175
|
saveable.onDirtyChanged(() => setDirty(saveableWidget, saveable.dirty));
|
|
176
176
|
const closeWithSaving = this.createCloseWithSaving();
|
|
177
|
-
const closeWithoutSaving = () =>
|
|
177
|
+
const closeWithoutSaving = async () => {
|
|
178
|
+
const revert = Saveable.closingWidgetWouldLoseSaveable(saveableWidget, Array.from(this.saveThrottles.keys()));
|
|
179
|
+
await this.closeWithoutSaving(saveableWidget, revert);
|
|
180
|
+
};
|
|
178
181
|
Object.assign(saveableWidget, {
|
|
179
182
|
closeWithoutSaving,
|
|
180
183
|
closeWithSaving,
|
|
@@ -224,7 +227,8 @@ export class SaveableService implements FrontendApplicationContribution {
|
|
|
224
227
|
}
|
|
225
228
|
const notLastWithDocument = !Saveable.closingWidgetWouldLoseSaveable(widget, Array.from(this.saveThrottles.keys()));
|
|
226
229
|
if (notLastWithDocument) {
|
|
227
|
-
|
|
230
|
+
await widget.closeWithoutSaving(false);
|
|
231
|
+
return undefined;
|
|
228
232
|
}
|
|
229
233
|
if (options && options.shouldSave) {
|
|
230
234
|
return options.shouldSave();
|
package/src/browser/saveable.ts
CHANGED
|
@@ -21,7 +21,7 @@ import { MaybePromise } from '../common/types';
|
|
|
21
21
|
import { Key } from './keyboard/keys';
|
|
22
22
|
import { AbstractDialog } from './dialogs';
|
|
23
23
|
import { nls } from '../common/nls';
|
|
24
|
-
import { DisposableCollection, isObject } from '../common';
|
|
24
|
+
import { Disposable, DisposableCollection, isObject } from '../common';
|
|
25
25
|
import { BinaryBuffer } from '../common/buffer';
|
|
26
26
|
|
|
27
27
|
export type AutoSaveMode = 'off' | 'afterDelay' | 'onFocusChange' | 'onWindowChange';
|
|
@@ -112,6 +112,74 @@ export class DelegatingSaveable implements Saveable {
|
|
|
112
112
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
export class CompositeSaveable implements Saveable {
|
|
116
|
+
protected isDirty = false;
|
|
117
|
+
protected readonly onDirtyChangedEmitter = new Emitter<void>();
|
|
118
|
+
protected readonly onContentChangedEmitter = new Emitter<void>();
|
|
119
|
+
protected readonly toDispose = new DisposableCollection(this.onDirtyChangedEmitter, this.onContentChangedEmitter);
|
|
120
|
+
protected readonly saveablesMap = new Map<Saveable, Disposable>();
|
|
121
|
+
|
|
122
|
+
get dirty(): boolean {
|
|
123
|
+
return this.isDirty;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
get onDirtyChanged(): Event<void> {
|
|
127
|
+
return this.onDirtyChangedEmitter.event;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
get onContentChanged(): Event<void> {
|
|
131
|
+
return this.onContentChangedEmitter.event;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async save(options?: SaveOptions): Promise<void> {
|
|
135
|
+
await Promise.all(this.saveables.map(saveable => saveable.save(options)));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async revert(options?: Saveable.RevertOptions): Promise<void> {
|
|
139
|
+
await Promise.all(this.saveables.map(saveable => saveable.revert?.(options)));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get saveables(): readonly Saveable[] {
|
|
143
|
+
return Array.from(this.saveablesMap.keys());
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
add(saveable: Saveable): void {
|
|
147
|
+
if (this.saveablesMap.has(saveable)) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const toDispose = new DisposableCollection();
|
|
151
|
+
this.toDispose.push(toDispose);
|
|
152
|
+
this.saveablesMap.set(saveable, toDispose);
|
|
153
|
+
toDispose.push(Disposable.create(() => {
|
|
154
|
+
this.saveablesMap.delete(saveable);
|
|
155
|
+
}));
|
|
156
|
+
toDispose.push(saveable.onDirtyChanged(() => {
|
|
157
|
+
const wasDirty = this.isDirty;
|
|
158
|
+
this.isDirty = this.saveables.some(s => s.dirty);
|
|
159
|
+
if (this.isDirty !== wasDirty) {
|
|
160
|
+
this.onDirtyChangedEmitter.fire();
|
|
161
|
+
}
|
|
162
|
+
}));
|
|
163
|
+
toDispose.push(saveable.onContentChanged(() => {
|
|
164
|
+
this.onContentChangedEmitter.fire();
|
|
165
|
+
}));
|
|
166
|
+
if (saveable.dirty && !this.isDirty) {
|
|
167
|
+
this.isDirty = true;
|
|
168
|
+
this.onDirtyChangedEmitter.fire();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
remove(saveable: Saveable): boolean {
|
|
173
|
+
const toDispose = this.saveablesMap.get(saveable);
|
|
174
|
+
toDispose?.dispose();
|
|
175
|
+
return !!toDispose;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
dispose(): void {
|
|
179
|
+
this.toDispose.dispose();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
115
183
|
export namespace Saveable {
|
|
116
184
|
export interface RevertOptions {
|
|
117
185
|
/**
|
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import { MenuNode, MenuPath } from '../../../common';
|
|
18
|
-
import { NAVIGATION,
|
|
18
|
+
import { NAVIGATION, RenderedToolbarItem } from './tab-bar-toolbar-types';
|
|
19
19
|
|
|
20
20
|
export const TOOLBAR_WRAPPER_ID_SUFFIX = '-as-tabbar-toolbar-item';
|
|
21
21
|
|
|
22
|
-
export class ToolbarMenuNodeWrapper implements
|
|
23
|
-
constructor(protected readonly menuNode: MenuNode, readonly group
|
|
22
|
+
export class ToolbarMenuNodeWrapper implements RenderedToolbarItem {
|
|
23
|
+
constructor(protected readonly menuNode: MenuNode, readonly group: string | undefined, readonly delegateMenuPath: MenuPath, readonly menuPath?: MenuPath) { }
|
|
24
24
|
get id(): string { return this.menuNode.id + TOOLBAR_WRAPPER_ID_SUFFIX; }
|
|
25
25
|
get command(): string { return this.menuNode.command ?? ''; };
|
|
26
26
|
get icon(): string | undefined { return this.menuNode.icon; }
|
|
@@ -17,11 +17,11 @@
|
|
|
17
17
|
import debounce = require('lodash.debounce');
|
|
18
18
|
import { inject, injectable, named } from 'inversify';
|
|
19
19
|
// eslint-disable-next-line max-len
|
|
20
|
-
import {
|
|
20
|
+
import { CommandRegistry, ContributionProvider, Disposable, DisposableCollection, Emitter, Event, MenuModelRegistry, MenuNode, MenuPath } from '../../../common';
|
|
21
21
|
import { ContextKeyService } from '../../context-key-service';
|
|
22
22
|
import { FrontendApplicationContribution } from '../../frontend-application-contribution';
|
|
23
23
|
import { Widget } from '../../widgets';
|
|
24
|
-
import {
|
|
24
|
+
import { MenuDelegate, ReactTabBarToolbarItem, RenderedToolbarItem, TabBarToolbarItem } from './tab-bar-toolbar-types';
|
|
25
25
|
import { ToolbarMenuNodeWrapper } from './tab-bar-toolbar-menu-adapters';
|
|
26
26
|
|
|
27
27
|
/**
|
|
@@ -75,7 +75,7 @@ export class TabBarToolbarRegistry implements FrontendApplicationContribution {
|
|
|
75
75
|
*
|
|
76
76
|
* @param item the item to register.
|
|
77
77
|
*/
|
|
78
|
-
registerItem(item:
|
|
78
|
+
registerItem(item: RenderedToolbarItem | ReactTabBarToolbarItem): Disposable {
|
|
79
79
|
const { id } = item;
|
|
80
80
|
if (this.items.has(id)) {
|
|
81
81
|
throw new Error(`A toolbar item is already registered with the '${id}' ID.`);
|
|
@@ -110,24 +110,18 @@ export class TabBarToolbarRegistry implements FrontendApplicationContribution {
|
|
|
110
110
|
for (const delegate of this.menuDelegates.values()) {
|
|
111
111
|
if (delegate.isVisible(widget)) {
|
|
112
112
|
const menu = this.menuRegistry.getMenu(delegate.menuPath);
|
|
113
|
-
const
|
|
114
|
-
for (const child of children) {
|
|
113
|
+
for (const child of menu.children) {
|
|
115
114
|
if (!child.when || this.contextKeyService.match(child.when, widget.node)) {
|
|
116
115
|
if (child.children) {
|
|
117
116
|
for (const grandchild of child.children) {
|
|
118
117
|
if (!grandchild.when || this.contextKeyService.match(grandchild.when, widget.node)) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
} else if (CompoundMenuNode.is(grandchild)) {
|
|
122
|
-
let menuPath;
|
|
123
|
-
if (menuPath = this.menuRegistry.getPath(grandchild)) {
|
|
124
|
-
result.push(new ToolbarMenuNodeWrapper(grandchild, child.id, menuPath));
|
|
125
|
-
}
|
|
126
|
-
}
|
|
118
|
+
const menuPath = this.menuRegistry.getPath(grandchild);
|
|
119
|
+
result.push(new ToolbarMenuNodeWrapper(grandchild, child.id, delegate.menuPath, menuPath));
|
|
127
120
|
}
|
|
128
121
|
}
|
|
129
122
|
} else if (child.command) {
|
|
130
|
-
|
|
123
|
+
const menuPath = this.menuRegistry.getPath(child);
|
|
124
|
+
result.push(new ToolbarMenuNodeWrapper(child, undefined, delegate.menuPath, menuPath));
|
|
131
125
|
}
|
|
132
126
|
}
|
|
133
127
|
}
|
|
@@ -145,15 +139,17 @@ export class TabBarToolbarRegistry implements FrontendApplicationContribution {
|
|
|
145
139
|
* @returns `false` if the `item` should be suppressed, otherwise `true`
|
|
146
140
|
*/
|
|
147
141
|
protected isItemVisible(item: TabBarToolbarItem | ReactTabBarToolbarItem, widget: Widget): boolean {
|
|
148
|
-
if (
|
|
142
|
+
if (!this.isConditionalItemVisible(item, widget)) {
|
|
149
143
|
return false;
|
|
150
144
|
}
|
|
151
|
-
|
|
145
|
+
|
|
146
|
+
if (item.command && !this.commandRegistry.isVisible(item.command, widget)) {
|
|
152
147
|
return false;
|
|
153
148
|
}
|
|
154
|
-
if (
|
|
149
|
+
if (item.menuPath && !this.isNonEmptyMenu(item, widget)) {
|
|
155
150
|
return false;
|
|
156
151
|
}
|
|
152
|
+
|
|
157
153
|
// The item is not vetoed. Accept it
|
|
158
154
|
return true;
|
|
159
155
|
}
|
|
@@ -166,7 +162,7 @@ export class TabBarToolbarRegistry implements FrontendApplicationContribution {
|
|
|
166
162
|
* @param widget the widget that is updating the toolbar
|
|
167
163
|
* @returns `false` if the `item` should be suppressed, otherwise `true`
|
|
168
164
|
*/
|
|
169
|
-
protected isConditionalItemVisible(item:
|
|
165
|
+
protected isConditionalItemVisible(item: TabBarToolbarItem, widget: Widget): boolean {
|
|
170
166
|
if (item.isVisible && !item.isVisible(widget)) {
|
|
171
167
|
return false;
|
|
172
168
|
}
|
|
@@ -176,19 +172,6 @@ export class TabBarToolbarRegistry implements FrontendApplicationContribution {
|
|
|
176
172
|
return true;
|
|
177
173
|
}
|
|
178
174
|
|
|
179
|
-
/**
|
|
180
|
-
* Query whether a tab-bar toolbar `item` that has a command should be shown in the toolbar.
|
|
181
|
-
* This implementation returns `false` if the `item`'s command is not visible in the
|
|
182
|
-
* `widget` according to the command registry.
|
|
183
|
-
*
|
|
184
|
-
* @param item a tab-bar toolbar item that has a non-empty `command`
|
|
185
|
-
* @param widget the widget that is updating the toolbar
|
|
186
|
-
* @returns `false` if the `item` should be suppressed, otherwise `true`
|
|
187
|
-
*/
|
|
188
|
-
protected isTabBarToolbarItemVisible(item: TabBarToolbarItem, widget: Widget): boolean {
|
|
189
|
-
return this.commandRegistry.isVisible(item.command, widget);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
175
|
/**
|
|
193
176
|
* Query whether a menu toolbar `item` should be shown in the toolbar.
|
|
194
177
|
* This implementation returns `false` if the `item` does not have any actual menu to show.
|
|
@@ -197,7 +180,10 @@ export class TabBarToolbarRegistry implements FrontendApplicationContribution {
|
|
|
197
180
|
* @param widget the widget that is updating the toolbar
|
|
198
181
|
* @returns `false` if the `item` should be suppressed, otherwise `true`
|
|
199
182
|
*/
|
|
200
|
-
|
|
183
|
+
isNonEmptyMenu(item: TabBarToolbarItem, widget: Widget | undefined): boolean {
|
|
184
|
+
if (!item.menuPath) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
201
187
|
const menu = this.menuRegistry.getMenu(item.menuPath);
|
|
202
188
|
const isVisible: (node: MenuNode) => boolean = node =>
|
|
203
189
|
node.children?.length
|
|
@@ -220,7 +206,7 @@ export class TabBarToolbarRegistry implements FrontendApplicationContribution {
|
|
|
220
206
|
}
|
|
221
207
|
}
|
|
222
208
|
|
|
223
|
-
registerMenuDelegate(menuPath: MenuPath, when?:
|
|
209
|
+
registerMenuDelegate(menuPath: MenuPath, when?: ((widget: Widget) => boolean)): Disposable {
|
|
224
210
|
const id = this.toElementId(menuPath);
|
|
225
211
|
if (!this.menuDelegates.has(id)) {
|
|
226
212
|
const isVisible: MenuDelegate['isVisible'] = !when
|