textToHtmlTokenizer.test.ts 9.0 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
A
Alex Dima 已提交
5

A
Alex Dima 已提交
6
import * as assert from 'assert';
A
Tweaks  
Alex Dima 已提交
7
import { TokenizationResult2 } from 'vs/editor/common/core/token';
A
Alex Dima 已提交
8 9
import { ColorId, FontStyle, IState, LanguageIdentifier, MetadataConsts, TokenizationRegistry } from 'vs/editor/common/modes';
import { tokenizeLineToHTML, tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer';
A
Alex Dima 已提交
10
import { ViewLineToken, ViewLineTokens } from 'vs/editor/test/common/core/viewLineToken';
A
Alex Dima 已提交
11
import { MockMode } from 'vs/editor/test/common/mocks/mockMode';
E
Erich Gamma 已提交
12 13

suite('Editor Modes - textToHtmlTokenizer', () => {
A
Alex Dima 已提交
14 15 16 17
	function toStr(pieces: { className: string; text: string }[]): string {
		let resultArr = pieces.map((t) => `<span class="${t.className}">${t.text}</span>`);
		return resultArr.join('');
	}
E
Erich Gamma 已提交
18

A
Alex Dima 已提交
19 20
	test('TextToHtmlTokenizer 1', () => {
		let mode = new Mode();
21
		let support = TokenizationRegistry.get(mode.getId())!;
E
Erich Gamma 已提交
22

23
		let actual = tokenizeToString('.abc..def...gh', support);
A
Alex Dima 已提交
24 25 26 27 28 29 30 31 32
		let expected = [
			{ className: 'mtk7', text: '.' },
			{ className: 'mtk9', text: 'abc' },
			{ className: 'mtk7', text: '..' },
			{ className: 'mtk9', text: 'def' },
			{ className: 'mtk7', text: '...' },
			{ className: 'mtk9', text: 'gh' },
		];
		let expectedStr = `<div class="monaco-tokenized-source">${toStr(expected)}</div>`;
E
Erich Gamma 已提交
33

A
Alex Dima 已提交
34
		assert.equal(actual, expectedStr);
E
Erich Gamma 已提交
35

A
Alex Dima 已提交
36 37
		mode.dispose();
	});
E
Erich Gamma 已提交
38

A
Alex Dima 已提交
39 40
	test('TextToHtmlTokenizer 2', () => {
		let mode = new Mode();
41
		let support = TokenizationRegistry.get(mode.getId())!;
A
Alex Dima 已提交
42

43
		let actual = tokenizeToString('.abc..def...gh\n.abc..def...gh', support);
A
Alex Dima 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
		let expected1 = [
			{ className: 'mtk7', text: '.' },
			{ className: 'mtk9', text: 'abc' },
			{ className: 'mtk7', text: '..' },
			{ className: 'mtk9', text: 'def' },
			{ className: 'mtk7', text: '...' },
			{ className: 'mtk9', text: 'gh' },
		];
		let expected2 = [
			{ className: 'mtk7', text: '.' },
			{ className: 'mtk9', text: 'abc' },
			{ className: 'mtk7', text: '..' },
			{ className: 'mtk9', text: 'def' },
			{ className: 'mtk7', text: '...' },
			{ className: 'mtk9', text: 'gh' },
		];
		let expectedStr1 = toStr(expected1);
		let expectedStr2 = toStr(expected2);
		let expectedStr = `<div class="monaco-tokenized-source">${expectedStr1}<br/>${expectedStr2}</div>`;

		assert.equal(actual, expectedStr);

		mode.dispose();
E
Erich Gamma 已提交
67 68
	});

69 70
	test('tokenizeLineToHTML', () => {
		const text = 'Ciao hello world!';
A
Alex Dima 已提交
71
		const lineTokens = new ViewLineTokens([
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
			new ViewLineToken(
				4,
				(
					(3 << MetadataConsts.FOREGROUND_OFFSET)
					| ((FontStyle.Bold | FontStyle.Italic) << MetadataConsts.FONT_STYLE_OFFSET)
				) >>> 0
			),
			new ViewLineToken(
				5,
				(
					(1 << MetadataConsts.FOREGROUND_OFFSET)
				) >>> 0
			),
			new ViewLineToken(
				10,
				(
					(4 << MetadataConsts.FOREGROUND_OFFSET)
				) >>> 0
			),
			new ViewLineToken(
				11,
				(
					(1 << MetadataConsts.FOREGROUND_OFFSET)
				) >>> 0
			),
			new ViewLineToken(
				17,
				(
					(5 << MetadataConsts.FOREGROUND_OFFSET)
					| ((FontStyle.Underline) << MetadataConsts.FONT_STYLE_OFFSET)
				) >>> 0
			)
A
Alex Dima 已提交
104
		]);
A
Alex Dima 已提交
105
		const colorMap = [null!, '#000000', '#ffffff', '#ff0000', '#00ff00', '#0000ff'];
106 107

		assert.equal(
108
			tokenizeLineToHTML(text, lineTokens, colorMap, 0, 17, 4, true),
109 110 111
			[
				'<div>',
				'<span style="color: #ff0000;font-style: italic;font-weight: bold;">Ciao</span>',
P
Peng Lyu 已提交
112
				'<span style="color: #000000;">&nbsp;</span>',
113
				'<span style="color: #00ff00;">hello</span>',
P
Peng Lyu 已提交
114
				'<span style="color: #000000;">&nbsp;</span>',
115 116 117 118 119 120
				'<span style="color: #0000ff;text-decoration: underline;">world!</span>',
				'</div>'
			].join('')
		);

		assert.equal(
121
			tokenizeLineToHTML(text, lineTokens, colorMap, 0, 12, 4, true),
122 123 124
			[
				'<div>',
				'<span style="color: #ff0000;font-style: italic;font-weight: bold;">Ciao</span>',
P
Peng Lyu 已提交
125
				'<span style="color: #000000;">&nbsp;</span>',
126
				'<span style="color: #00ff00;">hello</span>',
P
Peng Lyu 已提交
127
				'<span style="color: #000000;">&nbsp;</span>',
128 129 130 131 132 133
				'<span style="color: #0000ff;text-decoration: underline;">w</span>',
				'</div>'
			].join('')
		);

		assert.equal(
134
			tokenizeLineToHTML(text, lineTokens, colorMap, 0, 11, 4, true),
135 136 137
			[
				'<div>',
				'<span style="color: #ff0000;font-style: italic;font-weight: bold;">Ciao</span>',
P
Peng Lyu 已提交
138
				'<span style="color: #000000;">&nbsp;</span>',
139
				'<span style="color: #00ff00;">hello</span>',
P
Peng Lyu 已提交
140
				'<span style="color: #000000;">&nbsp;</span>',
141 142 143 144 145
				'</div>'
			].join('')
		);

		assert.equal(
146
			tokenizeLineToHTML(text, lineTokens, colorMap, 1, 11, 4, true),
147 148 149
			[
				'<div>',
				'<span style="color: #ff0000;font-style: italic;font-weight: bold;">iao</span>',
P
Peng Lyu 已提交
150
				'<span style="color: #000000;">&nbsp;</span>',
151
				'<span style="color: #00ff00;">hello</span>',
P
Peng Lyu 已提交
152
				'<span style="color: #000000;">&nbsp;</span>',
153 154 155 156 157
				'</div>'
			].join('')
		);

		assert.equal(
158
			tokenizeLineToHTML(text, lineTokens, colorMap, 4, 11, 4, true),
159 160
			[
				'<div>',
P
Peng Lyu 已提交
161
				'<span style="color: #000000;">&nbsp;</span>',
162
				'<span style="color: #00ff00;">hello</span>',
P
Peng Lyu 已提交
163
				'<span style="color: #000000;">&nbsp;</span>',
164 165 166 167 168
				'</div>'
			].join('')
		);

		assert.equal(
169
			tokenizeLineToHTML(text, lineTokens, colorMap, 5, 11, 4, true),
170 171 172
			[
				'<div>',
				'<span style="color: #00ff00;">hello</span>',
P
Peng Lyu 已提交
173
				'<span style="color: #000000;">&nbsp;</span>',
174 175 176 177 178
				'</div>'
			].join('')
		);

		assert.equal(
179
			tokenizeLineToHTML(text, lineTokens, colorMap, 5, 10, 4, true),
180 181 182 183 184 185 186 187
			[
				'<div>',
				'<span style="color: #00ff00;">hello</span>',
				'</div>'
			].join('')
		);

		assert.equal(
188
			tokenizeLineToHTML(text, lineTokens, colorMap, 6, 9, 4, true),
189 190 191 192 193 194 195
			[
				'<div>',
				'<span style="color: #00ff00;">ell</span>',
				'</div>'
			].join('')
		);
	});
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
	test('tokenizeLineToHTML handle spaces #35954', () => {
		const text = '  Ciao   hello world!';
		const lineTokens = new ViewLineTokens([
			new ViewLineToken(
				2,
				(
					(1 << MetadataConsts.FOREGROUND_OFFSET)
				) >>> 0
			),
			new ViewLineToken(
				6,
				(
					(3 << MetadataConsts.FOREGROUND_OFFSET)
					| ((FontStyle.Bold | FontStyle.Italic) << MetadataConsts.FONT_STYLE_OFFSET)
				) >>> 0
			),
			new ViewLineToken(
				9,
				(
					(1 << MetadataConsts.FOREGROUND_OFFSET)
				) >>> 0
			),
			new ViewLineToken(
				14,
				(
					(4 << MetadataConsts.FOREGROUND_OFFSET)
				) >>> 0
			),
			new ViewLineToken(
				15,
				(
					(1 << MetadataConsts.FOREGROUND_OFFSET)
				) >>> 0
			),
			new ViewLineToken(
				21,
				(
					(5 << MetadataConsts.FOREGROUND_OFFSET)
					| ((FontStyle.Underline) << MetadataConsts.FONT_STYLE_OFFSET)
				) >>> 0
			)
		]);
		const colorMap = [null!, '#000000', '#ffffff', '#ff0000', '#00ff00', '#0000ff'];

		assert.equal(
241
			tokenizeLineToHTML(text, lineTokens, colorMap, 0, 21, 4, true),
242 243
			[
				'<div>',
P
Peng Lyu 已提交
244
				'<span style="color: #000000;">&nbsp;&nbsp;</span>',
245
				'<span style="color: #ff0000;font-style: italic;font-weight: bold;">Ciao</span>',
P
Peng Lyu 已提交
246
				'<span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span>',
247
				'<span style="color: #00ff00;">hello</span>',
P
Peng Lyu 已提交
248
				'<span style="color: #000000;">&nbsp;</span>',
249 250 251 252 253 254
				'<span style="color: #0000ff;text-decoration: underline;">world!</span>',
				'</div>'
			].join('')
		);

		assert.equal(
255
			tokenizeLineToHTML(text, lineTokens, colorMap, 0, 17, 4, true),
256 257
			[
				'<div>',
P
Peng Lyu 已提交
258
				'<span style="color: #000000;">&nbsp;&nbsp;</span>',
259
				'<span style="color: #ff0000;font-style: italic;font-weight: bold;">Ciao</span>',
P
Peng Lyu 已提交
260
				'<span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span>',
261
				'<span style="color: #00ff00;">hello</span>',
P
Peng Lyu 已提交
262
				'<span style="color: #000000;">&nbsp;</span>',
263 264 265 266 267 268
				'<span style="color: #0000ff;text-decoration: underline;">wo</span>',
				'</div>'
			].join('')
		);

		assert.equal(
269
			tokenizeLineToHTML(text, lineTokens, colorMap, 0, 3, 4, true),
270 271
			[
				'<div>',
P
Peng Lyu 已提交
272
				'<span style="color: #000000;">&nbsp;&nbsp;</span>',
273 274 275 276 277
				'<span style="color: #ff0000;font-style: italic;font-weight: bold;">C</span>',
				'</div>'
			].join('')
		);
	});
278

E
Erich Gamma 已提交
279 280
});

A
Alex Dima 已提交
281
class Mode extends MockMode {
A
Alex Dima 已提交
282

283
	private static readonly _id = new LanguageIdentifier('textToHtmlTokenizerMode', 3);
A
Alex Dima 已提交
284

E
Erich Gamma 已提交
285
	constructor() {
A
Alex Dima 已提交
286 287
		super(Mode._id);
		this._register(TokenizationRegistry.register(this.getId(), {
A
Alex Dima 已提交
288 289
			getInitialState: (): IState => null!,
			tokenize: undefined!,
A
Tweaks  
Alex Dima 已提交
290
			tokenize2: (line: string, state: IState): TokenizationResult2 => {
A
Alex Dima 已提交
291 292
				let tokensArr: number[] = [];
				let prevColor: ColorId = -1;
A
Alex Dima 已提交
293
				for (let i = 0; i < line.length; i++) {
A
Alex Dima 已提交
294 295 296 297 298 299
					let colorId = line.charAt(i) === '.' ? 7 : 9;
					if (prevColor !== colorId) {
						tokensArr.push(i);
						tokensArr.push((
							colorId << MetadataConsts.FOREGROUND_OFFSET
						) >>> 0);
A
Alex Dima 已提交
300
					}
A
Alex Dima 已提交
301 302 303 304 305 306
					prevColor = colorId;
				}

				let tokens = new Uint32Array(tokensArr.length);
				for (let i = 0; i < tokens.length; i++) {
					tokens[i] = tokensArr[i];
A
Alex Dima 已提交
307
				}
A
Alex Dima 已提交
308
				return new TokenizationResult2(tokens, null!);
A
Alex Dima 已提交
309
			}
A
Alex Dima 已提交
310
		}));
E
Erich Gamma 已提交
311 312
	}
}