editors - make findEditors more powerful
This commit is contained in:
parent
c32f1cc463
commit
31536dd690
5 changed files with 184 additions and 42 deletions
|
@ -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>;
|
||||
|
|
Loading…
Reference in a new issue