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
3296 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
}
80
setColorMapOverride(colorMapOverride: Color[] | null): void {
81
}
82
public getFileIconTheme(): IFileIconTheme {
83
return {
84
hasFileIcons: false,
85
hasFolderIcons: false,
86
hidesExplorerArrows: false
87
};
88
}
89
90
private _builtInProductIconTheme = new UnthemedProductIconTheme();
91
92
public getProductIconTheme(): IProductIconTheme {
93
return this._builtInProductIconTheme;
94
}
95
public readonly onDidColorThemeChange = new Emitter<IColorTheme>().event;
96
public readonly onDidFileIconThemeChange = new Emitter<IFileIconTheme>().event;
97
public readonly onDidProductIconThemeChange = new Emitter<IProductIconTheme>().event;
98
}
99
100
class MockState implements IState {
101
public static readonly INSTANCE = new MockState();
102
private constructor() { }
103
public clone(): IState {
104
return this;
105
}
106
public equals(other: IState): boolean {
107
return this === other;
108
}
109
}
110
111
function testBadTokensProvider(providerTokens: IToken[], expectedClassicTokens: Token[], expectedModernTokens: number[]): void {
112
113
class BadTokensProvider implements TokensProvider {
114
public getInitialState(): IState {
115
return MockState.INSTANCE;
116
}
117
public tokenize(line: string, state: IState): ILineTokens {
118
return {
119
tokens: providerTokens,
120
endState: MockState.INSTANCE
121
};
122
}
123
}
124
125
const disposables = new DisposableStore();
126
const languageService = disposables.add(new LanguageService());
127
disposables.add(languageService.registerLanguage({ id: languageId }));
128
const adapter = new TokenizationSupportAdapter(
129
languageId,
130
new BadTokensProvider(),
131
languageService,
132
new MockThemeService()
133
);
134
135
const actualClassicTokens = adapter.tokenize('whatever', true, MockState.INSTANCE);
136
assert.deepStrictEqual(actualClassicTokens.tokens, expectedClassicTokens);
137
138
const actualModernTokens = adapter.tokenizeEncoded('whatever', true, MockState.INSTANCE);
139
const modernTokens: number[] = [];
140
for (let i = 0; i < actualModernTokens.tokens.length; i++) {
141
modernTokens[i] = actualModernTokens.tokens[i];
142
}
143
144
// Add the encoded language id to the expected tokens
145
const encodedLanguageId = languageService.languageIdCodec.encodeLanguageId(languageId);
146
const tokenLanguageMetadata = (encodedLanguageId << MetadataConsts.LANGUAGEID_OFFSET);
147
for (let i = 1; i < expectedModernTokens.length; i += 2) {
148
expectedModernTokens[i] |= tokenLanguageMetadata;
149
}
150
assert.deepStrictEqual(modernTokens, expectedModernTokens);
151
152
disposables.dispose();
153
}
154
155
test('tokens always start at index 0', () => {
156
testBadTokensProvider(
157
[
158
{ startIndex: 7, scopes: 'foo' },
159
{ startIndex: 0, scopes: 'bar' }
160
],
161
[
162
new Token(0, 'foo', languageId),
163
new Token(0, 'bar', languageId),
164
],
165
[
166
0, (0 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK,
167
0, (1 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK
168
]
169
);
170
});
171
172
test('tokens always start after each other', () => {
173
testBadTokensProvider(
174
[
175
{ startIndex: 0, scopes: 'foo' },
176
{ startIndex: 5, scopes: 'bar' },
177
{ startIndex: 3, scopes: 'foo' },
178
],
179
[
180
new Token(0, 'foo', languageId),
181
new Token(5, 'bar', languageId),
182
new Token(5, 'foo', languageId),
183
],
184
[
185
0, (0 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK,
186
5, (1 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK,
187
5, (2 << MetadataConsts.FOREGROUND_OFFSET) | MetadataConsts.BALANCED_BRACKETS_MASK
188
]
189
);
190
});
191
});
192
193