diff --git a/src/vs/workbench/browser/parts/editor/baseEditor.ts b/src/vs/workbench/browser/parts/editor/baseEditor.ts index 35d96ad23a1f67473b5419b898fb152e34a112c6..e57afd9b033f6e664d2be4d14f212774ae5ee8c5 100644 --- a/src/vs/workbench/browser/parts/editor/baseEditor.ts +++ b/src/vs/workbench/browser/parts/editor/baseEditor.ts @@ -48,6 +48,7 @@ export abstract class BaseEditor extends Composite implements IEditorPane { get input(): EditorInput | undefined { return this._input; } protected _options: EditorOptions | undefined; + get options(): EditorOptions | undefined { return this._options; } private _group?: IEditorGroup; get group(): IEditorGroup | undefined { return this._group; } diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 98011bdf51d819104066ba45cca79e953adcd9fa..9c6a4f57a922715830065920b75cc61cd1a34709 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -69,6 +69,11 @@ export interface IEditorPane extends IComposite { */ readonly input: IEditorInput | undefined; + /** + * The assigned options of the editor. + */ + readonly options: EditorOptions | undefined; + /** * The assigned group this editor is showing in. */ diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts index 83e044a1c8bd33b079c8cdf9778d66f7bc60e883..48d67977a408a413437d92257133a470ccce0f4d 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -343,8 +343,10 @@ export class CustomEditorContribution extends Disposable implements IWorkbenchCo ) { super(); - this._register(this.editorService.overrideOpenEditor((editor, options, group) => { - return this.onEditorOpening(editor, options, group); + this._register(this.editorService.overrideOpenEditor({ + open: (editor, options, group) => { + return this.onEditorOpening(editor, options, group); + } })); this._register(this.editorService.onDidCloseEditor(({ editor }) => { diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 4c21a261e155047c40e79de5ea281f0a2cd0a0ce..3b73376208780b80cb21ab78eaa7c765e32fab80 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { Registry } from 'vs/platform/registry/common/platform'; -import { ToggleAutoSaveAction, GlobalNewUntitledFileAction, FocusFilesExplorer, GlobalCompareResourcesAction, SaveAllAction, ShowActiveFileInExplorer, CollapseExplorerView, RefreshExplorerView, CompareWithClipboardAction, NEW_FILE_COMMAND_ID, NEW_FILE_LABEL, NEW_FOLDER_COMMAND_ID, NEW_FOLDER_LABEL, TRIGGER_RENAME_LABEL, MOVE_FILE_TO_TRASH_LABEL, COPY_FILE_LABEL, PASTE_FILE_LABEL, FileCopiedContext, renameHandler, moveFileToTrashHandler, copyFileHandler, pasteFileHandler, deleteFileHandler, cutFileHandler, DOWNLOAD_COMMAND_ID, openFilePreserveFocusHandler, DOWNLOAD_LABEL, ShowOpenedFileInNewWindow } from 'vs/workbench/contrib/files/browser/fileActions'; +import { ToggleAutoSaveAction, GlobalNewUntitledFileAction, FocusFilesExplorer, GlobalCompareResourcesAction, SaveAllAction, ShowActiveFileInExplorer, CollapseExplorerView, RefreshExplorerView, CompareWithClipboardAction, NEW_FILE_COMMAND_ID, NEW_FILE_LABEL, NEW_FOLDER_COMMAND_ID, NEW_FOLDER_LABEL, TRIGGER_RENAME_LABEL, MOVE_FILE_TO_TRASH_LABEL, COPY_FILE_LABEL, PASTE_FILE_LABEL, FileCopiedContext, renameHandler, moveFileToTrashHandler, copyFileHandler, pasteFileHandler, deleteFileHandler, cutFileHandler, DOWNLOAD_COMMAND_ID, openFilePreserveFocusHandler, DOWNLOAD_LABEL, ShowOpenedFileInNewWindow, ReopenResourcesAction } from 'vs/workbench/contrib/files/browser/fileActions'; import { revertLocalChangesCommand, acceptLocalChangesCommand, CONFLICT_RESOLUTION_CONTEXT } from 'vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler'; import { SyncActionDescriptor, MenuId, MenuRegistry, ILocalizedString } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; @@ -36,6 +36,7 @@ const category = { value: nls.localize('filesCategory', "File"), original: 'File const registry = Registry.as(ActionExtensions.WorkbenchActions); registry.registerWorkbenchAction(SyncActionDescriptor.create(SaveAllAction, SaveAllAction.ID, SaveAllAction.LABEL, { primary: undefined, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_S }, win: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_S) } }), 'File: Save All', category.value); registry.registerWorkbenchAction(SyncActionDescriptor.create(GlobalCompareResourcesAction, GlobalCompareResourcesAction.ID, GlobalCompareResourcesAction.LABEL), 'File: Compare Active File With...', category.value); +registry.registerWorkbenchAction(SyncActionDescriptor.create(ReopenResourcesAction, ReopenResourcesAction.ID, ReopenResourcesAction.LABEL), 'File: Reopen With...', category.value); registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusFilesExplorer, FocusFilesExplorer.ID, FocusFilesExplorer.LABEL), 'File: Focus on Files Explorer', category.value); registry.registerWorkbenchAction(SyncActionDescriptor.create(ShowActiveFileInExplorer, ShowActiveFileInExplorer.ID, ShowActiveFileInExplorer.LABEL), 'File: Reveal Active File in Side Bar', category.value); registry.registerWorkbenchAction(SyncActionDescriptor.create(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL), 'File: Collapse Folders in Explorer', category.value); diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index 38529b63a3d6010780dbd8803f82c30cba4fb66c..146ebf56b1e2c12cbc7391f96bb85be8eba48f8b 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -16,9 +16,9 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { VIEWLET_ID, IExplorerService, IFilesConfiguration } from 'vs/workbench/contrib/files/common/files'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IFileService } from 'vs/platform/files/common/files'; -import { toResource, SideBySideEditor } from 'vs/workbench/common/editor'; +import { toResource, SideBySideEditor, IEditorInput } from 'vs/workbench/common/editor'; import { ExplorerViewPaneContainer } from 'vs/workbench/contrib/files/browser/explorerViewlet'; -import { IQuickInputService, ItemActivation } from 'vs/platform/quickinput/common/quickInput'; +import { IQuickInputService, ItemActivation, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ITextModel } from 'vs/editor/common/model'; @@ -34,7 +34,7 @@ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Schemas } from 'vs/base/common/network'; import { IDialogService, IConfirmationResult, getFileNamesMessage, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorService, IOpenEditorOverrideHandler } from 'vs/workbench/services/editor/common/editorService'; import { Constants } from 'vs/base/common/uint'; import { CLOSE_EDITORS_AND_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; import { coalesce } from 'vs/base/common/arrays'; @@ -47,6 +47,9 @@ import { IWorkingCopyService, IWorkingCopy } from 'vs/workbench/services/working import { sequence, timeout } from 'vs/base/common/async'; import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService'; import { once } from 'vs/base/common/functional'; +import { IEditorOptions } from 'vs/platform/editor/common/editor'; +import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; export const NEW_FILE_COMMAND_ID = 'explorer.newFile'; export const NEW_FILE_LABEL = nls.localize('newFile', "New File"); @@ -480,23 +483,27 @@ export class GlobalCompareResourcesAction extends Action { if (activeResource) { // Compare with next editor that opens - const toDispose = this.editorService.overrideOpenEditor(editor => { - - // Only once! - toDispose.dispose(); + const toDispose = this.editorService.overrideOpenEditor({ + getEditorOverrides: (editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup | undefined) => { + return []; + }, + open: editor => { + // Only once! + toDispose.dispose(); + + // Open editor as diff + const resource = editor.resource; + if (resource) { + return { + override: this.editorService.openEditor({ + leftResource: activeResource, + rightResource: resource + }) + }; + } - // Open editor as diff - const resource = editor.resource; - if (resource) { - return { - override: this.editorService.openEditor({ - leftResource: activeResource, - rightResource: resource - }) - }; + return undefined; } - - return undefined; }); once(this.quickInputService.onHide)((async () => { @@ -512,6 +519,87 @@ export class GlobalCompareResourcesAction extends Action { } } +const builtinProviderDisplayName = nls.localize('builtinProviderDisplayName', "Built-in"); +export class ReopenResourcesAction extends Action { + + static readonly ID = 'workbench.files.action.reopenWithEditor'; + static readonly LABEL = nls.localize('workbench.files.action.reopenWithEditor', "Reopen With..."); + + constructor( + id: string, + label: string, + @IQuickInputService private readonly quickInputService: IQuickInputService, + @IEditorService private readonly editorService: IEditorService, + ) { + super(id, label); + } + + async run(): Promise { + const activeInput = this.editorService.activeEditor; + const activeEditorPane = this.editorService.activeEditorPane; + if (!activeEditorPane) { + return; + } + + const options = activeEditorPane.options; + const group = activeEditorPane.group; + const activeResource = activeInput ? activeInput.resource : undefined; + + if (!activeResource) { + return; + } + + const overrides = this.editorService.getEditorOverrides(activeInput!, options, group); + const items: (IQuickPickItem & { handler?: IOpenEditorOverrideHandler })[] = overrides.map((override) => { + return { + handler: override[0], + id: override[1].id, + label: override[1].label, + description: override[1].active ? 'Currently Active' : undefined, + detail: override[1].detail + }; + }); + + if (!items.length) { + return; + } + + items.unshift({ + id: 'default', + label: nls.localize('promptOpenWith.defaultEditor.displayName', "Text Editor"), + description: activeInput instanceof FileEditorInput ? 'Currently Active' : undefined, + detail: builtinProviderDisplayName + }); + + const picker = this.quickInputService.createQuickPick<(IQuickPickItem & { handler?: IOpenEditorOverrideHandler })>(); + picker.items = items; + picker.placeholder = nls.localize('promptOpenWith.placeHolder', "Select editor to use for '{0}'...", resources.basename(activeResource)); + + const pickedItem = await new Promise<(IQuickPickItem & { handler?: IOpenEditorOverrideHandler }) | undefined>(resolve => { + picker.onDidAccept(() => { + resolve(picker.selectedItems.length === 1 ? picker.selectedItems[0] : undefined); + picker.dispose(); + }); + + picker.show(); + }); + + if (!pickedItem) { + return; + } + + if (pickedItem.id === 'default') { + const fileEditorInput = this.editorService.createEditorInput({ resource: activeResource!, forceFile: true }); + const textOptions = options ? { ...options, ignoreOverrides: true } : { ignoreOverrides: true }; + + await this.editorService.openEditor(fileEditorInput, textOptions, group); + return; + } + + await pickedItem.handler!.open(activeInput!, options, group, pickedItem.id); + } +} + export class ToggleAutoSaveAction extends Action { static readonly ID = 'workbench.action.toggleAutoSave'; static readonly LABEL = nls.localize('toggleAutoSave', "Toggle Auto Save"); diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index 3b21068d10131c731c0a2ec0c717b5a38e728e78..56be384831a259188e718d7ad86ce747b887cbf8 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -94,7 +94,26 @@ export class NotebookContribution implements IWorkbenchContribution { @IInstantiationService private readonly instantiationService: IInstantiationService ) { - this.editorService.overrideOpenEditor((editor, options, group) => this.onEditorOpening(editor, options, group)); + this.editorService.overrideOpenEditor({ + getEditorOverrides: (editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup | undefined) => { + let resource = editor.resource; + if (!resource) { + return []; + } + + const infos = notebookService.getContributedNotebookProviders(resource); + + return infos.map(info => { + return { + label: info.displayName, + id: info.id, + active: editor instanceof NotebookEditorInput && editor.viewType === info.id, + detail: info.providerDisplayName + }; + }); + }, + open: (editor, options, group, id) => this.onEditorOpening(editor, options, group, id) + }); this.editorService.onDidActiveEditorChange(() => { if (this.editorService.activeEditor && this.editorService.activeEditor! instanceof NotebookEditorInput) { @@ -104,7 +123,7 @@ export class NotebookContribution implements IWorkbenchContribution { }); } - private onEditorOpening(originalInput: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup): IOpenEditorOverride | undefined { + private onEditorOpening(originalInput: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup, id: string | undefined): IOpenEditorOverride | undefined { let resource = originalInput.resource; if (!resource) { return undefined; @@ -112,15 +131,22 @@ export class NotebookContribution implements IWorkbenchContribution { let info: NotebookProviderInfo | undefined; const data = CellUri.parse(resource); - if (data && (info = getFirstNotebookInfo(this.notebookService, data.notebook))) { - // cell-uri -> open (container) notebook - const name = basename(data.notebook); - const input = this.instantiationService.createInstance(NotebookEditorInput, data.notebook, name, info.id); - this._resourceMapping.set(resource, input); - return { override: this.editorService.openEditor(input, new NotebookEditorOptions({ ...options, forceReload: true, cellOptions: { resource, options } }), group) }; + if (data) { + const infos = this.notebookService.getContributedNotebookProviders(data.notebook); + + if (infos.length) { + const info = id === undefined ? infos[0] : (infos.find(info => info.id === id) || infos[0]); + // cell-uri -> open (container) notebook + const name = basename(data.notebook); + const input = this.instantiationService.createInstance(NotebookEditorInput, data.notebook, name, info.id); + this._resourceMapping.set(resource, input); + return { override: this.editorService.openEditor(input, new NotebookEditorOptions({ ...options, forceReload: true, cellOptions: { resource, options } }), group) }; + } } - info = getFirstNotebookInfo(this.notebookService, resource); + const infos = this.notebookService.getContributedNotebookProviders(resource); + info = id === undefined ? infos[0] : infos.find(info => info.id === id); + if (!info) { return undefined; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookService.ts b/src/vs/workbench/contrib/notebook/browser/notebookService.ts index 8b02c8e5ab93ec92711c12d25566ba41fb171610..492f3922f4e45d1fda2829f5e5eb5ef46e9ef831 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookService.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookService.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as nls from 'vs/nls'; import { Disposable, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { URI } from 'vs/base/common/uri'; @@ -143,6 +144,7 @@ export class NotebookService extends Disposable implements INotebookService { id: notebookContribution.viewType, displayName: notebookContribution.displayName, selector: notebookContribution.selector || [], + providerDisplayName: extension.description.isBuiltin ? nls.localize('builtinProviderDisplayName', "Built-in") : extension.description.displayName || extension.description.identifier.value, })); } } diff --git a/src/vs/workbench/contrib/notebook/common/notebookProvider.ts b/src/vs/workbench/contrib/notebook/common/notebookProvider.ts index f2d5a49b540a4b8cc39c407f6ec4e3faad0e73a2..a1f4ca196a4571c760000e07ed49e05559b53354 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookProvider.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookProvider.ts @@ -17,15 +17,18 @@ export class NotebookProviderInfo { readonly id: string; readonly displayName: string; readonly selector: readonly NotebookSelector[]; + readonly providerDisplayName: string; constructor(descriptor: { readonly id: string; readonly displayName: string; readonly selector: readonly NotebookSelector[]; + readonly providerDisplayName: string; }) { this.id = descriptor.id; this.displayName = descriptor.displayName; this.selector = descriptor.selector; + this.providerDisplayName = descriptor.providerDisplayName; } matches(resource: URI): boolean { diff --git a/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts b/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts index 4d5ef350017048051bf374b5ed48365ff48857f3..04945ccdee6fdb81fee4111eb0bc75ce07605ea2 100644 --- a/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts +++ b/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts @@ -58,7 +58,9 @@ export class PreferencesContribution implements IWorkbenchContribution { // install editor opening listener unless user has disabled this if (!!this.configurationService.getValue(USE_SPLIT_JSON_SETTING)) { - this.editorOpeningListener = this.editorService.overrideOpenEditor((editor, options, group) => this.onEditorOpening(editor, options, group)); + this.editorOpeningListener = this.editorService.overrideOpenEditor({ + open: (editor, options, group) => this.onEditorOpening(editor, options, group) + }); } } diff --git a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts index d8483a7d5ecd585958d29783d4d243b30b92e553..746029df38e37389690e73f309b9d7b6f5689d31 100644 --- a/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts +++ b/src/vs/workbench/contrib/searchEditor/browser/searchEditor.contribution.ts @@ -22,7 +22,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } from 'vs/workbench/browser/editor'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; -import { ActiveEditorContext, Extensions as EditorInputExtensions, IEditorInputFactory, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; +import { Extensions as EditorInputExtensions, IEditorInputFactory, IEditorInputFactoryRegistry, ActiveEditorContext } from 'vs/workbench/common/editor'; import * as SearchConstants from 'vs/workbench/contrib/search/common/constants'; import * as SearchEditorConstants from 'vs/workbench/contrib/searchEditor/browser/constants'; import { SearchEditor } from 'vs/workbench/contrib/searchEditor/browser/searchEditor'; @@ -54,27 +54,29 @@ class SearchEditorContribution implements IWorkbenchContribution { @IContextKeyService protected readonly contextKeyService: IContextKeyService, ) { - this.editorService.overrideOpenEditor((editor, options, group) => { - const resource = editor.resource; - if (!resource) { return undefined; } + this.editorService.overrideOpenEditor({ + open: (editor, options, group) => { + const resource = editor.resource; + if (!resource) { return undefined; } - if (!endsWith(resource.path, '.code-search')) { - return undefined; - } + if (!endsWith(resource.path, '.code-search')) { + return undefined; + } - if (group.isOpened(editor)) { - return undefined; - } + if (group.isOpened(editor) && editor instanceof SearchEditorInput) { + return undefined; + } - this.telemetryService.publicLog2('searchEditor/openSavedSearchEditor'); + this.telemetryService.publicLog2('searchEditor/openSavedSearchEditor'); - return { - override: (async () => { - const { config } = await instantiationService.invokeFunction(parseSavedSearchEditor, resource); - const input = instantiationService.invokeFunction(getOrMakeSearchEditorInput, { backingUri: resource, config }); - return editorService.openEditor(input, { ...options, ignoreOverrides: true }, group); - })() - }; + return { + override: (async () => { + const { config } = await instantiationService.invokeFunction(parseSavedSearchEditor, resource); + const input = instantiationService.invokeFunction(getOrMakeSearchEditorInput, { backingUri: resource, config }); + return editorService.openEditor(input, { ...options, ignoreOverrides: true }, group); + })() + }; + } }); } } diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 877db95e28565a2a1f5fa9585e1a7df1a5e60203..ea360f390d5fa1abd70613386f910053962c786c 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -17,7 +17,7 @@ import { URI } from 'vs/base/common/uri'; import { basename, isEqualOrParent, joinPath } from 'vs/base/common/resources'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IEditorGroupsService, IEditorGroup, GroupsOrder, IEditorReplacement, GroupChangeKind, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IResourceEditorInputType, SIDE_GROUP, IResourceEditorReplacement, IOpenEditorOverrideHandler, IEditorService, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE, ISaveEditorsOptions, ISaveAllEditorsOptions, IRevertAllEditorsOptions, IBaseSaveRevertAllEditorOptions } from 'vs/workbench/services/editor/common/editorService'; +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'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Disposable, IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { coalesce, distinct, insert } from 'vs/base/common/arrays'; @@ -477,13 +477,23 @@ export class EditorService extends Disposable implements EditorServiceImpl { return toDisposable(() => remove()); } + getEditorOverrides(editorInput: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup | undefined): [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry][] { + const ret = []; + for (const handler of this.openEditorHandlers) { + const handlers = handler.getEditorOverrides ? handler.getEditorOverrides(editorInput, options, group).map(val => { return [handler, val] as [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry]; }) : []; + ret.push(...handlers); + } + + return ret; + } + private onGroupWillOpenEditor(group: IEditorGroup, event: IEditorOpeningEvent): void { if (event.options && event.options.ignoreOverrides) { return; } for (const handler of this.openEditorHandlers) { - const result = handler(event.editor, event.options, group); + const result = handler.open(event.editor, event.options, group); const override = result?.override; if (override) { event.prevent((() => override.then(editor => withNullAsUndefined(editor)))); @@ -1110,6 +1120,10 @@ export class DelegatingEditorService implements IEditorService { @IEditorService private editorService: EditorService ) { } + getEditorOverrides(editorInput: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup | undefined) { + return []; + } + openEditor(editor: IEditorInput, options?: IEditorOptions | ITextEditorOptions, group?: OpenInEditorGroup): Promise; openEditor(editor: IResourceEditorInput | IUntitledTextResourceEditorInput, group?: OpenInEditorGroup): Promise; openEditor(editor: IResourceDiffEditorInput, group?: OpenInEditorGroup): Promise; diff --git a/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts index 4b401b8acce6a2ecde42c8ce5fc4fee693ebd053..360e7434fbe2e5773c3802b92bed92bce8bf25e4 100644 --- a/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -26,8 +26,16 @@ export type ACTIVE_GROUP_TYPE = typeof ACTIVE_GROUP; export const SIDE_GROUP = -2; export type SIDE_GROUP_TYPE = typeof SIDE_GROUP; +export interface IOpenEditorOverrideEntry { + id: string; + label: string; + active: boolean; + detail?: string; +} + export interface IOpenEditorOverrideHandler { - (editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup): IOpenEditorOverride | undefined; + open(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup, id?: string): IOpenEditorOverride | undefined; + getEditorOverrides?(editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup | undefined): IOpenEditorOverrideEntry[]; } export interface IOpenEditorOverride { @@ -201,6 +209,11 @@ export interface IEditorService { isOpen(editor: IResourceEditorInput): boolean; isOpen(editor: IEditorInput): boolean; + /** + * Get all available editor overrides for the editor input. + */ + getEditorOverrides(editorInput: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup | undefined): [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry][]; + /** * Allows to override the opening of editors by installing a handler that will * be called each time an editor is about to open allowing to override the diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index 90f3c5fee0408800825e9cac880fa2630e75c27a..11d828ea967ec60696144f4393356e4b90bef5db 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -963,14 +963,16 @@ suite('EditorService', () => { let overrideCalled = false; - const handler = service.overrideOpenEditor(editor => { - if (editor === input1) { - overrideCalled = true; + const handler = service.overrideOpenEditor({ + open: editor => { + if (editor === input1) { + overrideCalled = true; - return { override: service.openEditor(input2, { pinned: true }) }; - } + return { override: service.openEditor(input2, { pinned: true }) }; + } - return undefined; + return undefined; + } }); await service.openEditor(input1, { pinned: true }); diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index bf6ee67f306432c76dbae54395cd59c6207b3f40..cae22fd188056b694b5e47a6f4356cf39e3b5229 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -52,7 +52,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IDecorationsService, IResourceDecorationChangeEvent, IDecoration, IDecorationData, IDecorationsProvider } from 'vs/workbench/services/decorations/browser/decorations'; import { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IAddGroupOptions, IMergeGroupOptions, IMoveEditorOptions, ICopyEditorOptions, IEditorReplacement, IGroupChangeEvent, IFindGroupScope, EditorGroupLayout, ICloseEditorOptions, GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IEditorService, IOpenEditorOverrideHandler, ISaveEditorsOptions, IRevertAllEditorsOptions, IResourceEditorInputType, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorService, IOpenEditorOverrideHandler, ISaveEditorsOptions, IRevertAllEditorsOptions, IResourceEditorInputType, SIDE_GROUP_TYPE, ACTIVE_GROUP_TYPE, IOpenEditorOverrideEntry } from 'vs/workbench/services/editor/common/editorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IEditorRegistry, EditorDescriptor, Extensions } from 'vs/workbench/browser/editor'; import { EditorGroup } from 'vs/workbench/common/editor/editorGroup'; @@ -629,6 +629,7 @@ export class TestEditorService implements EditorServiceImpl { constructor(private editorGroupService?: IEditorGroupsService) { } getEditors() { return []; } + getEditorOverrides(editorInput: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup | undefined): [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry][] { return []; } overrideOpenEditor(_handler: IOpenEditorOverrideHandler): IDisposable { return toDisposable(() => undefined); } openEditor(editor: IEditorInput, options?: IEditorOptions | ITextEditorOptions, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; openEditor(editor: IResourceEditorInput | IUntitledTextResourceEditorInput, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise;