Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts
5251 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import assert from 'assert';
7
import { Color } from '../../../../base/common/color.js';
8
import { Emitter } from '../../../../base/common/event.js';
9
import { DisposableStore } from '../../../../base/common/lifecycle.js';
10
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
11
import { LanguageId, MetadataConsts } from '../../../common/encodedTokenAttributes.js';
12
import { IState, Token } from '../../../common/languages.js';
13
import { TokenTheme } from '../../../common/languages/supports/tokenization.js';
14
import { LanguageService } from '../../../common/services/languageService.js';
15
import { ILineTokens, IToken, TokenizationSupportAdapter, TokensProvider } from '../../browser/standaloneLanguages.js';
16
import { IStandaloneTheme, IStandaloneThemeData, IStandaloneThemeService } from '../../common/standaloneTheme.js';
17
import { UnthemedProductIconTheme } from '../../../../platform/theme/browser/iconsStyleSheet.js';
18
import { ColorIdentifier } from '../../../../platform/theme/common/colorRegistry.js';
19
import { ColorScheme } from '../../../../platform/theme/common/theme.js';
20
import { IColorTheme, IFileIconTheme, IProductIconTheme, ITokenStyle } from '../../../../platform/theme/common/themeService.js';
21
22
suite('TokenizationSupport2Adapter', () => {
23
24
ensureNoDisposablesAreLeakedInTestSuite();
25
26
const languageId = 'tttt';
27
// const tokenMetadata = (LanguageId.PlainText << MetadataConsts.LANGUAGEID_OFFSET);
28
29
class MockTokenTheme extends TokenTheme {
30
private counter = 0;
31
constructor() {
32
super(null!, null!);
33
}
34
public override match(languageId: LanguageId, token: string): number {
35
return (
36
((this.counter++) << MetadataConsts.FOREGROUND_OFFSET)
37
| (languageId << MetadataConsts.LANGUAGEID_OFFSET)
38
) >>> 0;
39
}
40
}
41
42
class MockThemeService implements IStandaloneThemeService {
43
declare readonly _serviceBrand: undefined;
44
public setTheme(themeName: string): string {
45
throw new Error('Not implemented');
46
}
47
public setAutoDetectHighContrast(autoDetectHighContrast: boolean): void {
48
throw new Error('Not implemented');
49
}
50
public defineTheme(themeName: string, themeData: IStandaloneThemeData): void {
51
throw new Error('Not implemented');
52
}
53
public getColorTheme(): IStandaloneTheme {
54
return {
55
label: 'mock',
56
57
tokenTheme: new MockTokenTheme(),
58
59
themeName: ColorScheme.LIGHT,
60
61
type: ColorScheme.LIGHT,
62
63
getColor: (color: ColorIdentifier, useDefault?: boolean): Color => {
64
throw new Error('Not implemented');
65
},
66
67
defines: (color: ColorIdentifier): boolean => {
68
throw new Error('Not implemented');
69
},
70
71
getTokenStyleMetadata: (type: string, modifiers: string[], modelLanguage: string): ITokenStyle | undefined => {
72
return undefined;
73
},
74
75
semanticHighlighting: false,
76
77
tokenColorMap: [],
78
79
tokenFontMap: []
80
};
81
}
82
setColorMapOverride(colorMapOverride: Color[] | null): void {
83
}
84
public getFileIconTheme(): IFileIconTheme {
85
return {
86
hasFileIcons: false,
87
hasFolderIcons: false,
88
hidesExplorerArrows: false
89
};
90
}
91
92
private _builtInProductIconTheme = new UnthemedProductIconTheme();
93
94
public getProductIconTheme(): IProductIconTheme {
95
return this._builtInProductIconTheme;
96
}
97
public readonly onDidColorThemeChange = new Emitter<IColorTheme>().event;
98
public readonly onDidFileIconThemeChange = new Emitter<IFileIconTheme>().event;
99
public readonly onDidProductIconThemeChange = new Emitter<IProductIconTheme>().event;
100
}
101
102
class MockState implements IState {
103
public static readonly INSTANCE = new MockState();
104
private constructor() { }
105
public clone(): IState {
106
return this;
107
}
108
public equals(other: IState): boolean {
109
return this === other;
110
}
111
}
112
113
function testBadTokensProvider(providerTokens: IToken[], expectedClassicTokens: Token[], expectedModernTokens: number[]): void {
114
115
class BadTokensProvider implements TokensProvider {
116
public getInitialState(): IState {
117
return MockState.INSTANCE;
118
}
119
public tokenize(line: string, state: IState): ILineTokens {
120
return {
121
tokens: providerTokens,
122
endState: MockState.INSTANCE
123
};
124
}
125
}
126
127
const disposables = new DisposableStore();
128
const languageService = disposables.add(new LanguageService());
129
disposables.add(languageService.registerLanguage({ id: languageId }));
130
const adapter = new TokenizationSupportAdapter(
131
languageId,
132
new BadTokensProvider(),
133
languageService,
134
new MockThemeService()
135
);
136
137
const actualClassicTokens = adapter.tokenize('whatever', true, MockState.INSTANCE);
138
assert.deepStrictEqual(actualClassicTokens.tokens, expectedClassicTokens);
139
140
const actualModernTokens = adapter.tokenizeEncoded('whatever', true, MockState.INSTANCE);
141
const modernTokens: number[] = [];
142
for (let i = 0; i < actualModernTokens.tokens.length; i++) {
143
modernTokens[i] = actualModernTokens.tokens[i];
144
}
145
146
// Add the encoded language id to the expected tokens
147
const encodedLanguageId = languageService.languageIdCodec.encodeLanguageId(languageId);
148
const tokenLanguageMetadata = (encodedLanguageId << MetadataConsts.LANGUAGEID_OFFSET);
149
for (let i = 1; i < expectedModernTokens.length; i += 2) {
150
expectedModernTokens[i] |= tokenLanguageMetadata;
151
}
152
assert.deepStrictEqual(modernTokens, expectedModernTokens);
153
154
disposables.dispose();
155
}
156
157
test('tokens always start at index 0', () => {
158
testBadTokensProvider(
159
[
160
{ startIndex: 7, scopes: 'foo' },
161
{ startIndex: 0, scopes: 'bar' }
162
],
163
[
164
new Token(0, 'foo', languageId),
165
new Token(0, 'bar', languageId),
166
],
167
[
168
0, (0 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK,
169
0, (1 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK
170
]
171
);
172
});
173
174
test('tokens always start after each other', () => {
175
testBadTokensProvider(
176
[
177
{ startIndex: 0, scopes: 'foo' },
178
{ startIndex: 5, scopes: 'bar' },
179
{ startIndex: 3, scopes: 'foo' },
180
],
181
[
182
new Token(0, 'foo', languageId),
183
new Token(5, 'bar', languageId),
184
new Token(5, 'foo', languageId),
185
],
186
[
187
0, (0 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK,
188
5, (1 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK,
189
5, (2 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK
190
]
191
);
192
});
193
});
194
195