From d6a0467a5e3e645b7f044da7933693951521c058 Mon Sep 17 00:00:00 2001 From: Anton Kosyakov Date: Tue, 2 Jul 2019 11:57:37 +0000 Subject: [PATCH] [vscode] support `onLanguage` activation event Signed-off-by: Anton Kosyakov --- .../textmate/monaco-textmate-service.ts | 54 +++++++++++-------- .../src/hosted/browser/hosted-plugin.ts | 13 +++++ .../plugin-ext/src/plugin/plugin-manager.ts | 2 +- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/packages/monaco/src/browser/textmate/monaco-textmate-service.ts b/packages/monaco/src/browser/textmate/monaco-textmate-service.ts index 846949cb99a93..7e2a2415e4c22 100644 --- a/packages/monaco/src/browser/textmate/monaco-textmate-service.ts +++ b/packages/monaco/src/browser/textmate/monaco-textmate-service.ts @@ -16,7 +16,7 @@ import { injectable, inject, named } from 'inversify'; import { Registry, IOnigLib, IRawGrammar, parseRawGrammar } from 'vscode-textmate'; -import { ILogger, ContributionProvider } from '@theia/core'; +import { ILogger, ContributionProvider, Emitter } from '@theia/core'; import { FrontendApplicationContribution, isBasicWasmSupported } from '@theia/core/lib/browser'; import { ThemeService } from '@theia/core/lib/browser/theming'; import { LanguageGrammarDefinitionContribution, getEncodedLanguageId } from './textmate-contribution'; @@ -30,6 +30,14 @@ export type OnigasmPromise = Promise; @injectable() export class MonacoTextmateService implements FrontendApplicationContribution { + protected readonly _activatedLanguages = new Set(); + get activatedLanguages(): ReadonlySet { + return this._activatedLanguages; + } + + protected readonly onDidActivateLanguageEmitter = new Emitter(); + readonly onDidActivateLanguage = this.onDidActivateLanguageEmitter.event; + protected grammarRegistry: Registry; @inject(ContributionProvider) @named(LanguageGrammarDefinitionContribution) @@ -97,35 +105,39 @@ export class MonacoTextmateService implements FrontendApplicationContribution { } }); - const registered = new Set(); for (const { id } of monaco.languages.getLanguages()) { - if (!registered.has(id)) { - monaco.languages.onLanguage(id, () => this.activateLanguage(id)); - registered.add(id); - } + monaco.languages.onLanguage(id, () => this.activateLanguage(id)); } } async activateLanguage(languageId: string) { - const scopeName = this.textmateRegistry.getScope(languageId); - if (!scopeName) { - return; - } - const provider = this.textmateRegistry.getProvider(scopeName); - if (!provider) { + if (this._activatedLanguages.has(languageId)) { return; } + this._activatedLanguages.add(languageId); + try { + const scopeName = this.textmateRegistry.getScope(languageId); + if (!scopeName) { + return; + } + const provider = this.textmateRegistry.getProvider(scopeName); + if (!provider) { + return; + } - const configuration = this.textmateRegistry.getGrammarConfiguration(languageId); - const initialLanguage = getEncodedLanguageId(languageId); + const configuration = this.textmateRegistry.getGrammarConfiguration(languageId); + const initialLanguage = getEncodedLanguageId(languageId); - await this.onigasmPromise; - try { - const grammar = await this.grammarRegistry.loadGrammarWithConfiguration(scopeName, initialLanguage, configuration); - const options = configuration.tokenizerOption ? configuration.tokenizerOption : TokenizerOption.DEFAULT; - monaco.languages.setTokensProvider(languageId, createTextmateTokenizer(grammar, options)); - } catch (error) { - this.logger.warn('No grammar for this language id', languageId, error); + await this.onigasmPromise; + try { + const grammar = await this.grammarRegistry.loadGrammarWithConfiguration(scopeName, initialLanguage, configuration); + const options = configuration.tokenizerOption ? configuration.tokenizerOption : TokenizerOption.DEFAULT; + monaco.languages.setTokensProvider(languageId, createTextmateTokenizer(grammar, options)); + } catch (error) { + this.logger.warn('No grammar for this language id', languageId, error); + } + } finally { + this.onDidActivateLanguageEmitter.fire(languageId); } } } diff --git a/packages/plugin-ext/src/hosted/browser/hosted-plugin.ts b/packages/plugin-ext/src/hosted/browser/hosted-plugin.ts index da80219fd6a61..c2030746aa846 100644 --- a/packages/plugin-ext/src/hosted/browser/hosted-plugin.ts +++ b/packages/plugin-ext/src/hosted/browser/hosted-plugin.ts @@ -35,6 +35,7 @@ import { PluginServer } from '../../common/plugin-protocol'; import { KeysToKeysToAnyValue } from '../../common/types'; import { FileStat } from '@theia/filesystem/lib/common/filesystem'; import { PluginManagerExt, MAIN_RPC_CONTEXT } from '../../common'; +import { MonacoTextmateService } from '@theia/monaco/lib/browser/textmate'; export type PluginHost = 'frontend' | string; @@ -76,6 +77,9 @@ export class HostedPluginSupport { @inject(WorkspaceService) protected readonly workspaceService: WorkspaceService; + @inject(MonacoTextmateService) + protected readonly monacoTextmateService: MonacoTextmateService; + private theiaReadyPromise: Promise; protected readonly managers: PluginManagerExt[] = []; @@ -89,6 +93,11 @@ export class HostedPluginSupport { protected init(): void { this.theiaReadyPromise = Promise.all([this.preferenceServiceImpl.ready, this.workspaceService.roots]); this.storagePathService.onStoragePathChanged(path => this.updateStoragePath(path)); + + for (const id of this.monacoTextmateService.activatedLanguages) { + this.activateByLanguage(id); + } + this.monacoTextmateService.onDidActivateLanguage(id => this.activateByLanguage(id)); } checkAndLoadPlugin(container: interfaces.Container): void { @@ -197,6 +206,10 @@ export class HostedPluginSupport { } } + activateByLanguage(languageId: string): void { + this.activateByEvent(`onLanguage:${languageId}`); + } + } interface PluginsInitializationData { diff --git a/packages/plugin-ext/src/plugin/plugin-manager.ts b/packages/plugin-ext/src/plugin/plugin-manager.ts index a8d1cfeff7eb5..53d5201da0f9c 100644 --- a/packages/plugin-ext/src/plugin/plugin-manager.ts +++ b/packages/plugin-ext/src/plugin/plugin-manager.ts @@ -61,7 +61,7 @@ class ActivatedPlugin { export class PluginManagerExtImpl implements PluginManagerExt, PluginManager { - static SUPPORTED_ACTIVATION_EVENTS = new Set(['*']); + static SUPPORTED_ACTIVATION_EVENTS = new Set(['*', 'onLanguage']); private readonly registry = new Map(); private readonly activations = new Map Promise)[] | undefined>();