未验证 提交 6c4a00ce 编写于 作者: M Matt Bierner 提交者: GitHub

Make default text editor replace existing editors for resource (#112848)

* Make default text editor replace existing editors for resource

Fixes #111474

This ports the logic that we previouly had for custom editors to the generic open with flow: https://github.com/microsoft/vscode/blob/f0bb23ca02f320816219017234e412caa425851e/src%2Fvs%2Fworkbench%2Fcontrib%2FcustomEditor%2Fbrowser%2FcustomEditors.ts#L281

* Add a new `getEditorsForResource` helper method to editor service

This adds a `IEditorService.getEditorsForResource` method that returns all editors associated with a given resource. I've adopted this for custom editors and notebooks

* Making suggested changes

* Add unit tests for findEditors
上级 a59f3001
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { coalesce, distinct } from 'vs/base/common/arrays';
import { coalesce, distinct, firstOrDefault } from 'vs/base/common/arrays';
import { Codicon } from 'vs/base/common/codicons';
import { Emitter, Event } from 'vs/base/common/event';
import { Lazy } from 'vs/base/common/lazy';
......@@ -154,13 +154,8 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
...this.getAllCustomEditors(resource).allEditors,
]);
let currentlyOpenedEditorType: undefined | string;
for (const editor of group ? group.editors : []) {
if (editor.resource && isEqual(editor.resource, resource)) {
currentlyOpenedEditorType = editor instanceof CustomEditorInput ? editor.viewType : defaultCustomEditor.id;
break;
}
}
const existingEditorForResource = group && firstOrDefault(this.editorService.findEditors(resource, group));
const currentlyOpenedEditorType: undefined | string = existingEditorForResource instanceof CustomEditorInput ? existingEditorForResource.viewType : defaultCustomEditor.id;
const resourceExt = extname(resource);
......@@ -276,9 +271,8 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ
}
// Try to replace existing editors for resource
const existingEditors = targetGroup.editors.filter(editor => editor.resource && isEqual(editor.resource, resource));
if (existingEditors.length) {
const existing = existingEditors[0];
const existing = firstOrDefault(this.editorService.findEditors(resource, targetGroup));
if (existing) {
if (!input.matches(existing)) {
await this.editorService.replaceEditors([{
editor: existing,
......@@ -453,7 +447,7 @@ export class CustomEditorContribution extends Disposable implements IWorkbenchCo
return this.onEditorOpening(editor, options, group);
},
getEditorOverrides: (resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined): IOpenEditorOverrideEntry[] => {
const currentEditor = group?.editors.find(editor => isEqual(editor.resource, resource));
const currentEditor = group && firstOrDefault(this.editorService.findEditors(resource, group));
const toOverride = (entry: CustomEditorInfo): IOpenEditorOverrideEntry => {
return {
......@@ -542,7 +536,7 @@ export class CustomEditorContribution extends Disposable implements IWorkbenchCo
return;
}
const existingEditorForResource = group.editors.find(editor => isEqual(resource, editor.resource));
const existingEditorForResource = firstOrDefault(this.editorService.findEditors(resource, group));
if (existingEditorForResource) {
if (editor === existingEditorForResource) {
return;
......
......@@ -230,7 +230,7 @@ export class NotebookContribution extends Disposable implements IWorkbenchContri
this._register(this.editorService.overrideOpenEditor({
getEditorOverrides: (resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined) => {
const currentEditorForResource = group?.editors.find(editor => isEqual(editor.resource, resource));
const currentEditorForResource = group && this.editorService.findEditors(resource, group);
const associatedEditors = distinct([
...this.getUserAssociatedNotebookEditors(resource),
......@@ -341,10 +341,8 @@ export class NotebookContribution extends Disposable implements IWorkbenchContri
}
if (id === undefined) {
const existingEditors = group.editors.filter(editor =>
editor.resource
&& isEqual(editor.resource, notebookUri)
&& !(editor instanceof NotebookEditorInput)
const existingEditors = this.editorService.findEditors(notebookUri, group).filter(editor =>
!(editor instanceof NotebookEditorInput)
&& !(editor instanceof NotebookDiffEditorInput)
);
......@@ -409,7 +407,7 @@ export class NotebookContribution extends Disposable implements IWorkbenchContri
return undefined;
}
const existingEditors = group.editors.filter(editor => editor.resource && isEqual(editor.resource, notebookUri) && !(editor instanceof NotebookEditorInput));
const existingEditors = this.editorService.findEditors(notebookUri, group).filter(editor => !(editor instanceof NotebookEditorInput));
if (existingEditors.length) {
return undefined;
......
......@@ -756,6 +756,26 @@ export class EditorService extends Disposable implements EditorServiceImpl {
//#endregion
//#region findEditor()
findEditors(resource: URI, group: IEditorGroup | GroupIdentifier): IEditorInput[] {
if (!this.isOpen({ resource })) {
return [];
}
const canonicalResource = this.asCanonicalEditorResource(resource);
const targetGroup = typeof group === 'number' ? this.editorGroupService.getGroup(group) : group;
if (!targetGroup) {
return [];
}
return targetGroup.getEditors(EditorsOrder.SEQUENTIAL).filter(editor => {
return editor.resource && isEqual(editor.resource, canonicalResource);
});
}
//#endregion
//#region replaceEditors()
async replaceEditors(editors: IResourceEditorReplacement[], group: IEditorGroup | GroupIdentifier): Promise<void>;
......@@ -1322,6 +1342,8 @@ export class DelegatingEditorService implements IEditorService {
isOpen(editor: IResourceEditorInput): boolean;
isOpen(editor: IEditorInput | IResourceEditorInput): boolean { return this.editorService.isOpen(editor as IResourceEditorInput /* TS fail */); }
findEditors(resource: URI, group: IEditorGroup | GroupIdentifier) { return this.editorService.findEditors(resource, group); }
overrideOpenEditor(handler: IOpenEditorOverrideHandler): IDisposable { return this.editorService.overrideOpenEditor(handler); }
getEditorOverrides(resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined) { return this.editorService.getEditorOverrides(resource, options, group); }
......
......@@ -9,7 +9,7 @@ import { IConfigurationNode, IConfigurationRegistry, Extensions } from 'vs/platf
import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration';
import { Registry } from 'vs/platform/registry/common/platform';
import { ICustomEditorInfo, IEditorService, IOpenEditorOverrideHandler, IOpenEditorOverrideEntry } from 'vs/workbench/services/editor/common/editorService';
import { IEditorInput, IEditorPane, IEditorInputFactoryRegistry, Extensions as EditorExtensions, EditorResourceAccessor } from 'vs/workbench/common/editor';
import { IEditorInput, IEditorPane, IEditorInputFactoryRegistry, Extensions as EditorExtensions, EditorResourceAccessor, EditorOptions } from 'vs/workbench/common/editor';
import { ITextEditorOptions, IEditorOptions } from 'vs/platform/editor/common/editor';
import { IEditorGroup, IEditorGroupsService, OpenEditorContext, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
......@@ -18,6 +18,7 @@ import { URI } from 'vs/base/common/uri';
import { extname, basename, isEqual } from 'vs/base/common/resources';
import { Codicon } from 'vs/base/common/codicons';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { firstOrDefault } from 'vs/base/common/arrays';
/**
* Id of the default editor for open with.
......@@ -214,7 +215,21 @@ export function getAllAvailableEditors(
const fileEditorInput = editorService.createEditorInput({ resource, forceFile: true });
const textOptions: IEditorOptions | ITextEditorOptions = options ? { ...options, override: false } : { override: false };
return { override: editorService.openEditor(fileEditorInput, textOptions, group) };
return {
override: (async () => {
// Try to replace existing editors for resource
const existingEditor = firstOrDefault(editorService.findEditors(resource, group));
if (existingEditor && !fileEditorInput.matches(existingEditor)) {
await editorService.replaceEditors([{
editor: existingEditor,
replacement: fileEditorInput,
options: options ? EditorOptions.create(options) : undefined,
}], group);
}
return editorService.openEditor(fileEditorInput, textOptions, group);
})()
};
}
},
{
......
......@@ -233,6 +233,11 @@ export interface IEditorService {
isOpen(editor: IResourceEditorInput): boolean;
isOpen(editor: IEditorInput): boolean;
/**
* Find the existing editors for a given resource.
*/
findEditors(resource: URI, group: IEditorGroup | GroupIdentifier): IEditorInput[];
/**
* Get all available editor overrides for the editor input.
*/
......
......@@ -1094,4 +1094,52 @@ suite('EditorService', () => {
part.dispose();
});
test('findEditors', async () => {
const [part, service] = createEditorService();
const input = new TestFileEditorInput(URI.parse('my://resource-openEditors'), TEST_EDITOR_INPUT_ID);
const otherInput = new TestFileEditorInput(URI.parse('my://resource2-openEditors'), TEST_EDITOR_INPUT_ID);
await part.whenRestored;
// Open editors
await service.openEditors([{ editor: input }, { editor: otherInput }]);
assert.equal(part.activeGroup.count, 2);
// Try using find editors for opened editors
{
const found = service.findEditors(input.resource, part.activeGroup);
assert.equal(found.length, 1);
assert.equal(found[0], input);
}
{
const found = service.findEditors(otherInput.resource, part.activeGroup);
assert.equal(found.length, 1);
assert.equal(found[0], otherInput);
}
// Make sure we don't find non-opened editors
{
const found = service.findEditors(URI.parse('my://no-such-resource'), part.activeGroup);
assert.equal(found.length, 0);
}
// Make sure we don't find editors across groups
{
const newEditor = await service.openEditor(new TestFileEditorInput(URI.parse('my://other-group-resource'), TEST_EDITOR_INPUT_ID), { pinned: true, preserveFocus: true }, SIDE_GROUP);
const found = service.findEditors(input.resource, newEditor!.group!.id);
assert.equal(found.length, 0);
}
// Check we don't find editors after closing them
await part.activeGroup.closeAllEditors();
{
const found = service.findEditors(input.resource, part.activeGroup);
assert.equal(found.length, 0);
}
part.dispose();
});
});
......@@ -704,6 +704,7 @@ export class TestEditorService implements EditorServiceImpl {
constructor(private editorGroupService?: IEditorGroupsService) { }
getEditors() { return []; }
findEditors() { return []; }
getEditorOverrides(resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined): [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry][] { return []; }
overrideOpenEditor(_handler: IOpenEditorOverrideHandler): IDisposable { return toDisposable(() => undefined); }
registerCustomEditorViewTypesHandler(source: string, handler: ICustomEditorViewTypesHandler): IDisposable {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册