Path: blob/main/src/vs/editor/common/tokenizationRegistry.ts
3292 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { Color } from '../../base/common/color.js';6import { Emitter, Event } from '../../base/common/event.js';7import { Disposable, IDisposable, toDisposable } from '../../base/common/lifecycle.js';8import { ITokenizationRegistry, ITokenizationSupportChangedEvent, ILazyTokenizationSupport } from './languages.js';9import { ColorId } from './encodedTokenAttributes.js';1011export class TokenizationRegistry<TSupport> implements ITokenizationRegistry<TSupport> {1213private readonly _tokenizationSupports = new Map<string, TSupport>();14private readonly _factories = new Map<string, TokenizationSupportFactoryData<TSupport>>();1516private readonly _onDidChange = new Emitter<ITokenizationSupportChangedEvent>();17public readonly onDidChange: Event<ITokenizationSupportChangedEvent> = this._onDidChange.event;1819private _colorMap: Color[] | null;2021constructor() {22this._colorMap = null;23}2425public handleChange(languageIds: string[]): void {26this._onDidChange.fire({27changedLanguages: languageIds,28changedColorMap: false29});30}3132public register(languageId: string, support: TSupport): IDisposable {33this._tokenizationSupports.set(languageId, support);34this.handleChange([languageId]);35return toDisposable(() => {36if (this._tokenizationSupports.get(languageId) !== support) {37return;38}39this._tokenizationSupports.delete(languageId);40this.handleChange([languageId]);41});42}4344public get(languageId: string): TSupport | null {45return this._tokenizationSupports.get(languageId) || null;46}4748public registerFactory(languageId: string, factory: ILazyTokenizationSupport<TSupport>): IDisposable {49this._factories.get(languageId)?.dispose();50const myData = new TokenizationSupportFactoryData(this, languageId, factory);51this._factories.set(languageId, myData);52return toDisposable(() => {53const v = this._factories.get(languageId);54if (!v || v !== myData) {55return;56}57this._factories.delete(languageId);58v.dispose();59});60}6162public async getOrCreate(languageId: string): Promise<TSupport | null> {63// check first if the support is already set64const tokenizationSupport = this.get(languageId);65if (tokenizationSupport) {66return tokenizationSupport;67}6869const factory = this._factories.get(languageId);70if (!factory || factory.isResolved) {71// no factory or factory.resolve already finished72return null;73}7475await factory.resolve();7677return this.get(languageId);78}7980public isResolved(languageId: string): boolean {81const tokenizationSupport = this.get(languageId);82if (tokenizationSupport) {83return true;84}8586const factory = this._factories.get(languageId);87if (!factory || factory.isResolved) {88return true;89}9091return false;92}9394public setColorMap(colorMap: Color[]): void {95this._colorMap = colorMap;96this._onDidChange.fire({97changedLanguages: Array.from(this._tokenizationSupports.keys()),98changedColorMap: true99});100}101102public getColorMap(): Color[] | null {103return this._colorMap;104}105106public getDefaultBackground(): Color | null {107if (this._colorMap && this._colorMap.length > ColorId.DefaultBackground) {108return this._colorMap[ColorId.DefaultBackground];109}110return null;111}112}113114class TokenizationSupportFactoryData<TSupport> extends Disposable {115116private _isDisposed: boolean = false;117private _resolvePromise: Promise<void> | null = null;118private _isResolved: boolean = false;119120public get isResolved(): boolean {121return this._isResolved;122}123124constructor(125private readonly _registry: TokenizationRegistry<TSupport>,126private readonly _languageId: string,127private readonly _factory: ILazyTokenizationSupport<TSupport>,128) {129super();130}131132public override dispose(): void {133this._isDisposed = true;134super.dispose();135}136137public async resolve(): Promise<void> {138if (!this._resolvePromise) {139this._resolvePromise = this._create();140}141return this._resolvePromise;142}143144private async _create(): Promise<void> {145const value = await this._factory.tokenizationSupport;146this._isResolved = true;147if (value && !this._isDisposed) {148this._register(this._registry.register(this._languageId, value));149}150}151}152153154