diff --git a/src/_.contribution.ts b/src/_.contribution.ts index 5aafec65..f0e7b2db 100644 --- a/src/_.contribution.ts +++ b/src/_.contribution.ts @@ -16,31 +16,61 @@ interface ILangImpl { language: monaco.languages.IMonarchLanguage; } -let languageDefinitions: { [languageId: string]: ILang } = {}; +const languageDefinitions: { [languageId: string]: ILang; } = {}; +const lazyLanguageLoaders: { [languageId: string]: LazyLanguageLoader; } = {}; -function _loadLanguage(languageId: string): Promise { - const loader = languageDefinitions[languageId].loader; - return loader().then((mod) => { - _monaco.languages.setMonarchTokensProvider(languageId, mod.language); - _monaco.languages.setLanguageConfiguration(languageId, mod.conf); - }); -} +class LazyLanguageLoader { + + public static getOrCreate(languageId: string): LazyLanguageLoader { + if (!lazyLanguageLoaders[languageId]) { + lazyLanguageLoaders[languageId] = new LazyLanguageLoader(languageId); + } + return lazyLanguageLoaders[languageId]; + } + + private readonly _languageId: string; + private _loadingTriggered: boolean; + private _lazyLoadPromise: Promise; + private _lazyLoadPromiseResolve!: (value: ILangImpl) => void; + private _lazyLoadPromiseReject!: (err: any) => void; -let languagePromises: { [languageId: string]: Promise } = {}; + constructor(languageId: string) { + this._languageId = languageId; + this._loadingTriggered = false; + this._lazyLoadPromise = new Promise((resolve, reject) => { + this._lazyLoadPromiseResolve = resolve; + this._lazyLoadPromiseReject = reject; + }); + } -export function loadLanguage(languageId: string): Promise { - if (!languagePromises[languageId]) { - languagePromises[languageId] = _loadLanguage(languageId); + public whenLoaded(): Promise { + return this._lazyLoadPromise; + } + + public load(): Promise { + if (!this._loadingTriggered) { + this._loadingTriggered = true; + languageDefinitions[this._languageId].loader().then(mod => this._lazyLoadPromiseResolve(mod), err => this._lazyLoadPromiseReject(err)); + } + return this._lazyLoadPromise; } - return languagePromises[languageId]; +} + +export function loadLanguage(languageId: string): Promise { + return LazyLanguageLoader.getOrCreate(languageId).load(); } export function registerLanguage(def: ILang): void { - let languageId = def.id; + const languageId = def.id; languageDefinitions[languageId] = def; _monaco.languages.register(def); + + const lazyLanguageLoader = LazyLanguageLoader.getOrCreate(languageId); + _monaco.languages.setMonarchTokensProvider(languageId, lazyLanguageLoader.whenLoaded().then(mod => mod.language)); _monaco.languages.onLanguage(languageId, () => { - loadLanguage(languageId); + lazyLanguageLoader.load().then(mod => { + _monaco.languages.setLanguageConfiguration(languageId, mod.conf); + }); }); }