Extract TMGrammarFactory to its own file

This commit is contained in:
Alex Dima 2019-07-08 12:26:30 +02:00
parent 2329188776
commit c3f72b8b80
3 changed files with 152 additions and 139 deletions

View file

@ -23,10 +23,11 @@ import { ExtensionMessageCollector } from 'vs/workbench/services/extensions/comm
import { ITMSyntaxExtensionPoint, grammarsExtPoint } from 'vs/workbench/services/textMate/common/TMGrammars';
import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService';
import { ITokenColorizationRule, IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IGrammar, Registry, StackElement, IRawTheme, IOnigLib } from 'vscode-textmate';
import { IGrammar, StackElement, IOnigLib } from 'vscode-textmate';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TMScopeRegistry, IValidGrammarDefinition, IValidEmbeddedLanguagesMap, IValidTokenTypeMap } from 'vs/workbench/services/textMate/common/TMScopeRegistry';
import { IValidGrammarDefinition, IValidEmbeddedLanguagesMap, IValidTokenTypeMap } from 'vs/workbench/services/textMate/common/TMScopeRegistry';
import { TMGrammarFactory } from 'vs/workbench/services/textMate/common/TMGrammarFactory';
export abstract class AbstractTextMateService extends Disposable implements ITextMateService {
public _serviceBrand: any;
@ -316,142 +317,6 @@ export abstract class AbstractTextMateService extends Disposable implements ITex
protected abstract _loadOnigLib(): Promise<IOnigLib> | undefined;
}
interface ITMGrammarFactoryHost {
logTrace(msg: string): void;
logError(msg: string, err: any): void;
readFile(resource: URI): Promise<string>;
}
interface ICreateGrammarResult {
languageId: LanguageId;
grammar: IGrammar;
initialState: StackElement;
containsEmbeddedLanguages: boolean;
}
class TMGrammarFactory extends Disposable {
private readonly _host: ITMGrammarFactoryHost;
private readonly _initialState: StackElement;
private readonly _scopeRegistry: TMScopeRegistry;
private readonly _injections: { [scopeName: string]: string[]; };
private readonly _injectedEmbeddedLanguages: { [scopeName: string]: IValidEmbeddedLanguagesMap[]; };
private readonly _languageToScope2: string[];
private readonly _grammarRegistry: Registry;
constructor(host: ITMGrammarFactoryHost, grammarDefinitions: IValidGrammarDefinition[], vscodeTextmate: typeof import('vscode-textmate'), onigLib?: Promise<IOnigLib>) {
super();
this._host = host;
this._initialState = vscodeTextmate.INITIAL;
this._scopeRegistry = this._register(new TMScopeRegistry());
this._injections = {};
this._injectedEmbeddedLanguages = {};
this._languageToScope2 = [];
this._grammarRegistry = new vscodeTextmate.Registry({
getOnigLib: (typeof onigLib === 'undefined' ? undefined : () => onigLib),
loadGrammar: async (scopeName: string) => {
const grammarDefinition = this._scopeRegistry.getGrammarDefinition(scopeName);
if (!grammarDefinition) {
this._host.logTrace(`No grammar found for scope ${scopeName}`);
return null;
}
const location = grammarDefinition.location;
try {
const content = await this._host.readFile(location);
return vscodeTextmate.parseRawGrammar(content, location.path);
} catch (e) {
this._host.logError(`Unable to load and parse grammar for scope ${scopeName} from ${location}`, e);
return null;
}
},
getInjections: (scopeName: string) => {
const scopeParts = scopeName.split('.');
let injections: string[] = [];
for (let i = 1; i <= scopeParts.length; i++) {
const subScopeName = scopeParts.slice(0, i).join('.');
injections = [...injections, ...(this._injections[subScopeName] || [])];
}
return injections;
}
});
for (const validGrammar of grammarDefinitions) {
this._scopeRegistry.register(validGrammar);
if (validGrammar.injectTo) {
for (let injectScope of validGrammar.injectTo) {
let injections = this._injections[injectScope];
if (!injections) {
this._injections[injectScope] = injections = [];
}
injections.push(validGrammar.scopeName);
}
if (validGrammar.embeddedLanguages) {
for (let injectScope of validGrammar.injectTo) {
let injectedEmbeddedLanguages = this._injectedEmbeddedLanguages[injectScope];
if (!injectedEmbeddedLanguages) {
this._injectedEmbeddedLanguages[injectScope] = injectedEmbeddedLanguages = [];
}
injectedEmbeddedLanguages.push(validGrammar.embeddedLanguages);
}
}
}
if (validGrammar.language) {
this._languageToScope2[validGrammar.language] = validGrammar.scopeName;
}
}
}
public has(languageId: LanguageId): boolean {
return this._languageToScope2[languageId] ? true : false;
}
public setTheme(theme: IRawTheme): void {
this._grammarRegistry.setTheme(theme);
}
public getColorMap(): string[] {
return this._grammarRegistry.getColorMap();
}
public async createGrammar(languageId: LanguageId): Promise<ICreateGrammarResult> {
const scopeName = this._languageToScope2[languageId];
if (typeof scopeName !== 'string') {
// No TM grammar defined
return Promise.reject(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language.")));
}
const grammarDefinition = this._scopeRegistry.getGrammarDefinition(scopeName);
if (!grammarDefinition) {
// No TM grammar defined
return Promise.reject(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language.")));
}
let embeddedLanguages = grammarDefinition.embeddedLanguages;
if (this._injectedEmbeddedLanguages[scopeName]) {
const injectedEmbeddedLanguages = this._injectedEmbeddedLanguages[scopeName];
for (const injected of injectedEmbeddedLanguages) {
for (const scope of Object.keys(injected)) {
embeddedLanguages[scope] = injected[scope];
}
}
}
const containsEmbeddedLanguages = (Object.keys(embeddedLanguages).length > 0);
const grammar = await this._grammarRegistry.loadGrammarWithConfiguration(scopeName, languageId, { embeddedLanguages, tokenTypes: <any>grammarDefinition.tokenTypes });
return {
languageId: languageId,
grammar: grammar,
initialState: this._initialState,
containsEmbeddedLanguages: containsEmbeddedLanguages
};
}
}
class TMTokenizationSupport implements ITokenizationSupport {
private readonly _languageId: LanguageId;
private readonly _actual: TMTokenization;

View file

@ -0,0 +1,147 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { URI } from 'vs/base/common/uri';
import { LanguageId } from 'vs/editor/common/modes';
import { IGrammar, Registry, StackElement, IRawTheme, IOnigLib } from 'vscode-textmate';
import { Disposable } from 'vs/base/common/lifecycle';
import { TMScopeRegistry, IValidGrammarDefinition, IValidEmbeddedLanguagesMap } from 'vs/workbench/services/textMate/common/TMScopeRegistry';
interface ITMGrammarFactoryHost {
logTrace(msg: string): void;
logError(msg: string, err: any): void;
readFile(resource: URI): Promise<string>;
}
interface ICreateGrammarResult {
languageId: LanguageId;
grammar: IGrammar;
initialState: StackElement;
containsEmbeddedLanguages: boolean;
}
export class TMGrammarFactory extends Disposable {
private readonly _host: ITMGrammarFactoryHost;
private readonly _initialState: StackElement;
private readonly _scopeRegistry: TMScopeRegistry;
private readonly _injections: { [scopeName: string]: string[]; };
private readonly _injectedEmbeddedLanguages: { [scopeName: string]: IValidEmbeddedLanguagesMap[]; };
private readonly _languageToScope2: string[];
private readonly _grammarRegistry: Registry;
constructor(host: ITMGrammarFactoryHost, grammarDefinitions: IValidGrammarDefinition[], vscodeTextmate: typeof import('vscode-textmate'), onigLib: Promise<IOnigLib> | undefined) {
super();
this._host = host;
this._initialState = vscodeTextmate.INITIAL;
this._scopeRegistry = this._register(new TMScopeRegistry());
this._injections = {};
this._injectedEmbeddedLanguages = {};
this._languageToScope2 = [];
this._grammarRegistry = new vscodeTextmate.Registry({
getOnigLib: (typeof onigLib === 'undefined' ? undefined : () => onigLib),
loadGrammar: async (scopeName: string) => {
const grammarDefinition = this._scopeRegistry.getGrammarDefinition(scopeName);
if (!grammarDefinition) {
this._host.logTrace(`No grammar found for scope ${scopeName}`);
return null;
}
const location = grammarDefinition.location;
try {
const content = await this._host.readFile(location);
return vscodeTextmate.parseRawGrammar(content, location.path);
} catch (e) {
this._host.logError(`Unable to load and parse grammar for scope ${scopeName} from ${location}`, e);
return null;
}
},
getInjections: (scopeName: string) => {
const scopeParts = scopeName.split('.');
let injections: string[] = [];
for (let i = 1; i <= scopeParts.length; i++) {
const subScopeName = scopeParts.slice(0, i).join('.');
injections = [...injections, ...(this._injections[subScopeName] || [])];
}
return injections;
}
});
for (const validGrammar of grammarDefinitions) {
this._scopeRegistry.register(validGrammar);
if (validGrammar.injectTo) {
for (let injectScope of validGrammar.injectTo) {
let injections = this._injections[injectScope];
if (!injections) {
this._injections[injectScope] = injections = [];
}
injections.push(validGrammar.scopeName);
}
if (validGrammar.embeddedLanguages) {
for (let injectScope of validGrammar.injectTo) {
let injectedEmbeddedLanguages = this._injectedEmbeddedLanguages[injectScope];
if (!injectedEmbeddedLanguages) {
this._injectedEmbeddedLanguages[injectScope] = injectedEmbeddedLanguages = [];
}
injectedEmbeddedLanguages.push(validGrammar.embeddedLanguages);
}
}
}
if (validGrammar.language) {
this._languageToScope2[validGrammar.language] = validGrammar.scopeName;
}
}
}
public has(languageId: LanguageId): boolean {
return this._languageToScope2[languageId] ? true : false;
}
public setTheme(theme: IRawTheme): void {
this._grammarRegistry.setTheme(theme);
}
public getColorMap(): string[] {
return this._grammarRegistry.getColorMap();
}
public async createGrammar(languageId: LanguageId): Promise<ICreateGrammarResult> {
const scopeName = this._languageToScope2[languageId];
if (typeof scopeName !== 'string') {
// No TM grammar defined
return Promise.reject(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language.")));
}
const grammarDefinition = this._scopeRegistry.getGrammarDefinition(scopeName);
if (!grammarDefinition) {
// No TM grammar defined
return Promise.reject(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language.")));
}
let embeddedLanguages = grammarDefinition.embeddedLanguages;
if (this._injectedEmbeddedLanguages[scopeName]) {
const injectedEmbeddedLanguages = this._injectedEmbeddedLanguages[scopeName];
for (const injected of injectedEmbeddedLanguages) {
for (const scope of Object.keys(injected)) {
embeddedLanguages[scope] = injected[scope];
}
}
}
const containsEmbeddedLanguages = (Object.keys(embeddedLanguages).length > 0);
const grammar = await this._grammarRegistry.loadGrammarWithConfiguration(scopeName, languageId, { embeddedLanguages, tokenTypes: <any>grammarDefinition.tokenTypes });
return {
languageId: languageId,
grammar: grammar,
initialState: this._initialState,
containsEmbeddedLanguages: containsEmbeddedLanguages
};
}
}

View file

@ -430,7 +430,8 @@
"**/vs/editor/common/**",
"**/vs/workbench/common/**",
"**/vs/workbench/services/**/common/**",
"**/vs/workbench/api/**/common/**"
"**/vs/workbench/api/**/common/**",
"vscode-textmate"
]
},
{