Skip to content

Commit 9d5d73f

Browse files
authored
Shared editor association setting between custom editor and notebook (microsoft#94952)
1 parent 5e76858 commit 9d5d73f

7 files changed

Lines changed: 125 additions & 45 deletions

File tree

src/vs/workbench/contrib/customEditor/browser/customEditor.contribution.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
76
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
87
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
98
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
@@ -17,7 +16,6 @@ import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEdito
1716
import './commands';
1817
import { CustomEditorInput } from './customEditorInput';
1918
import { CustomEditorContribution, CustomEditorService } from './customEditors';
20-
import { editorAssociationsConfigurationNode } from './editorAssociationsSetting';
2119

2220
registerSingleton(ICustomEditorService, CustomEditorService);
2321

@@ -41,6 +39,3 @@ Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactor
4139

4240
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories)
4341
.registerCustomEditorInputFactory(CustomEditorInputFactory);
44-
45-
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
46-
.registerConfiguration(editorAssociationsConfigurationNode);

src/vs/workbench/contrib/customEditor/browser/customEditors.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { coalesce } from 'vs/base/common/arrays';
7+
import { Event, Emitter } from 'vs/base/common/event';
78
import { Lazy } from 'vs/base/common/lazy';
89
import { Disposable } from 'vs/base/common/lifecycle';
910
import { basename, extname, isEqual } from 'vs/base/common/resources';
@@ -27,12 +28,12 @@ import { CustomEditorModelManager } from 'vs/workbench/contrib/customEditor/comm
2728
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
2829
import { IWebviewService, webviewHasOwnEditFunctionsContext } from 'vs/workbench/contrib/webview/browser/webview';
2930
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
30-
import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService';
31+
import { IEditorService, IOpenEditorOverride, ICustomEditorViewTypesHandler, ICustomEditorInfo } from 'vs/workbench/services/editor/common/editorService';
3132
import { ContributedCustomEditors, defaultCustomEditor } from '../common/contributedCustomEditors';
3233
import { CustomEditorInput } from './customEditorInput';
33-
import { CustomEditorAssociation, CustomEditorAssociationsSettingIntelliSense, CustomEditorsAssociations, customEditorsAssociationsSettingId } from './editorAssociationsSetting';
34+
import { CustomEditorAssociation, CustomEditorsAssociations, customEditorsAssociationsSettingId } from 'vs/workbench/services/editor/browser/editorAssociationsSetting';
3435

35-
export class CustomEditorService extends Disposable implements ICustomEditorService {
36+
export class CustomEditorService extends Disposable implements ICustomEditorService, ICustomEditorViewTypesHandler {
3637
_serviceBrand: any;
3738

3839
private readonly _contributedEditors = this._register(new ContributedCustomEditors());
@@ -42,6 +43,8 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
4243
private readonly _customEditorContextKey: IContextKey<string>;
4344
private readonly _focusedCustomEditorIsEditable: IContextKey<boolean>;
4445
private readonly _webviewHasOwnEditFunctions: IContextKey<boolean>;
46+
private readonly _onDidChangeViewTypes = new Emitter<void>();
47+
onDidChangeViewTypes: Event<void> = this._onDidChangeViewTypes.event;
4548

4649
constructor(
4750
@IContextKeyService contextKeyService: IContextKeyService,
@@ -59,9 +62,10 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
5962
this._focusedCustomEditorIsEditable = CONTEXT_FOCUSED_CUSTOM_EDITOR_IS_EDITABLE.bindTo(contextKeyService);
6063
this._webviewHasOwnEditFunctions = webviewHasOwnEditFunctionsContext.bindTo(contextKeyService);
6164

62-
this._register(new CustomEditorAssociationsSettingIntelliSense(this._contributedEditors));
65+
this._register(this.editorService.registerCustomEditorViewTypesHandler('Custom Editor', this));
6366
this._register(this._contributedEditors.onChange(() => {
6467
this.updateContexts();
68+
this._onDidChangeViewTypes.fire();
6569
}));
6670
this._register(this.editorService.onDidActiveEditorChange(() => this.updateContexts()));
6771

@@ -74,6 +78,10 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
7478
this.updateContexts();
7579
}
7680

81+
getViewTypes(): ICustomEditorInfo[] {
82+
return [...this._contributedEditors];
83+
}
84+
7785
public get models() { return this._models; }
7886

7987
public getCustomEditor(viewType: string): CustomEditorInfo | undefined {

src/vs/workbench/contrib/notebook/browser/notebookService.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common
1717
import { Iterable } from 'vs/base/common/iterator';
1818
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
1919
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
20+
import { IEditorService, ICustomEditorViewTypesHandler, ICustomEditorInfo } from 'vs/workbench/services/editor/common/editorService';
2021

2122
function MODEL_ID(resource: URI): string {
2223
return resource.toString();
@@ -76,6 +77,10 @@ export class NotebookProviderInfoStore {
7677
getContributedNotebook(resource: URI): readonly NotebookProviderInfo[] {
7778
return [...Iterable.filter(this.contributedEditors.values(), customEditor => customEditor.matches(resource))];
7879
}
80+
81+
public [Symbol.iterator](): Iterator<NotebookProviderInfo> {
82+
return this.contributedEditors.values();
83+
}
7984
}
8085

8186
export class NotebookOutputRendererInfoStore {
@@ -119,7 +124,7 @@ class ModelData implements IDisposable {
119124
}
120125

121126

122-
export class NotebookService extends Disposable implements INotebookService {
127+
export class NotebookService extends Disposable implements INotebookService, ICustomEditorViewTypesHandler {
123128
_serviceBrand: undefined;
124129
private readonly _notebookProviders = new Map<string, { controller: IMainNotebookController, extensionData: NotebookExtensionDescription }>();
125130
private readonly _notebookRenderers = new Map<number, { extensionData: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, preloads: URI[] }>();
@@ -129,8 +134,12 @@ export class NotebookService extends Disposable implements INotebookService {
129134
private _onDidChangeActiveEditor = new Emitter<{ viewType: string, uri: URI }>();
130135
onDidChangeActiveEditor: Event<{ viewType: string, uri: URI }> = this._onDidChangeActiveEditor.event;
131136

137+
private readonly _onDidChangeViewTypes = new Emitter<void>();
138+
onDidChangeViewTypes: Event<void> = this._onDidChangeViewTypes.event;
139+
132140
constructor(
133-
@IExtensionService private readonly extensionService: IExtensionService
141+
@IExtensionService private readonly extensionService: IExtensionService,
142+
@IEditorService private readonly editorService: IEditorService
134143
) {
135144
super();
136145

@@ -166,6 +175,16 @@ export class NotebookService extends Disposable implements INotebookService {
166175

167176
// console.log(this.notebookRenderersInfoStore);
168177
});
178+
179+
this.editorService.registerCustomEditorViewTypesHandler('Notebook', this);
180+
}
181+
182+
getViewTypes(): ICustomEditorInfo[] {
183+
return [...this.notebookProviderInfoStore].map(info => ({
184+
id: info.id,
185+
displayName: info.displayName,
186+
providerDisplayName: info.providerDisplayName
187+
}));
169188
}
170189

171190
async canResolve(viewType: string): Promise<boolean> {
@@ -178,10 +197,12 @@ export class NotebookService extends Disposable implements INotebookService {
178197

179198
registerNotebookController(viewType: string, extensionData: NotebookExtensionDescription, controller: IMainNotebookController) {
180199
this._notebookProviders.set(viewType, { extensionData, controller });
200+
this._onDidChangeViewTypes.fire();
181201
}
182202

183203
unregisterNotebookProvider(viewType: string): void {
184204
this._notebookProviders.delete(viewType);
205+
this._onDidChangeViewTypes.fire();
185206
}
186207

187208
registerNotebookRenderer(handle: number, extensionData: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, preloads: URI[]) {

src/vs/workbench/contrib/customEditor/browser/editorAssociationsSetting.ts renamed to src/vs/workbench/services/editor/browser/editorAssociationsSetting.ts

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,23 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
77
import * as nls from 'vs/nls';
88
import { IConfigurationNode, IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
99
import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration';
10-
import { CustomEditorSelector } from 'vs/workbench/contrib/customEditor/common/customEditor';
11-
import { ContributedCustomEditors, defaultCustomEditor } from 'vs/workbench/contrib/customEditor/common/contributedCustomEditors';
12-
import { Disposable } from 'vs/base/common/lifecycle';
1310
import { Registry } from 'vs/platform/registry/common/platform';
11+
import { ICustomEditorInfo } from 'vs/workbench/services/editor/common/editorService';
1412

1513
export const customEditorsAssociationsSettingId = 'workbench.editorAssociations';
1614

17-
export type CustomEditorAssociation = CustomEditorSelector & {
15+
export const viewTypeSchamaAddition: IJSONSchema = {
16+
type: 'string',
17+
enum: []
18+
};
19+
20+
export type CustomEditorAssociation = {
1821
readonly viewType: string;
22+
readonly filenamePattern?: string;
1923
};
2024

2125
export type CustomEditorsAssociations = readonly CustomEditorAssociation[];
2226

23-
const viewTypeSchamaAddition: IJSONSchema = {
24-
type: 'string',
25-
enum: []
26-
};
27-
2827
export const editorAssociationsConfigurationNode: IConfigurationNode = {
2928
...workbenchConfigurationNodeBase,
3029
properties: {
@@ -59,30 +58,19 @@ export const editorAssociationsConfigurationNode: IConfigurationNode = {
5958
}
6059
};
6160

62-
export class CustomEditorAssociationsSettingIntelliSense extends Disposable {
6361

64-
constructor(
65-
private readonly _contributedCustomEditors: ContributedCustomEditors,
66-
) {
67-
super();
62+
const builtinProviderDisplayName = nls.localize('builtinProviderDisplayName', "Built-in");
6863

69-
this._register(_contributedCustomEditors.onChange(() => {
70-
this.updateSchema();
71-
}));
72-
this.updateSchema();
73-
}
64+
export const DEFAULT_CUSTOM_EDITOR: ICustomEditorInfo = {
65+
id: 'default',
66+
displayName: nls.localize('promptOpenWith.defaultEditor.displayName', "Text Editor"),
67+
providerDisplayName: builtinProviderDisplayName
68+
};
7469

75-
private updateSchema() {
76-
const enumValues: string[] = [];
77-
const enumDescriptions: string[] = [];
78-
for (const info of [defaultCustomEditor, ...this._contributedCustomEditors]) {
79-
enumValues.push(info.id);
80-
enumDescriptions.push(nls.localize('editorAssociations.viewType.sourceDescription', "Source: {0}", info.providerDisplayName));
81-
}
82-
viewTypeSchamaAddition.enum = enumValues;
83-
viewTypeSchamaAddition.enumDescriptions = enumDescriptions;
70+
export function updateViewTypeSchema(enumValues: string[], enumDescriptions: string[]): void {
71+
viewTypeSchamaAddition.enum = enumValues;
72+
viewTypeSchamaAddition.enumDescriptions = enumDescriptions;
8473

85-
Registry.as<IConfigurationRegistry>(Extensions.Configuration)
86-
.notifyConfigurationSchemaUpdated(editorAssociationsConfigurationNode);
87-
}
74+
Registry.as<IConfigurationRegistry>(Extensions.Configuration)
75+
.notifyConfigurationSchemaUpdated(editorAssociationsConfigurationNode);
8876
}

src/vs/workbench/services/editor/browser/editorService.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import * as nls from 'vs/nls';
67
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
78
import { IResourceEditorInput, ITextEditorOptions, IEditorOptions, EditorActivation } from 'vs/platform/editor/common/editor';
89
import { SideBySideEditor, IEditorInput, IEditorPane, GroupIdentifier, IFileEditorInput, IUntitledTextResourceEditorInput, IResourceDiffEditorInput, IEditorInputFactoryRegistry, Extensions as EditorExtensions, EditorInput, SideBySideEditorInput, IEditorInputWithOptions, isEditorInputWithOptions, EditorOptions, TextEditorOptions, IEditorIdentifier, IEditorCloseEvent, ITextEditorPane, ITextDiffEditorPane, IRevertOptions, SaveReason, EditorsOrder, isTextEditorPane, IWorkbenchEditorConfiguration, toResource, IVisibleEditorPane } from 'vs/workbench/common/editor';
@@ -17,7 +18,7 @@ import { URI } from 'vs/base/common/uri';
1718
import { basename, isEqualOrParent, joinPath } from 'vs/base/common/resources';
1819
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
1920
import { IEditorGroupsService, IEditorGroup, GroupsOrder, IEditorReplacement, GroupChangeKind, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService';
20-
import { IResourceEditorInputType, SIDE_GROUP, IResourceEditorReplacement, IOpenEditorOverrideHandler, IEditorService, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE, ISaveEditorsOptions, ISaveAllEditorsOptions, IRevertAllEditorsOptions, IBaseSaveRevertAllEditorOptions, IOpenEditorOverrideEntry } from 'vs/workbench/services/editor/common/editorService';
21+
import { IResourceEditorInputType, SIDE_GROUP, IResourceEditorReplacement, IOpenEditorOverrideHandler, IEditorService, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE, ISaveEditorsOptions, ISaveAllEditorsOptions, IRevertAllEditorsOptions, IBaseSaveRevertAllEditorOptions, IOpenEditorOverrideEntry, ICustomEditorViewTypesHandler, ICustomEditorInfo } from 'vs/workbench/services/editor/common/editorService';
2122
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
2223
import { Disposable, IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
2324
import { coalesce, distinct, insert } from 'vs/base/common/arrays';
@@ -33,6 +34,8 @@ import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/u
3334
import { timeout } from 'vs/base/common/async';
3435
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
3536
import { indexOfPath } from 'vs/base/common/extpath';
37+
import { DEFAULT_CUSTOM_EDITOR, updateViewTypeSchema, editorAssociationsConfigurationNode } from 'vs/workbench/services/editor/browser/editorAssociationsSetting';
38+
import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
3639

3740
type CachedEditorInput = ResourceEditorInput | IFileEditorInput | UntitledTextEditorInput;
3841
type OpenInEditorGroup = IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE;
@@ -1088,6 +1091,48 @@ export class EditorService extends Disposable implements EditorServiceImpl {
10881091

10891092
//#endregion
10901093

1094+
//#region Custom View Type
1095+
private customEditorViewTypesHandlers = new Map<string, ICustomEditorViewTypesHandler>();
1096+
registerCustomEditorViewTypesHandler(source: string, handler: ICustomEditorViewTypesHandler): IDisposable {
1097+
if (this.customEditorViewTypesHandlers.has(source)) {
1098+
throw new Error(`Use a different name for the custom editor component, ${source} is already occupied.`);
1099+
}
1100+
1101+
this.customEditorViewTypesHandlers.set(source, handler);
1102+
this.updateSchema();
1103+
1104+
const viewTypeChangeEvent = handler.onDidChangeViewTypes(() => {
1105+
this.updateSchema();
1106+
});
1107+
1108+
return {
1109+
dispose: () => {
1110+
viewTypeChangeEvent.dispose();
1111+
this.customEditorViewTypesHandlers.delete(source);
1112+
this.updateSchema();
1113+
}
1114+
};
1115+
}
1116+
1117+
private updateSchema() {
1118+
const enumValues: string[] = [];
1119+
const enumDescriptions: string[] = [];
1120+
1121+
const infos: ICustomEditorInfo[] = [DEFAULT_CUSTOM_EDITOR];
1122+
1123+
for (const [, handler] of this.customEditorViewTypesHandlers) {
1124+
infos.push(...handler.getViewTypes());
1125+
}
1126+
1127+
infos.forEach(info => {
1128+
enumValues.push(info.id);
1129+
enumDescriptions.push(nls.localize('editorAssociations.viewType.sourceDescription', "Source: {0}", info.providerDisplayName));
1130+
});
1131+
1132+
updateViewTypeSchema(enumValues, enumDescriptions);
1133+
}
1134+
1135+
//#endregion
10911136
dispose(): void {
10921137
super.dispose();
10931138

@@ -1195,7 +1240,14 @@ export class DelegatingEditorService implements IEditorService {
11951240
revert(editors: IEditorIdentifier | IEditorIdentifier[], options?: IRevertOptions): Promise<void> { return this.editorService.revert(editors, options); }
11961241
revertAll(options?: IRevertAllEditorsOptions): Promise<void> { return this.editorService.revertAll(options); }
11971242

1243+
registerCustomEditorViewTypesHandler(source: string, handler: ICustomEditorViewTypesHandler): IDisposable {
1244+
throw new Error('Method not implemented.');
1245+
}
1246+
11981247
//#endregion
11991248
}
12001249

12011250
registerSingleton(IEditorService, EditorService);
1251+
1252+
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
1253+
.registerConfiguration(editorAssociationsConfigurationNode);

src/vs/workbench/services/editor/common/editorService.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ export interface ISaveAllEditorsOptions extends ISaveEditorsOptions, IBaseSaveRe
6767

6868
export interface IRevertAllEditorsOptions extends IRevertOptions, IBaseSaveRevertAllEditorOptions { }
6969

70+
export interface ICustomEditorInfo {
71+
72+
readonly id: string;
73+
readonly displayName: string;
74+
readonly providerDisplayName: string;
75+
}
76+
77+
export interface ICustomEditorViewTypesHandler {
78+
readonly onDidChangeViewTypes: Event<void>;
79+
getViewTypes(): ICustomEditorInfo[];
80+
}
81+
7082
export interface IEditorService {
7183

7284
_serviceBrand: undefined;
@@ -221,6 +233,8 @@ export interface IEditorService {
221233
*/
222234
overrideOpenEditor(handler: IOpenEditorOverrideHandler): IDisposable;
223235

236+
registerCustomEditorViewTypesHandler(source: string, handler: ICustomEditorViewTypesHandler): IDisposable;
237+
224238
/**
225239
* Invoke a function in the context of the services of the active editor.
226240
*/

0 commit comments

Comments
 (0)