Path: blob/main/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts
5251 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: [],7778tokenFontMap: []79};80}81setColorMapOverride(colorMapOverride: Color[] | null): void {82}83public getFileIconTheme(): IFileIconTheme {84return {85hasFileIcons: false,86hasFolderIcons: false,87hidesExplorerArrows: false88};89}9091private _builtInProductIconTheme = new UnthemedProductIconTheme();9293public getProductIconTheme(): IProductIconTheme {94return this._builtInProductIconTheme;95}96public readonly onDidColorThemeChange = new Emitter<IColorTheme>().event;97public readonly onDidFileIconThemeChange = new Emitter<IFileIconTheme>().event;98public readonly onDidProductIconThemeChange = new Emitter<IProductIconTheme>().event;99}100101class MockState implements IState {102public static readonly INSTANCE = new MockState();103private constructor() { }104public clone(): IState {105return this;106}107public equals(other: IState): boolean {108return this === other;109}110}111112function testBadTokensProvider(providerTokens: IToken[], expectedClassicTokens: Token[], expectedModernTokens: number[]): void {113114class BadTokensProvider implements TokensProvider {115public getInitialState(): IState {116return MockState.INSTANCE;117}118public tokenize(line: string, state: IState): ILineTokens {119return {120tokens: providerTokens,121endState: MockState.INSTANCE122};123}124}125126const disposables = new DisposableStore();127const languageService = disposables.add(new LanguageService());128disposables.add(languageService.registerLanguage({ id: languageId }));129const adapter = new TokenizationSupportAdapter(130languageId,131new BadTokensProvider(),132languageService,133new MockThemeService()134);135136const actualClassicTokens = adapter.tokenize('whatever', true, MockState.INSTANCE);137assert.deepStrictEqual(actualClassicTokens.tokens, expectedClassicTokens);138139const actualModernTokens = adapter.tokenizeEncoded('whatever', true, MockState.INSTANCE);140const modernTokens: number[] = [];141for (let i = 0; i < actualModernTokens.tokens.length; i++) {142modernTokens[i] = actualModernTokens.tokens[i];143}144145// Add the encoded language id to the expected tokens146const encodedLanguageId = languageService.languageIdCodec.encodeLanguageId(languageId);147const tokenLanguageMetadata = (encodedLanguageId << MetadataConsts.LANGUAGEID_OFFSET);148for (let i = 1; i < expectedModernTokens.length; i += 2) {149expectedModernTokens[i] |= tokenLanguageMetadata;150}151assert.deepStrictEqual(modernTokens, expectedModernTokens);152153disposables.dispose();154}155156test('tokens always start at index 0', () => {157testBadTokensProvider(158[159{ startIndex: 7, scopes: 'foo' },160{ startIndex: 0, scopes: 'bar' }161],162[163new Token(0, 'foo', languageId),164new Token(0, 'bar', languageId),165],166[1670, (0 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK,1680, (1 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK169]170);171});172173test('tokens always start after each other', () => {174testBadTokensProvider(175[176{ startIndex: 0, scopes: 'foo' },177{ startIndex: 5, scopes: 'bar' },178{ startIndex: 3, scopes: 'foo' },179],180[181new Token(0, 'foo', languageId),182new Token(5, 'bar', languageId),183new Token(5, 'foo', languageId),184],185[1860, (0 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK,1875, (1 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK,1885, (2 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK189]190);191});192});193194195