Add editor contribution tests (#8784)

* wip

* rewrite association

* fix tests

* add more tests

* fix tests

* fix more tests

* fix tests
This commit is contained in:
Anthony Dresser
2020-01-10 18:57:47 -08:00
committed by GitHub
parent 0059ffb777
commit 2f6c944317
16 changed files with 421 additions and 75 deletions

View File

@@ -11,7 +11,6 @@ import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/ed
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Registry } from 'vs/platform/registry/common/platform';
import * as path from 'vs/base/common/path';
@@ -25,7 +24,6 @@ export class EditorReplacementContribution implements IWorkbenchContribution {
constructor(
@IEditorService private readonly editorService: IEditorService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IModeService private readonly modeService: IModeService
) {
this.editorOpeningListener = this.editorService.overrideOpenEditor((editor, options, group) => this.onEditorOpening(editor, options, group));
@@ -48,8 +46,6 @@ export class EditorReplacementContribution implements IWorkbenchContribution {
language = editor.getPreferredMode();
} else if (editor instanceof UntitledTextEditorInput) {
language = editor.getMode();
} else {
return undefined;
}
if (!language) { // in the case the input doesn't have a preferred mode set we will attempt to guess the mode from the file path
@@ -62,18 +58,18 @@ export class EditorReplacementContribution implements IWorkbenchContribution {
}
if (!language) {
const defaultInputCreator = languageAssociationRegistry.getAssociations().filter(e => e.isDefault)[0];
const defaultInputCreator = languageAssociationRegistry.defaultAssociation;
if (defaultInputCreator) {
editor.setMode(defaultInputCreator.language);
const newInput = this.instantiationService.invokeFunction(defaultInputCreator.creator, editor);
editor.setMode(defaultInputCreator[0]);
const newInput = defaultInputCreator[1].convertInput(editor);
if (newInput) {
return { override: this.editorService.openEditor(newInput, options, group) };
}
}
} else {
const inputCreator = languageAssociationRegistry.getAssociations().filter(e => e.language === language)[0];
const inputCreator = languageAssociationRegistry.getAssociationForLanguage(language);
if (inputCreator) {
const newInput = this.instantiationService.invokeFunction(inputCreator.creator, editor);
const newInput = inputCreator.convertInput(editor);
if (newInput) {
return { override: this.editorService.openEditor(newInput, options, group) };
}

View File

@@ -5,29 +5,75 @@
import { Registry } from 'vs/platform/registry/common/platform';
import { IEditorInput, EditorInput } from 'vs/workbench/common/editor';
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { find } from 'vs/base/common/arrays';
import { ServicesAccessor, IInstantiationService, BrandedService } from 'vs/platform/instantiation/common/instantiation';
import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledTextEditorInput';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
import { getCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
export type InputCreator = (servicesAccessor: ServicesAccessor, activeEditor: IEditorInput) => EditorInput | undefined;
export type BaseInputCreator = (activeEditor: IEditorInput) => IEditorInput;
export interface ILanguageAssociation {
convertInput(activeEditor: IEditorInput): EditorInput | undefined;
createBase(activeEditor: IEditorInput): IEditorInput;
}
type ILanguageAssociationSignature<Services extends BrandedService[]> = new (...services: Services) => ILanguageAssociation;
export interface ILanguageAssociationRegistry {
registerLanguageAssociation(language: string, creator: InputCreator, baseInputCreator: BaseInputCreator, isDefault?: boolean): void;
getAssociations(): Array<{ language: string, creator: InputCreator, baseInputCreator: BaseInputCreator, isDefault: boolean }>;
registerLanguageAssociation<Services extends BrandedService[]>(languages: string[], contribution: ILanguageAssociationSignature<Services>, isDefault?: boolean): IDisposable;
getAssociationForLanguage(language: string): ILanguageAssociation;
readonly defaultAssociation: [string, ILanguageAssociation];
/**
* Starts the registry by providing the required services.
*/
start(accessor: ServicesAccessor): void;
}
const languageAssociationRegistery = new class implements ILanguageAssociationRegistry {
private associations = new Array<{ language: string, creator: InputCreator, baseInputCreator: BaseInputCreator, isDefault: boolean }>();
private associationsInstances = new Map<string, ILanguageAssociation>();
private associationContructors = new Map<string, ILanguageAssociationSignature<BrandedService[]>>();
private defaultAssociationsInstance?: [string, ILanguageAssociation];
private defaultAssociationsConstructor?: [string, ILanguageAssociationSignature<BrandedService[]>];
registerLanguageAssociation(language: string, creator: InputCreator, baseInputCreator: BaseInputCreator, isDefault: boolean = false): void {
this.associations.push({ language, creator, baseInputCreator, isDefault });
start(accessor: ServicesAccessor): void {
const instantiationService = accessor.get(IInstantiationService);
for (const [language, ctor] of this.associationContructors) {
const instance = instantiationService.createInstance(ctor);
this.associationsInstances.set(language, instance);
}
if (this.defaultAssociationsConstructor) {
this.defaultAssociationsInstance = [this.defaultAssociationsConstructor[0], instantiationService.createInstance(this.defaultAssociationsConstructor[1])];
}
}
getAssociations(): Array<{ language: string, creator: InputCreator, baseInputCreator: BaseInputCreator, isDefault: boolean }> {
return this.associations.slice();
registerLanguageAssociation<Services extends BrandedService[]>(languages: string[], contribution: ILanguageAssociationSignature<Services>, isDefault?: boolean): IDisposable {
for (const language of languages) {
this.associationContructors.set(language, contribution);
}
if (isDefault) {
this.defaultAssociationsConstructor = [languages[0], contribution];
}
return toDisposable(() => {
for (const language of languages) {
this.associationContructors.delete(language);
this.associationsInstances.delete(language);
}
});
}
getAssociationForLanguage(language: string): ILanguageAssociation | undefined {
return this.associationsInstances.get(language);
}
get defaultAssociation(): [string, ILanguageAssociation] | undefined {
return this.defaultAssociationsInstance;
}
};
@@ -37,15 +83,14 @@ export const Extensions = {
Registry.add(Extensions.LanguageAssociations, languageAssociationRegistery);
export function doHandleUpgrade(accessor: ServicesAccessor, editor: EditorInput): EditorInput {
export function doHandleUpgrade(editor: EditorInput): EditorInput {
if (editor instanceof UntitledTextEditorInput || editor instanceof FileEditorInput) {
const instantiationService = accessor.get(IInstantiationService);
const activeWidget = getCodeEditor(editor);
const textModel = activeWidget.getModel();
const oldLanguage = textModel.getLanguageIdentifier().language;
const association = find(languageAssociationRegistery.getAssociations(), l => l.language === oldLanguage);
const association = languageAssociationRegistery.getAssociationForLanguage(oldLanguage);
if (association) {
return instantiationService.invokeFunction(association.creator, editor);
return association.convertInput(editor);
}
}
return editor;