@theia/monaco
Version:
Theia - Monaco Extension
130 lines (112 loc) • 4.95 kB
text/typescript
// *****************************************************************************
// Copyright (C) 2018 Ericsson and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { injectable } from '@theia/core/shared/inversify';
import { IGrammarConfiguration } from 'vscode-textmate';
import { TokenizerOption } from './textmate-tokenizer';
import { Disposable } from '@theia/core/lib/common/disposable';
export interface TextmateGrammarConfiguration extends IGrammarConfiguration {
/**
* Optional options to further refine the tokenization of the grammar.
*/
readonly tokenizerOption?: TokenizerOption;
}
export interface GrammarDefinitionProvider {
getGrammarDefinition(): Promise<GrammarDefinition>;
getInjections?(scopeName: string): string[];
}
export interface GrammarDefinition {
format: 'json' | 'plist';
content: object | string;
location?: string;
}
export class TextmateRegistry {
protected readonly scopeToProvider = new Map<string, GrammarDefinitionProvider[]>();
protected readonly languageToConfig = new Map<string, TextmateGrammarConfiguration[]>();
protected readonly languageIdToScope = new Map<string, string[]>();
get languages(): IterableIterator<string> {
return this.languageIdToScope.keys();
}
registerTextmateGrammarScope(scope: string, provider: GrammarDefinitionProvider): Disposable {
const providers = this.scopeToProvider.get(scope) || [];
const existingProvider = providers[0];
if (existingProvider) {
Promise.all([existingProvider.getGrammarDefinition(), provider.getGrammarDefinition()]).then(([a, b]) => {
if (a.location !== b.location || !a.location && !b.location) {
console.warn(`a registered grammar provider for '${scope}' scope is overridden`);
}
});
}
providers.unshift(provider);
this.scopeToProvider.set(scope, providers);
return Disposable.create(() => {
const index = providers.indexOf(provider);
if (index !== -1) {
providers.splice(index, 1);
}
});
}
getProvider(scope: string): GrammarDefinitionProvider | undefined {
const providers = this.scopeToProvider.get(scope);
return providers && providers[0];
}
mapLanguageIdToTextmateGrammar(languageId: string, scope: string): Disposable {
const scopes = this.languageIdToScope.get(languageId) || [];
const existingScope = scopes[0];
if (typeof existingScope === 'string') {
console.warn(`'${languageId}' language is remapped from '${existingScope}' to '${scope}' scope`);
}
scopes.unshift(scope);
this.languageIdToScope.set(languageId, scopes);
return Disposable.create(() => {
const index = scopes.indexOf(scope);
if (index !== -1) {
scopes.splice(index, 1);
}
});
}
getScope(languageId: string): string | undefined {
const scopes = this.languageIdToScope.get(languageId);
return scopes && scopes[0];
}
getLanguageId(scope: string): string | undefined {
for (const languageId of this.languageIdToScope.keys()) {
if (this.getScope(languageId) === scope) {
return languageId;
}
}
return undefined;
}
registerGrammarConfiguration(languageId: string, config: TextmateGrammarConfiguration): Disposable {
const configs = this.languageToConfig.get(languageId) || [];
const existingConfig = configs[0];
if (existingConfig) {
console.warn(`a registered grammar configuration for '${languageId}' language is overridden`);
}
configs.unshift(config);
this.languageToConfig.set(languageId, configs);
return Disposable.create(() => {
const index = configs.indexOf(config);
if (index !== -1) {
configs.splice(index, 1);
}
});
}
getGrammarConfiguration(languageId: string): TextmateGrammarConfiguration {
const configs = this.languageToConfig.get(languageId);
return configs && configs[0] || {};
}
}