Path: blob/main/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts
3296 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 assert from 'assert';6import { Color } from '../../../../base/common/color.js';7import { Emitter } from '../../../../base/common/event.js';8import { DisposableStore } from '../../../../base/common/lifecycle.js';9import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';10import { LanguageId, MetadataConsts } from '../../../common/encodedTokenAttributes.js';11import { IState, Token } from '../../../common/languages.js';12import { TokenTheme } from '../../../common/languages/supports/tokenization.js';13import { LanguageService } from '../../../common/services/languageService.js';14import { ILineTokens, IToken, TokenizationSupportAdapter, TokensProvider } from '../../browser/standaloneLanguages.js';15import { IStandaloneTheme, IStandaloneThemeData, IStandaloneThemeService } from '../../common/standaloneTheme.js';16import { UnthemedProductIconTheme } from '../../../../platform/theme/browser/iconsStyleSheet.js';17import { ColorIdentifier } from '../../../../platform/theme/common/colorRegistry.js';18import { ColorScheme } from '../../../../platform/theme/common/theme.js';19import { IColorTheme, IFileIconTheme, IProductIconTheme, ITokenStyle } from '../../../../platform/theme/common/themeService.js';2021suite('TokenizationSupport2Adapter', () => {2223ensureNoDisposablesAreLeakedInTestSuite();2425const languageId = 'tttt';26// const tokenMetadata = (LanguageId.PlainText << MetadataConsts.LANGUAGEID_OFFSET);2728class MockTokenTheme extends TokenTheme {29private counter = 0;30constructor() {31super(null!, null!);32}33public override match(languageId: LanguageId, token: string): number {34return (35((this.counter++) << MetadataConsts.FOREGROUND_OFFSET)36| (languageId << MetadataConsts.LANGUAGEID_OFFSET)37) >>> 0;38}39}4041class MockThemeService implements IStandaloneThemeService {42declare readonly _serviceBrand: undefined;43public setTheme(themeName: string): string {44throw new Error('Not implemented');45}46public setAutoDetectHighContrast(autoDetectHighContrast: boolean): void {47throw new Error('Not implemented');48}49public defineTheme(themeName: string, themeData: IStandaloneThemeData): void {50throw new Error('Not implemented');51}52public getColorTheme(): IStandaloneTheme {53return {54label: 'mock',5556tokenTheme: new MockTokenTheme(),5758themeName: ColorScheme.LIGHT,5960type: ColorScheme.LIGHT,6162getColor: (color: ColorIdentifier, useDefault?: boolean): Color => {63throw new Error('Not implemented');64},6566defines: (color: ColorIdentifier): boolean => {67throw new Error('Not implemented');68},6970getTokenStyleMetadata: (type: string, modifiers: string[], modelLanguage: string): ITokenStyle | undefined => {71return undefined;72},7374semanticHighlighting: false,7576tokenColorMap: []77};78}79setColorMapOverride(colorMapOverride: Color[] | null): void {80}81public getFileIconTheme(): IFileIconTheme {82return {83hasFileIcons: false,84hasFolderIcons: false,85hidesExplorerArrows: false86};87}8889private _builtInProductIconTheme = new UnthemedProductIconTheme();9091public getProductIconTheme(): IProductIconTheme {92return this._builtInProductIconTheme;93}94public readonly onDidColorThemeChange = new Emitter<IColorTheme>().event;95public readonly onDidFileIconThemeChange = new Emitter<IFileIconTheme>().event;96public readonly onDidProductIconThemeChange = new Emitter<IProductIconTheme>().event;97}9899class MockState implements IState {100public static readonly INSTANCE = new MockState();101private constructor() { }102public clone(): IState {103return this;104}105public equals(other: IState): boolean {106return this === other;107}108}109110function testBadTokensProvider(providerTokens: IToken[], expectedClassicTokens: Token[], expectedModernTokens: number[]): void {111112class BadTokensProvider implements TokensProvider {113public getInitialState(): IState {114return MockState.INSTANCE;115}116public tokenize(line: string, state: IState): ILineTokens {117return {118tokens: providerTokens,119endState: MockState.INSTANCE120};121}122}123124const disposables = new DisposableStore();125const languageService = disposables.add(new LanguageService());126disposables.add(languageService.registerLanguage({ id: languageId }));127const adapter = new TokenizationSupportAdapter(128languageId,129new BadTokensProvider(),130languageService,131new MockThemeService()132);133134const actualClassicTokens = adapter.tokenize('whatever', true, MockState.INSTANCE);135assert.deepStrictEqual(actualClassicTokens.tokens, expectedClassicTokens);136137const actualModernTokens = adapter.tokenizeEncoded('whatever', true, MockState.INSTANCE);138const modernTokens: number[] = [];139for (let i = 0; i < actualModernTokens.tokens.length; i++) {140modernTokens[i] = actualModernTokens.tokens[i];141}142143// Add the encoded language id to the expected tokens144const encodedLanguageId = languageService.languageIdCodec.encodeLanguageId(languageId);145const tokenLanguageMetadata = (encodedLanguageId << MetadataConsts.LANGUAGEID_OFFSET);146for (let i = 1; i < expectedModernTokens.length; i += 2) {147expectedModernTokens[i] |= tokenLanguageMetadata;148}149assert.deepStrictEqual(modernTokens, expectedModernTokens);150151disposables.dispose();152}153154test('tokens always start at index 0', () => {155testBadTokensProvider(156[157{ startIndex: 7, scopes: 'foo' },158{ startIndex: 0, scopes: 'bar' }159],160[161new Token(0, 'foo', languageId),162new Token(0, 'bar', languageId),163],164[1650, (0 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK,1660, (1 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK167]168);169});170171test('tokens always start after each other', () => {172testBadTokensProvider(173[174{ startIndex: 0, scopes: 'foo' },175{ startIndex: 5, scopes: 'bar' },176{ startIndex: 3, scopes: 'foo' },177],178[179new Token(0, 'foo', languageId),180new Token(5, 'bar', languageId),181new Token(5, 'foo', languageId),182],183[1840, (0 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK,1855, (1 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK,1865, (2 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK187]188);189});190});191192193