提交 31536dd6 编写于 作者: B Benjamin Pasero

editors - make findEditors more powerful

上级 c32f1cc4
......@@ -30,7 +30,6 @@ import { isWindows } from 'vs/base/common/platform';
import { Schemas } from 'vs/base/common/network';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { IEditorIdentifier, SaveReason } from 'vs/workbench/common/editor';
import { GroupsOrder, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { hash } from 'vs/base/common/hash';
export const CONFLICT_RESOLUTION_CONTEXT = 'saveConflictResolutionContext';
......@@ -321,8 +320,7 @@ class SaveModelAsAction extends Action {
constructor(
private model: ITextFileEditorModel,
@IEditorService private editorService: IEditorService,
@IEditorGroupsService private editorGroupService: IEditorGroupsService
@IEditorService private editorService: IEditorService
) {
super('workbench.files.action.saveModelAs', SAVE_FILE_AS_LABEL);
}
......@@ -338,25 +336,22 @@ class SaveModelAsAction extends Action {
private findEditor(): IEditorIdentifier | undefined {
let preferredMatchingEditor: IEditorIdentifier | undefined;
let otherMatchingEditors: IEditorIdentifier[] = [];
FindEditorLoop: for (const group of this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE)) {
const editors = this.editorService.findEditors(this.model.resource, group);
for (const editor of editors) {
if (editor instanceof FileEditorInput) {
// We prefer a `FileEditorInput` for "Save As", but it is possible
// that a custom editor is leveraging the text file model and as
// such we need to fallback to any other editor having the resource
// opened for running the save.
preferredMatchingEditor = { editor, groupId: group.id };
break FindEditorLoop;
}
otherMatchingEditors.push({ editor, groupId: group.id });
const editors = this.editorService.findEditors(this.model.resource);
for (const identifier of editors) {
if (identifier.editor instanceof FileEditorInput) {
// We prefer a `FileEditorInput` for "Save As", but it is possible
// that a custom editor is leveraging the text file model and as
// such we need to fallback to any other editor having the resource
// opened for running the save.
preferredMatchingEditor = identifier;
break;
} else if (!preferredMatchingEditor) {
preferredMatchingEditor = identifier;
}
}
return preferredMatchingEditor || otherMatchingEditors[0];
return preferredMatchingEditor;
}
}
......
......@@ -24,7 +24,7 @@ import { coalesce, distinct, firstOrDefault, insert } from 'vs/base/common/array
import { isCodeEditor, isDiffEditor, ICodeEditor, IDiffEditor, isCompositeEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorGroupView, EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { withNullAsUndefined } from 'vs/base/common/types';
import { isUndefined, withNullAsUndefined } from 'vs/base/common/types';
import { EditorsObserver } from 'vs/workbench/browser/parts/editor/editorsObserver';
import { IEditorViewState } from 'vs/editor/common/editorCommon';
import { IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
......@@ -856,17 +856,80 @@ export class EditorService extends Disposable implements EditorServiceImpl {
//#region findEditors()
findEditors(resource: URI, group: IEditorGroup | GroupIdentifier): ReadonlyArray<IEditorInput> {
findEditors(resource: URI): ReadonlyArray<IEditorIdentifier>;
findEditors(editor: IResourceEditorInputIdentifier): ReadonlyArray<IEditorIdentifier>;
findEditors(resource: URI, group: IEditorGroup | GroupIdentifier): ReadonlyArray<IEditorInput>;
findEditors(editor: IResourceEditorInputIdentifier, group: IEditorGroup | GroupIdentifier): IEditorInput | undefined;
findEditors(arg1: URI | IResourceEditorInputIdentifier, arg2?: IEditorGroup | GroupIdentifier): ReadonlyArray<IEditorIdentifier> | ReadonlyArray<IEditorInput> | IEditorInput | undefined;
findEditors(arg1: URI | IResourceEditorInputIdentifier, arg2?: IEditorGroup | GroupIdentifier): ReadonlyArray<IEditorIdentifier> | ReadonlyArray<IEditorInput> | IEditorInput | undefined {
const resource = URI.isUri(arg1) ? arg1 : arg1.resource;
const typeId = URI.isUri(arg1) ? undefined : arg1.typeId;
// Do a quick check for the resource via the editor observer
// which is a very efficient way to find an editor by resource
if (!this.editorsObserver.hasEditors(resource)) {
return []; // this is a very fast efficient check via editor observer
if (URI.isUri(arg1) || isUndefined(arg2)) {
return [];
}
return undefined;
}
const targetGroup = typeof group === 'number' ? this.editorGroupService.getGroup(group) : group;
if (!targetGroup) {
return [];
// Search only in specific group
if (!isUndefined(arg2)) {
const targetGroup = typeof arg2 === 'number' ? this.editorGroupService.getGroup(arg2) : arg2;
// Resource provided: result is an array
if (URI.isUri(arg1)) {
if (!targetGroup) {
return [];
}
return targetGroup.findEditors(resource);
}
// Editor identifier provided, result is single
else {
if (!targetGroup) {
return undefined;
}
const editors = targetGroup.findEditors(resource);
for (const editor of editors) {
if (editor.typeId === typeId) {
return editor;
}
}
return undefined;
}
}
return targetGroup.findEditors(resource);
// Search across all groups in MRU order
else {
const result: IEditorIdentifier[] = [];
for (const group of this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE)) {
const editors: IEditorInput[] = [];
// Resource provided: result is an array
if (URI.isUri(arg1)) {
editors.push(...this.findEditors(arg1, group));
}
// Editor identifier provided, result is single
else {
const editor = this.findEditors(arg1, group);
if (editor) {
editors.push(editor);
}
}
result.push(...editors.map(editor => ({ editor, groupId: group.id })));
}
return result;
}
}
//#endregion
......@@ -1321,7 +1384,11 @@ export class DelegatingEditorService implements IEditorService {
isOpened(editor: IResourceEditorInputIdentifier): boolean { return this.editorService.isOpened(editor); }
findEditors(resource: URI, group: IEditorGroup | GroupIdentifier): ReadonlyArray<IEditorInput> { return this.editorService.findEditors(resource, group); }
findEditors(resource: URI): ReadonlyArray<IEditorIdentifier>;
findEditors(resource: IResourceEditorInputIdentifier): ReadonlyArray<IEditorIdentifier>;
findEditors(resource: URI, group: IEditorGroup | GroupIdentifier): ReadonlyArray<IEditorInput>;
findEditors(resource: IResourceEditorInputIdentifier, group: IEditorGroup | GroupIdentifier): IEditorInput | undefined;
findEditors(arg1: URI | IResourceEditorInputIdentifier, arg2?: IEditorGroup | GroupIdentifier): ReadonlyArray<IEditorIdentifier> | ReadonlyArray<IEditorInput> | IEditorInput | undefined { return this.editorService.findEditors(arg1, arg2); }
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); }
......
......@@ -221,13 +221,17 @@ export interface IEditorService {
/**
* This method will return an entry for each editor that reports
* a `resource` that matches the provided one in the group.
* a `resource` that matches the provided one in the group or
* across all groups.
*
* It is possible that multiple editors are returned in case the
* same resource is opened in different editors. To find the specific
* editor, either check on the `typeId` or do an `instanceof` check.
* editor, use the `IResourceEditorInputIdentifier` as input.
*/
findEditors(resource: URI): ReadonlyArray<IEditorIdentifier>;
findEditors(resource: IResourceEditorInputIdentifier): ReadonlyArray<IEditorIdentifier>;
findEditors(resource: URI, group: IEditorGroup | GroupIdentifier): ReadonlyArray<IEditorInput>;
findEditors(resource: IResourceEditorInputIdentifier, group: IEditorGroup | GroupIdentifier): IEditorInput | undefined;
/**
* Get all available editor overrides for the editor input.
......
......@@ -1026,7 +1026,7 @@ suite('EditorService', () => {
handler.dispose();
});
test('findEditors', async () => {
test('findEditors (in group)', async () => {
const [part, service] = await createEditorService();
const input = new TestFileEditorInput(URI.parse('my://resource-openEditors'), TEST_EDITOR_INPUT_ID);
......@@ -1038,35 +1038,111 @@ suite('EditorService', () => {
// Try using find editors for opened editors
{
const found = service.findEditors(input.resource, part.activeGroup);
assert.strictEqual(found.length, 1);
assert.strictEqual(found[0], input);
const found1 = service.findEditors(input.resource, part.activeGroup);
assert.strictEqual(found1.length, 1);
assert.strictEqual(found1[0], input);
const found2 = service.findEditors(input, part.activeGroup);
assert.strictEqual(found2, input);
}
{
const found = service.findEditors(otherInput.resource, part.activeGroup);
assert.strictEqual(found.length, 1);
assert.strictEqual(found[0], otherInput);
const found1 = service.findEditors(otherInput.resource, part.activeGroup);
assert.strictEqual(found1.length, 1);
assert.strictEqual(found1[0], otherInput);
const found2 = service.findEditors(otherInput, part.activeGroup);
assert.strictEqual(found2, otherInput);
}
// Make sure we don't find non-opened editors
{
const found = service.findEditors(URI.parse('my://no-such-resource'), part.activeGroup);
assert.strictEqual(found.length, 0);
const found1 = service.findEditors(URI.parse('my://no-such-resource'), part.activeGroup);
assert.strictEqual(found1.length, 0);
const found2 = service.findEditors({ resource: URI.parse('my://no-such-resource'), typeId: '' }, part.activeGroup);
assert.strictEqual(found2, undefined);
}
// 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.strictEqual(found.length, 0);
const found1 = service.findEditors(input.resource, newEditor!.group!.id);
assert.strictEqual(found1.length, 0);
const found2 = service.findEditors(input, newEditor!.group!.id);
assert.strictEqual(found2, undefined);
}
// Check we don't find editors after closing them
await part.activeGroup.closeAllEditors();
{
const found = service.findEditors(input.resource, part.activeGroup);
assert.strictEqual(found.length, 0);
const found1 = service.findEditors(input.resource, part.activeGroup);
assert.strictEqual(found1.length, 0);
const found2 = service.findEditors(input, part.activeGroup);
assert.strictEqual(found2, undefined);
}
});
test('findEditors (across groups)', async () => {
const [part, service] = await createEditorService();
const rootGroup = part.activeGroup;
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);
// Open editors
await service.openEditors([{ editor: input }, { editor: otherInput }]);
const sideEditor = await service.openEditor(input, { pinned: true }, SIDE_GROUP);
// Try using find editors for opened editors
{
const found1 = service.findEditors(input.resource);
assert.strictEqual(found1.length, 2);
assert.strictEqual(found1[0].editor, input);
assert.strictEqual(found1[0].groupId, sideEditor?.group?.id);
assert.strictEqual(found1[1].editor, input);
assert.strictEqual(found1[1].groupId, rootGroup.id);
const found2 = service.findEditors(input);
assert.strictEqual(found2.length, 2);
assert.strictEqual(found2[0].editor, input);
assert.strictEqual(found2[0].groupId, sideEditor?.group?.id);
assert.strictEqual(found2[1].editor, input);
assert.strictEqual(found2[1].groupId, rootGroup.id);
}
{
const found1 = service.findEditors(otherInput.resource);
assert.strictEqual(found1.length, 1);
assert.strictEqual(found1[0].editor, otherInput);
assert.strictEqual(found1[0].groupId, rootGroup.id);
const found2 = service.findEditors(otherInput);
assert.strictEqual(found2.length, 1);
assert.strictEqual(found2[0].editor, otherInput);
assert.strictEqual(found2[0].groupId, rootGroup.id);
}
// Make sure we don't find non-opened editors
{
const found1 = service.findEditors(URI.parse('my://no-such-resource'));
assert.strictEqual(found1.length, 0);
const found2 = service.findEditors({ resource: URI.parse('my://no-such-resource'), typeId: '' });
assert.strictEqual(found2.length, 0);
}
// Check we don't find editors after closing them
await rootGroup.closeAllEditors();
await sideEditor?.group?.closeAllEditors();
{
const found1 = service.findEditors(input.resource);
assert.strictEqual(found1.length, 0);
const found2 = service.findEditors(input);
assert.strictEqual(found2.length, 0);
}
});
});
......@@ -781,7 +781,7 @@ export class TestEditorService implements EditorServiceImpl {
constructor(private editorGroupService?: IEditorGroupsService) { }
getEditors() { return []; }
findEditors() { return []; }
findEditors() { return [] as any; }
getEditorOverrides(resource: URI, 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<IEditorPane | undefined>;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册