Revert "Support multiple partial registrations to resolver (#155859)" (#156157)

* Revert "Support multiple partial registrations to resolver (#155859)"

This reverts commit a3c4e5ffce.

* Fix compilation
This commit is contained in:
Logan Ramos 2022-07-25 10:27:25 -04:00 committed by GitHub
parent 7d7df31b8e
commit 2af49c5bea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 84 additions and 177 deletions

View file

@ -275,9 +275,3 @@ export type UriDto<T> = { [K in keyof T]: T[K] extends URI
export function assertNever(value: never, message = 'Unreachable'): never {
throw new Error(message);
}
/**
* Given an object with all optional properties, requires at least one to be defined.
* i.e. AtLeastOne<MyObject>;
*/
export type AtLeastOne<T, U = { [K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];

View file

@ -578,7 +578,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
input2: { resource: filesToMerge[1].resource },
base: { resource: filesToMerge[2].resource },
result: { resource: filesToMerge[3].resource },
options: { pinned: true }
options: { pinned: true, override: 'mergeEditor.Input' } // TODO@bpasero remove the override once the resolver is ready
}];
}

View file

@ -484,8 +484,6 @@ export interface IResourceDiffEditorInput extends IBaseUntypedEditorInput {
readonly modified: IResourceEditorInput | ITextResourceEditorInput | IUntitledTextResourceEditorInput;
}
export type IResourceMergeEditorInputSide = (IResourceEditorInput | ITextResourceEditorInput) & { detail?: string };
/**
* A resource merge editor input compares multiple editors
* highlighting the differences for merging.
@ -498,12 +496,12 @@ export interface IResourceMergeEditorInput extends IBaseUntypedEditorInput {
/**
* The one changed version of the file.
*/
readonly input1: IResourceMergeEditorInputSide;
readonly input1: IResourceEditorInput | ITextResourceEditorInput;
/**
* The second changed version of the file.
*/
readonly input2: IResourceMergeEditorInputSide;
readonly input2: IResourceEditorInput | ITextResourceEditorInput;
/**
* The base common ancestor of the file to merge.

View file

@ -9,11 +9,11 @@ import { localize } from 'vs/nls';
import { ILocalizedString } from 'vs/platform/action/common/action';
import { Action2, IAction2Options, MenuId } from 'vs/platform/actions/common/actions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { EditorResolution } from 'vs/platform/editor/common/editor';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { API_OPEN_DIFF_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands';
import { IResourceMergeEditorInput } from 'vs/workbench/common/editor';
import { MergeEditorInputData } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput';
import { MergeEditorInput, MergeEditorInputData } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput';
import { MergeEditor } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor';
import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel';
import { ctxIsMergeEditor, ctxMergeEditorLayout } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor';
@ -48,14 +48,15 @@ export class OpenMergeEditor extends Action2 {
run(accessor: ServicesAccessor, ...args: unknown[]): void {
const validatedArgs = IRelaxedOpenArgs.validate(args[0]);
const input: IResourceMergeEditorInput = {
base: { resource: validatedArgs.base },
input1: { resource: validatedArgs.input1.uri, label: validatedArgs.input1.title, description: validatedArgs.input1.description, detail: validatedArgs.input1.detail },
input2: { resource: validatedArgs.input2.uri, label: validatedArgs.input2.title, description: validatedArgs.input2.description, detail: validatedArgs.input2.detail },
result: { resource: validatedArgs.output },
options: { preserveFocus: true }
};
accessor.get(IEditorService).openEditor(input);
const instaService = accessor.get(IInstantiationService);
const input = instaService.createInstance(
MergeEditorInput,
validatedArgs.base,
validatedArgs.input1,
validatedArgs.input2,
validatedArgs.output,
);
accessor.get(IEditorService).openEditor(input, { preserveFocus: true, override: EditorResolution.DISABLED });
}
}

View file

@ -10,15 +10,16 @@ import { localize } from 'vs/nls';
import { Action2 } from 'vs/platform/actions/common/actions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { MergeEditor } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IWorkbenchFileService } from 'vs/workbench/services/files/common/files';
import { URI } from 'vs/base/common/uri';
import { IResourceMergeEditorInput } from 'vs/workbench/common/editor';
import { MergeEditorInput } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput';
import { ctxIsMergeEditor } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor';
import { EditorResolution } from 'vs/platform/editor/common/editor';
interface MergeEditorContents {
languageId: string;
@ -98,10 +99,11 @@ export class MergeEditorOpenContents extends Action2 {
async run(accessor: ServicesAccessor): Promise<void> {
const service = accessor.get(IWorkbenchFileService);
const instaService = accessor.get(IInstantiationService);
const editorService = accessor.get(IEditorService);
const inputService = accessor.get(IQuickInputService);
const clipboardService = accessor.get(IClipboardService);
const textModelService = accessor.get(ITextModelService);
const editorService = accessor.get(IEditorService);
const result = await inputService.input({
prompt: localize('mergeEditor.enterJSON', 'Enter JSON'),
@ -152,12 +154,13 @@ export class MergeEditorOpenContents extends Action2 {
setLanguageId(resultUri, content.languageId),
]);
const input: IResourceMergeEditorInput = {
base: { resource: baseUri },
input1: { resource: input1Uri, label: 'Input 1', description: 'Input 1', detail: '(from JSON)' },
input2: { resource: input2Uri, label: 'Input 2', description: 'Input 2', detail: '(from JSON)' },
result: { resource: resultUri },
};
editorService.openEditor(input);
const input = instaService.createInstance(
MergeEditorInput,
baseUri,
{ uri: input1Uri, title: 'Input 1', description: 'Input 1', detail: '(from JSON)' },
{ uri: input2Uri, title: 'Input 2', description: 'Input 2', detail: '(from JSON)' },
resultUri,
);
editorService.openEditor(input, { override: EditorResolution.DISABLED });
}
}

View file

@ -140,8 +140,8 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements
override toUntyped(): IResourceMergeEditorInput {
return {
input1: { resource: this.input1.uri, label: this.input1.title, description: this.input1.description, detail: this.input1.detail },
input2: { resource: this.input2.uri, label: this.input2.title, description: this.input2.description, detail: this.input2.detail },
input1: { resource: this.input1.uri, label: this.input1.title, description: this.input1.description },
input2: { resource: this.input2.uri, label: this.input2.title, description: this.input2.description },
base: { resource: this.base },
result: { resource: this.result },
options: {

View file

@ -47,7 +47,7 @@ import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/v
import { ctxMergeBaseUri, ctxIsMergeEditor, ctxMergeEditorLayout, ctxMergeResultUri, MergeEditorLayoutTypes } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor';
import { settingsSashBorder } from 'vs/workbench/contrib/preferences/common/settingsEditorColorRegistry';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorResolverService, MergeEditorInputFactoryFunction, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService';
import { EditorInputFactoryFunction, IEditorResolverService, MergeEditorInputFactoryFunction, RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorResolverService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import './colors';
import { InputCodeEditorView } from './editors/inputCodeEditorView';
@ -559,6 +559,28 @@ export class MergeEditorResolverContribution extends Disposable {
) {
super();
const editorInputFactory: EditorInputFactoryFunction = (editor) => {
return {
editor: instantiationService.createInstance(
MergeEditorInput,
editor.resource,
{
uri: editor.resource,
title: '',
description: '',
detail: ''
},
{
uri: editor.resource,
title: '',
description: '',
detail: ''
},
editor.resource
)
};
};
const mergeEditorInputFactory: MergeEditorInputFactoryFunction = (mergeEditor: IResourceMergeEditorInput): EditorInputWithOptions => {
return {
editor: instantiationService.createInstance(
@ -566,15 +588,15 @@ export class MergeEditorResolverContribution extends Disposable {
mergeEditor.base.resource,
{
uri: mergeEditor.input1.resource,
title: mergeEditor.input1.label ?? basename(mergeEditor.input1.resource),
description: mergeEditor.input1.description ?? '',
detail: mergeEditor.input1.detail
title: basename(mergeEditor.input1.resource),
description: '',
detail: ''
},
{
uri: mergeEditor.input2.resource,
title: mergeEditor.input2.label ?? basename(mergeEditor.input2.resource),
description: mergeEditor.input2.description ?? '',
detail: mergeEditor.input2.detail
title: basename(mergeEditor.input2.resource),
description: '',
detail: ''
},
mergeEditor.result.resource
)
@ -584,13 +606,14 @@ export class MergeEditorResolverContribution extends Disposable {
this._register(editorResolverService.registerEditor(
`*`,
{
id: DEFAULT_EDITOR_ASSOCIATION.id,
label: DEFAULT_EDITOR_ASSOCIATION.displayName,
id: MergeEditorInput.ID,
label: localize('editor.mergeEditor.label', "Merge Editor"),
detail: DEFAULT_EDITOR_ASSOCIATION.providerDisplayName,
priority: RegisteredEditorPriority.builtin
priority: RegisteredEditorPriority.option
},
{},
{
createEditorInput: editorInputFactory,
createMergeEditorInput: mergeEditorInputFactory
}
));

View file

@ -57,8 +57,10 @@ import { IUserDataInitializationService } from 'vs/workbench/services/userData/b
import { MarkdownString } from 'vs/base/common/htmlContent';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
import { MergeEditorInput } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { ctxIsMergeEditor, ctxMergeBaseUri } from 'vs/workbench/contrib/mergeEditor/common/mergeEditor';
import { EditorResolution } from 'vs/platform/editor/common/editor';
const CONTEXT_CONFLICTS_SOURCES = new RawContextKey<string>('conflictsSources', '');
@ -728,12 +730,14 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
for (const conflict of conflicts) {
const remoteResourceName = localize({ key: 'remoteResourceName', comment: ['remote as in file in cloud'] }, "{0} (Remote)", basename(conflict.remoteResource));
const localResourceName = localize('localResourceName', "{0} (Local)", basename(conflict.remoteResource));
await this.editorService.openEditor({
input1: { resource: conflict.remoteResource, label: localize('Theirs', 'Theirs'), description: remoteResourceName },
input2: { resource: conflict.localResource, label: localize('Yours', 'Yours'), description: localResourceName },
base: { resource: conflict.baseResource },
result: { resource: conflict.previewResource }
});
const input = this.instantiationService.createInstance(
MergeEditorInput,
conflict.baseResource,
{ title: localize('Yours', 'Yours'), description: localResourceName, detail: undefined, uri: conflict.localResource },
{ title: localize('Theirs', 'Theirs'), description: remoteResourceName, detail: undefined, uri: conflict.remoteResource },
conflict.previewResource,
);
await this.editorService.openEditor(input, { override: EditorResolution.DISABLED });
}
}

View file

@ -915,7 +915,7 @@ export class NativeWindow extends Disposable {
input2: { resource: resources[1].resource },
base: { resource: resources[2].resource },
result: { resource: resources[3].resource },
options: { pinned: true }
options: { pinned: true, override: 'mergeEditor.Input' } // TODO@bpasero remove the override once the resolver is ready
};
editors.push(mergeEditor);
} else if (diffMode && isResourceEditorInput(resources[0]) && isResourceEditorInput(resources[1])) {

View file

@ -51,8 +51,7 @@ export class EditorResolverService extends Disposable implements IEditorResolver
private static readonly conflictingDefaultsStorageID = 'editorOverrideService.conflictingDefaults';
// Data Stores
private _editors: Map<string | glob.IRelativePattern, Map<string, RegisteredEditors>> = new Map<string | glob.IRelativePattern, Map<string, RegisteredEditors>>();
private _flattenedEditors: Map<string | glob.IRelativePattern, RegisteredEditors> = new Map();
private _editors: Map<string | glob.IRelativePattern, RegisteredEditors> = new Map<string | glob.IRelativePattern, RegisteredEditors>();
private cache: Set<string> | undefined;
constructor(
@ -236,29 +235,18 @@ export class EditorResolverService extends Disposable implements IEditorResolver
): IDisposable {
let registeredEditor = this._editors.get(globPattern);
if (registeredEditor === undefined) {
registeredEditor = new Map<string, RegisteredEditors>();
registeredEditor = [];
this._editors.set(globPattern, registeredEditor);
}
let editorsWithId = registeredEditor.get(editorInfo.id);
if (editorsWithId === undefined) {
editorsWithId = [];
}
const remove = insert(editorsWithId, {
const remove = insert(registeredEditor, {
globPattern,
editorInfo,
options,
editorFactoryObject
});
registeredEditor.set(editorInfo.id, editorsWithId);
this._flattenedEditors = this._flattenEditorsMap();
this._onDidChangeEditorRegistrations.fire();
return toDisposable(() => {
remove();
if (editorsWithId && editorsWithId.length === 0) {
registeredEditor?.delete(editorInfo.id);
}
this._flattenedEditors = this._flattenEditorsMap();
this._onDidChangeEditorRegistrations.fire();
});
}
@ -293,43 +281,11 @@ export class EditorResolverService extends Disposable implements IEditorResolver
return associations;
}
/**
* Given the nested nature of the editors map, we should merge factories of the same glob and id to make it flat
*/
private _flattenEditorsMap() {
const editors = new Map<string | glob.IRelativePattern, RegisteredEditors>();
for (const [glob, value] of this._editors) {
const registeredEditors: RegisteredEditors = [];
for (const editors of value.values()) {
let registeredEditor: RegisteredEditor | undefined = undefined;
// Merge all editors with the same id and glob pattern together
for (const editor of editors) {
if (!registeredEditor) {
registeredEditor = {
editorInfo: editor.editorInfo,
globPattern: editor.globPattern,
options: {},
editorFactoryObject: {}
};
}
// Merge options and factories
registeredEditor.options = { ...registeredEditor.options, ...editor.options };
registeredEditor.editorFactoryObject = { ...registeredEditor.editorFactoryObject, ...editor.editorFactoryObject };
}
if (registeredEditor) {
registeredEditors.push(registeredEditor);
}
}
editors.set(glob, registeredEditors);
}
return editors;
}
/**
* Returns all editors as an array. Possible to contain duplicates
*/
private get _registeredEditors(): RegisteredEditors {
return flatten(Array.from(this._flattenedEditors.values()));
return flatten(Array.from(this._editors.values()));
}
updateUserAssociations(globPattern: string, editorID: string): void {
@ -350,7 +306,7 @@ export class EditorResolverService extends Disposable implements IEditorResolver
const userSettings = this.getAssociationsForResource(resource);
const matchingEditors: RegisteredEditor[] = [];
// Then all glob patterns
for (const [key, editors] of this._flattenedEditors) {
for (const [key, editors] of this._editors) {
for (const editor of editors) {
const foundInSettings = userSettings.find(setting => setting.viewType === editor.editorInfo.id);
if ((foundInSettings && editor.editorInfo.priority !== RegisteredEditorPriority.exclusive) || globMatchesResource(key, resource)) {
@ -490,11 +446,6 @@ export class EditorResolverService extends Disposable implements IEditorResolver
}
}
// If no factory is above, return flow back to caller letting them know we could not resolve it
if (!selectedEditor.editorFactoryObject.createEditorInput) {
return;
}
// Respect options passed back
const inputWithOptions = await selectedEditor.editorFactoryObject.createEditorInput(editor, group);
options = inputWithOptions.options ?? options;
@ -788,7 +739,7 @@ export class EditorResolverService extends Disposable implements IEditorResolver
const cacheStorage: Set<string> = new Set<string>();
// Store just the relative pattern pieces without any path info
for (const [globPattern, contribPoint] of this._flattenedEditors) {
for (const [globPattern, contribPoint] of this._editors) {
const nonOptional = !!contribPoint.find(c => c.editorInfo.priority !== RegisteredEditorPriority.option && c.editorInfo.id !== DEFAULT_EDITOR_ASSOCIATION.id);
// Don't keep a cache of the optional ones as those wouldn't be opened on start anyways
if (!nonOptional) {

View file

@ -19,7 +19,6 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { EditorInputWithOptions, EditorInputWithOptionsAndGroup, IResourceDiffEditorInput, IResourceMergeEditorInput, IUntitledTextResourceEditorInput, IUntypedEditorInput } from 'vs/workbench/common/editor';
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
import { PreferredGroup } from 'vs/workbench/services/editor/common/editorService';
import { AtLeastOne } from 'vs/base/common/types';
export const IEditorResolverService = createDecorator<IEditorResolverService>('editorResolverService');
@ -110,15 +109,13 @@ export type DiffEditorInputFactoryFunction = (diffEditorInput: IResourceDiffEdit
export type MergeEditorInputFactoryFunction = (mergeEditorInput: IResourceMergeEditorInput, group: IEditorGroup) => EditorInputFactoryResult;
type EditorInputFactories = {
createEditorInput?: EditorInputFactoryFunction;
export type EditorInputFactoryObject = {
createEditorInput: EditorInputFactoryFunction;
createUntitledEditorInput?: UntitledEditorInputFactoryFunction;
createDiffEditorInput?: DiffEditorInputFactoryFunction;
createMergeEditorInput?: MergeEditorInputFactoryFunction;
};
export type EditorInputFactoryObject = AtLeastOne<EditorInputFactories>;
export interface IEditorResolverService {
readonly _serviceBrand: undefined;
/**
@ -141,8 +138,7 @@ export interface IEditorResolverService {
readonly onDidChangeEditorRegistrations: Event<void>;
/**
* Registers a specific editor. Editors with the same glob pattern and ID will be grouped together by the resolver.
* This allows for registration of the factories in different locations
* Registers a specific editor.
* @param globPattern The glob pattern for this registration
* @param editorInfo Information about the registration
* @param options Specific options which apply to this registration

View file

@ -382,67 +382,4 @@ suite('EditorResolverService', () => {
assert.strictEqual(service.getEditors().length, editors.length);
assert.strictEqual(service.getEditors().some(editor => editor.id === 'TEST_EDITOR'), false);
});
test('Multiple registrations to same glob and id #155859', async () => {
const [part, service, accessor] = await createEditorResolverService();
const testEditorInfo = {
id: 'TEST_EDITOR',
label: 'Test Editor Label',
detail: 'Test Editor Details',
priority: RegisteredEditorPriority.default
};
const registeredSingleEditor = service.registerEditor('*.test',
testEditorInfo,
{},
{
createEditorInput: ({ resource, options }, group) => ({ editor: new TestFileEditorInput(URI.parse(resource.toString()), TEST_EDITOR_INPUT_ID) })
}
);
const registeredDiffEditor = service.registerEditor('*.test',
testEditorInfo,
{},
{
createDiffEditorInput: ({ modified, original, options }, group) => ({
editor: accessor.instantiationService.createInstance(
DiffEditorInput,
'name',
'description',
new TestFileEditorInput(URI.parse(original.toString()), TEST_EDITOR_INPUT_ID),
new TestFileEditorInput(URI.parse(modified.toString()), TEST_EDITOR_INPUT_ID),
undefined)
})
}
);
// Resolve a diff
let resultingResolution = await service.resolveEditor({
original: { resource: URI.file('my://resource-basics.test') },
modified: { resource: URI.file('my://resource-basics.test') }
}, part.activeGroup);
assert.ok(resultingResolution);
assert.notStrictEqual(typeof resultingResolution, 'number');
if (resultingResolution !== ResolvedStatus.ABORT && resultingResolution !== ResolvedStatus.NONE) {
assert.strictEqual(resultingResolution.editor.typeId, 'workbench.editors.diffEditorInput');
resultingResolution.editor.dispose();
} else {
assert.fail();
}
// Remove diff registration
registeredDiffEditor.dispose();
// Resolve a diff again, expected failure
resultingResolution = await service.resolveEditor({
original: { resource: URI.file('my://resource-basics.test') },
modified: { resource: URI.file('my://resource-basics.test') }
}, part.activeGroup);
assert.ok(resultingResolution);
assert.strictEqual(typeof resultingResolution, 'number');
if (resultingResolution !== ResolvedStatus.NONE) {
assert.fail();
}
registeredSingleEditor.dispose();
});
});

View file

@ -268,7 +268,7 @@ export class BrowserHostService extends Disposable implements IHostService {
input2: { resource: editors[1].resource },
base: { resource: editors[2].resource },
result: { resource: editors[3].resource },
options: { pinned: true }
options: { pinned: true, override: 'mergeEditor.Input' } // TODO@bpasero remove the override once the resolver is ready
});
}