viewLineRenderer.test.ts 20.4 KB
Newer Older
A
Alex Dima 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

A
Alex Dima 已提交
7
import * as assert from 'assert';
A
Alex Dima 已提交
8
import { renderViewLine, RenderLineInput, CharacterMapping } from 'vs/editor/common/viewLayout/viewLineRenderer';
9
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
J
Johannes Rieken 已提交
10
import { CharCode } from 'vs/base/common/charCode';
A
Alex Dima 已提交
11 12 13

suite('viewLineRenderer.renderLine', () => {

14 15
	function createPart(endIndex: number, type: string): ViewLineToken {
		return new ViewLineToken(endIndex, type);
A
Alex Dima 已提交
16 17
	}

18
	function assertCharacterReplacement(lineContent: string, tabSize: number, expected: string, expectedCharOffsetInPart: number[][], expectedPartLengts: number[]): void {
A
Alex Dima 已提交
19
		let _actual = renderViewLine(new RenderLineInput(
20
			false,
A
Alex Dima 已提交
21
			lineContent,
22
			false,
23 24
			0,
			[new ViewLineToken(lineContent.length, '')],
25
			[],
A
Alex Dima 已提交
26
			tabSize,
27
			0,
A
Alex Dima 已提交
28
			-1,
29
			'none',
30
			false
A
Alex Dima 已提交
31
		));
A
Alex Dima 已提交
32

33
		assert.equal(_actual.html, '<span><span class="">' + expected + '</span></span>');
34
		assertCharacterMapping(_actual.characterMapping, expectedCharOffsetInPart);
35
		assertPartLengths(_actual.characterMapping, expectedPartLengts);
A
Alex Dima 已提交
36 37 38
	}

	test('replaces spaces', () => {
39 40 41
		assertCharacterReplacement(' ', 4, '&nbsp;', [[0, 1]], [1]);
		assertCharacterReplacement('  ', 4, '&nbsp;&nbsp;', [[0, 1, 2]], [2]);
		assertCharacterReplacement('a  b', 4, 'a&nbsp;&nbsp;b', [[0, 1, 2, 3, 4]], [4]);
A
Alex Dima 已提交
42 43 44
	});

	test('escapes HTML markup', () => {
45 46 47
		assertCharacterReplacement('a<b', 4, 'a&lt;b', [[0, 1, 2, 3]], [3]);
		assertCharacterReplacement('a>b', 4, 'a&gt;b', [[0, 1, 2, 3]], [3]);
		assertCharacterReplacement('a&b', 4, 'a&amp;b', [[0, 1, 2, 3]], [3]);
A
Alex Dima 已提交
48 49 50
	});

	test('replaces some bad characters', () => {
51 52 53 54
		assertCharacterReplacement('a\0b', 4, 'a&#00;b', [[0, 1, 2, 3]], [3]);
		assertCharacterReplacement('a' + String.fromCharCode(CharCode.UTF8_BOM) + 'b', 4, 'a\ufffdb', [[0, 1, 2, 3]], [3]);
		assertCharacterReplacement('a\u2028b', 4, 'a\ufffdb', [[0, 1, 2, 3]], [3]);
		assertCharacterReplacement('a\rb', 4, 'a&#8203b', [[0, 1, 2, 3]], [3]);
A
Alex Dima 已提交
55 56 57
	});

	test('handles tabs', () => {
58 59 60 61 62
		assertCharacterReplacement('\t', 4, '&nbsp;&nbsp;&nbsp;&nbsp;', [[0, 4]], [4]);
		assertCharacterReplacement('x\t', 4, 'x&nbsp;&nbsp;&nbsp;', [[0, 1, 4]], [4]);
		assertCharacterReplacement('xx\t', 4, 'xx&nbsp;&nbsp;', [[0, 1, 2, 4]], [4]);
		assertCharacterReplacement('xxx\t', 4, 'xxx&nbsp;', [[0, 1, 2, 3, 4]], [4]);
		assertCharacterReplacement('xxxx\t', 4, 'xxxx&nbsp;&nbsp;&nbsp;&nbsp;', [[0, 1, 2, 3, 4, 8]], [8]);
A
Alex Dima 已提交
63 64
	});

65
	function assertParts(lineContent: string, tabSize: number, parts: ViewLineToken[], expected: string, expectedCharOffsetInPart: number[][], expectedPartLengts: number[]): void {
A
Alex Dima 已提交
66
		let _actual = renderViewLine(new RenderLineInput(
67
			false,
A
Alex Dima 已提交
68
			lineContent,
69
			false,
70 71
			0,
			parts,
72
			[],
A
Alex Dima 已提交
73
			tabSize,
74
			0,
A
Alex Dima 已提交
75
			-1,
76
			'none',
77
			false
A
Alex Dima 已提交
78
		));
A
Alex Dima 已提交
79

80
		assert.equal(_actual.html, '<span>' + expected + '</span>');
81
		assertCharacterMapping(_actual.characterMapping, expectedCharOffsetInPart);
82
		assertPartLengths(_actual.characterMapping, expectedPartLengts);
A
Alex Dima 已提交
83 84 85
	}

	test('empty line', () => {
86
		assertParts('', 4, [], '<span>&nbsp;</span>', [], []);
A
Alex Dima 已提交
87 88 89
	});

	test('uses part type', () => {
90 91 92
		assertParts('x', 4, [createPart(1, 'y')], '<span class="y">x</span>', [[0, 1]], [1]);
		assertParts('x', 4, [createPart(1, 'aAbBzZ0123456789-cC')], '<span class="aAbBzZ0123456789-cC">x</span>', [[0, 1]], [1]);
		assertParts('x', 4, [createPart(1, '             ')], '<span class="             ">x</span>', [[0, 1]], [1]);
A
Alex Dima 已提交
93 94 95
	});

	test('two parts', () => {
96 97 98
		assertParts('xy', 4, [createPart(1, 'a'), createPart(2, 'b')], '<span class="a">x</span><span class="b">y</span>', [[0], [0, 1]], [1, 1]);
		assertParts('xyz', 4, [createPart(1, 'a'), createPart(3, 'b')], '<span class="a">x</span><span class="b">yz</span>', [[0], [0, 1, 2]], [1, 2]);
		assertParts('xyz', 4, [createPart(2, 'a'), createPart(3, 'b')], '<span class="a">xy</span><span class="b">z</span>', [[0, 1], [0, 1]], [2, 1]);
A
Alex Dima 已提交
99 100 101
	});

	test('overflow', () => {
A
Alex Dima 已提交
102
		let _actual = renderViewLine(new RenderLineInput(
103
			false,
A
Alex Dima 已提交
104
			'Hello world!',
105
			false,
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
			0,
			[
				createPart(1, '0'),
				createPart(2, '1'),
				createPart(3, '2'),
				createPart(4, '3'),
				createPart(5, '4'),
				createPart(6, '5'),
				createPart(7, '6'),
				createPart(8, '7'),
				createPart(9, '8'),
				createPart(10, '9'),
				createPart(11, '10'),
				createPart(12, '11'),
			],
121
			[],
A
Alex Dima 已提交
122
			4,
123
			10,
A
Alex Dima 已提交
124
			6,
125
			'boundary',
126
			false
A
Alex Dima 已提交
127
		));
A
Alex Dima 已提交
128 129

		let expectedOutput = [
130 131 132 133 134
			'<span class="0">H</span>',
			'<span class="1">e</span>',
			'<span class="2">l</span>',
			'<span class="3">l</span>',
			'<span class="4">o</span>',
A
Alex Dima 已提交
135
			'<span class="5">&nbsp;</span>',
136
			'<span class="vs-whitespace">&hellip;</span>'
A
Alex Dima 已提交
137 138
		].join('');

139
		assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
140 141 142 143 144 145
		assertCharacterMapping(_actual.characterMapping, [
			[0],
			[0],
			[0],
			[0],
			[0],
A
Alex Dima 已提交
146
			[0, 1],
A
Alex Dima 已提交
147
		]);
148
		assertPartLengths(_actual.characterMapping, [1, 1, 1, 1, 1, 1]);
A
Alex Dima 已提交
149 150 151 152 153
	});

	test('typical line', () => {
		let lineText = '\t    export class Game { // http://test.com     ';
		let lineParts = [
154 155 156 157 158 159 160 161 162 163 164 165
			createPart(5, 'block meta ts'),
			createPart(11, 'block declaration meta modifier object storage ts'),
			createPart(12, 'block declaration meta object ts'),
			createPart(17, 'block declaration meta object storage type ts'),
			createPart(18, 'block declaration meta object ts'),
			createPart(22, 'block class declaration entity meta name object ts'),
			createPart(23, 'block declaration meta object ts'),
			createPart(24, 'delimiter curly typescript'),
			createPart(25, 'block body declaration meta object ts'),
			createPart(28, 'block body comment declaration line meta object ts'),
			createPart(43, 'block body comment declaration line meta object ts detected-link'),
			createPart(48, 'block body comment declaration line meta object ts'),
A
Alex Dima 已提交
166 167
		];
		let expectedOutput = [
A
Alex Dima 已提交
168 169
			'<span class="vs-whitespace" style="width:40px">&rarr;&nbsp;&nbsp;&nbsp;</span>',
			'<span class="vs-whitespace" style="width:40px">&middot;&middot;&middot;&middot;</span>',
170 171 172 173 174 175 176 177 178 179
			'<span class="block declaration meta modifier object storage ts">export</span>',
			'<span class="block declaration meta object ts">&nbsp;</span>',
			'<span class="block declaration meta object storage type ts">class</span>',
			'<span class="block declaration meta object ts">&nbsp;</span>',
			'<span class="block class declaration entity meta name object ts">Game</span>',
			'<span class="block declaration meta object ts">&nbsp;</span>',
			'<span class="delimiter curly typescript">{</span>',
			'<span class="block body declaration meta object ts">&nbsp;</span>',
			'<span class="block body comment declaration line meta object ts">//&nbsp;</span>',
			'<span class="block body comment declaration line meta object ts detected-link">http://test.com</span>',
A
Alex Dima 已提交
180 181
			'<span class="vs-whitespace" style="width:20px">&middot;&middot;</span>',
			'<span class="vs-whitespace" style="width:30px">&middot;&middot;&middot;</span>'
A
Alex Dima 已提交
182 183
		].join('');
		let expectedOffsetsArr = [
184 185
			[0],
			[0, 1, 2, 3],
A
Alex Dima 已提交
186 187 188 189 190 191 192 193 194 195
			[0, 1, 2, 3, 4, 5],
			[0],
			[0, 1, 2, 3, 4],
			[0],
			[0, 1, 2, 3],
			[0],
			[0],
			[0],
			[0, 1, 2],
			[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
196 197
			[0, 1],
			[0, 1, 2, 3],
A
Alex Dima 已提交
198 199
		];

A
Alex Dima 已提交
200
		let _actual = renderViewLine(new RenderLineInput(
201
			false,
A
Alex Dima 已提交
202
			lineText,
203
			false,
204 205
			0,
			lineParts,
206
			[],
A
Alex Dima 已提交
207
			4,
208
			10,
A
Alex Dima 已提交
209
			-1,
210
			'boundary',
211
			false
A
Alex Dima 已提交
212
		));
A
Alex Dima 已提交
213

214
		assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
215
		assertCharacterMapping(_actual.characterMapping, expectedOffsetsArr);
216
		assertPartLengths(_actual.characterMapping, [4, 4, 6, 1, 5, 1, 4, 1, 1, 1, 3, 15, 2, 3]);
A
Alex Dima 已提交
217
	});
218 219 220 221 222

	test('issue #2255: Weird line rendering part 1', () => {
		let lineText = '\t\t\tcursorStyle:\t\t\t\t\t\t(prevOpts.cursorStyle !== newOpts.cursorStyle),';

		let lineParts = [
223 224 225 226 227 228 229 230 231 232
			createPart(3, 'block body decl declaration meta method object ts'), // 3 chars
			createPart(15, 'block body decl declaration member meta method object ts'), // 12 chars
			createPart(21, 'block body decl declaration member meta method object ts'), // 6 chars
			createPart(22, 'delimiter paren typescript'), // 1 char
			createPart(43, 'block body decl declaration member meta method object ts'), // 21 chars
			createPart(45, 'block body comparison decl declaration keyword member meta method object operator ts'), // 2 chars
			createPart(46, 'block body comparison decl declaration keyword member meta method object operator ts'), // 1 char
			createPart(66, 'block body decl declaration member meta method object ts'), // 20 chars
			createPart(67, 'delimiter paren typescript'), // 1 char
			createPart(68, 'block body decl declaration meta method object ts'), // 2 chars
233 234
		];
		let expectedOutput = [
235 236 237 238 239 240 241 242 243 244
			'<span class="block body decl declaration meta method object ts">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>',
			'<span class="block body decl declaration member meta method object ts">cursorStyle:</span>',
			'<span class="block body decl declaration member meta method object ts">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>',
			'<span class="delimiter paren typescript">(</span>',
			'<span class="block body decl declaration member meta method object ts">prevOpts.cursorStyle&nbsp;</span>',
			'<span class="block body comparison decl declaration keyword member meta method object operator ts">!=</span>',
			'<span class="block body comparison decl declaration keyword member meta method object operator ts">=</span>',
			'<span class="block body decl declaration member meta method object ts">&nbsp;newOpts.cursorStyle</span>',
			'<span class="delimiter paren typescript">)</span>',
			'<span class="block body decl declaration meta method object ts">,</span>',
245 246 247 248 249 250 251 252 253 254 255 256 257 258
		].join('');
		let expectedOffsetsArr = [
			[0, 4, 8], // 3 chars
			[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], // 12 chars
			[0, 4, 8, 12, 16, 20], // 6 chars
			[0], // 1 char
			[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], // 21 chars
			[0, 1], // 2 chars
			[0], // 1 char
			[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], // 20 chars
			[0], // 1 char
			[0, 1] // 2 chars
		];

A
Alex Dima 已提交
259
		let _actual = renderViewLine(new RenderLineInput(
260
			false,
A
Alex Dima 已提交
261
			lineText,
262
			false,
263 264
			0,
			lineParts,
265
			[],
A
Alex Dima 已提交
266
			4,
267
			10,
A
Alex Dima 已提交
268
			-1,
269
			'none',
270
			false
A
Alex Dima 已提交
271
		));
272

273
		assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
274
		assertCharacterMapping(_actual.characterMapping, expectedOffsetsArr);
275
		assertPartLengths(_actual.characterMapping, [12, 12, 24, 1, 21, 2, 1, 20, 1, 1]);
276 277 278 279 280 281
	});

	test('issue #2255: Weird line rendering part 2', () => {
		let lineText = ' \t\t\tcursorStyle:\t\t\t\t\t\t(prevOpts.cursorStyle !== newOpts.cursorStyle),';

		let lineParts = [
282 283 284 285 286 287 288 289 290 291
			createPart(4, 'block body decl declaration meta method object ts'), // 4 chars
			createPart(16, 'block body decl declaration member meta method object ts'), // 12 chars
			createPart(22, 'block body decl declaration member meta method object ts'), // 6 chars
			createPart(23, 'delimiter paren typescript'), // 1 char
			createPart(44, 'block body decl declaration member meta method object ts'), // 21 chars
			createPart(46, 'block body comparison decl declaration keyword member meta method object operator ts'), // 2 chars
			createPart(47, 'block body comparison decl declaration keyword member meta method object operator ts'), // 1 char
			createPart(67, 'block body decl declaration member meta method object ts'), // 20 chars
			createPart(68, 'delimiter paren typescript'), // 1 char
			createPart(69, 'block body decl declaration meta method object ts'), // 2 chars
292 293
		];
		let expectedOutput = [
294 295 296 297 298 299 300 301 302 303
			'<span class="block body decl declaration meta method object ts">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>',
			'<span class="block body decl declaration member meta method object ts">cursorStyle:</span>',
			'<span class="block body decl declaration member meta method object ts">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>',
			'<span class="delimiter paren typescript">(</span>',
			'<span class="block body decl declaration member meta method object ts">prevOpts.cursorStyle&nbsp;</span>',
			'<span class="block body comparison decl declaration keyword member meta method object operator ts">!=</span>',
			'<span class="block body comparison decl declaration keyword member meta method object operator ts">=</span>',
			'<span class="block body decl declaration member meta method object ts">&nbsp;newOpts.cursorStyle</span>',
			'<span class="delimiter paren typescript">)</span>',
			'<span class="block body decl declaration meta method object ts">,</span>',
304 305 306 307 308 309 310 311 312 313 314 315 316 317
		].join('');
		let expectedOffsetsArr = [
			[0, 1, 4, 8], // 4 chars
			[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], // 12 chars
			[0, 4, 8, 12, 16, 20], // 6 chars
			[0], // 1 char
			[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], // 21 chars
			[0, 1], // 2 chars
			[0], // 1 char
			[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], // 20 chars
			[0], // 1 char
			[0, 1] // 2 chars
		];

A
Alex Dima 已提交
318
		let _actual = renderViewLine(new RenderLineInput(
319
			false,
A
Alex Dima 已提交
320
			lineText,
321
			false,
322 323
			0,
			lineParts,
324
			[],
A
Alex Dima 已提交
325
			4,
326
			10,
A
Alex Dima 已提交
327
			-1,
328
			'none',
329
			false
A
Alex Dima 已提交
330
		));
331

332
		assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
333
		assertCharacterMapping(_actual.characterMapping, expectedOffsetsArr);
334
		assertPartLengths(_actual.characterMapping, [12, 12, 24, 1, 21, 2, 1, 20, 1, 1]);
335 336
	});

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
	test('issue Microsoft/monaco-editor#280: Improved source code rendering for RTL languages', () => {
		let lineText = 'var קודמות = \"מיותר קודמות צ\'ט של, אם לשון העברית שינויים ויש, אם\";';

		let lineParts = [
			createPart(3, 'mtk6'),
			createPart(13, 'mtk1'),
			createPart(66, 'mtk20'),
			createPart(67, 'mtk1'),
		];

		let expectedOutput = [
			'<span dir="ltr" class="mtk6">var</span>',
			'<span dir="ltr" class="mtk1">&nbsp;קודמות&nbsp;=&nbsp;</span>',
			'<span dir="ltr" class="mtk20">"מיותר&nbsp;קודמות&nbsp;צ\'ט&nbsp;של,&nbsp;אם&nbsp;לשון&nbsp;העברית&nbsp;שינויים&nbsp;ויש,&nbsp;אם"</span>',
			'<span dir="ltr" class="mtk1">;</span>'
		].join('');

		let _actual = renderViewLine(new RenderLineInput(
355
			false,
356 357 358 359 360 361 362 363 364 365 366 367
			lineText,
			true,
			0,
			lineParts,
			[],
			4,
			10,
			-1,
			'none',
			false
		));

368
		assert.equal(_actual.html, '<span>' + expectedOutput + '</span>');
369
		assert.equal(_actual.containsRTL, true);
370 371 372 373 374 375 376 377 378 379 380
	});

	test('issue #6885: Splits large tokens', () => {
		//                                                                                                                  1         1         1
		//                        1         2         3         4         5         6         7         8         9         0         1         2
		//               1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234
		let _lineText = 'This is just a long line that contains very interesting text. This is just a long line that contains very interesting text.';

		function assertSplitsTokens(message: string, lineText: string, expectedOutput: string[]): void {
			let lineParts = [createPart(lineText.length, 'mtk1')];
			let actual = renderViewLine(new RenderLineInput(
381
				false,
382 383 384 385 386 387 388 389 390 391 392
				lineText,
				false,
				0,
				lineParts,
				[],
				4,
				10,
				-1,
				'none',
				false
			));
393
			assert.equal(actual.html, '<span>' + expectedOutput.join('') + '</span>', message);
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
		}

		// A token with 49 chars
		{
			assertSplitsTokens(
				'49 chars',
				_lineText.substr(0, 49),
				[
					'<span class="mtk1">This&nbsp;is&nbsp;just&nbsp;a&nbsp;long&nbsp;line&nbsp;that&nbsp;contains&nbsp;very&nbsp;inter</span>',
				]
			);
		}

		// A token with 50 chars
		{
			assertSplitsTokens(
				'50 chars',
				_lineText.substr(0, 50),
				[
					'<span class="mtk1">This&nbsp;is&nbsp;just&nbsp;a&nbsp;long&nbsp;line&nbsp;that&nbsp;contains&nbsp;very&nbsp;intere</span>',
				]
			);
		}

		// A token with 51 chars
		{
			assertSplitsTokens(
				'51 chars',
				_lineText.substr(0, 51),
				[
					'<span class="mtk1">This&nbsp;is&nbsp;just&nbsp;a&nbsp;long&nbsp;line&nbsp;that&nbsp;contains&nbsp;very&nbsp;intere</span>',
					'<span class="mtk1">s</span>',
				]
			);
		}

		// A token with 99 chars
		{
			assertSplitsTokens(
				'99 chars',
				_lineText.substr(0, 99),
				[
					'<span class="mtk1">This&nbsp;is&nbsp;just&nbsp;a&nbsp;long&nbsp;line&nbsp;that&nbsp;contains&nbsp;very&nbsp;intere</span>',
					'<span class="mtk1">sting&nbsp;text.&nbsp;This&nbsp;is&nbsp;just&nbsp;a&nbsp;long&nbsp;line&nbsp;that&nbsp;contain</span>',
				]
			);
		}

		// A token with 100 chars
		{
			assertSplitsTokens(
				'100 chars',
				_lineText.substr(0, 100),
				[
					'<span class="mtk1">This&nbsp;is&nbsp;just&nbsp;a&nbsp;long&nbsp;line&nbsp;that&nbsp;contains&nbsp;very&nbsp;intere</span>',
					'<span class="mtk1">sting&nbsp;text.&nbsp;This&nbsp;is&nbsp;just&nbsp;a&nbsp;long&nbsp;line&nbsp;that&nbsp;contains</span>',
				]
			);
		}

		// A token with 101 chars
		{
			assertSplitsTokens(
				'101 chars',
				_lineText.substr(0, 101),
				[
					'<span class="mtk1">This&nbsp;is&nbsp;just&nbsp;a&nbsp;long&nbsp;line&nbsp;that&nbsp;contains&nbsp;very&nbsp;intere</span>',
					'<span class="mtk1">sting&nbsp;text.&nbsp;This&nbsp;is&nbsp;just&nbsp;a&nbsp;long&nbsp;line&nbsp;that&nbsp;contains</span>',
					'<span class="mtk1">&nbsp;</span>',
				]
			);
		}
	});

	test('issue #6885: Does not split large tokens in RTL text', () => {
		let lineText = 'את גרמנית בהתייחסות שמו, שנתי המשפט אל חפש, אם כתב אחרים ולחבר. של התוכן אודות בויקיפדיה כלל, של עזרה כימיה היא. על עמוד יוצרים מיתולוגיה סדר, אם שכל שתפו לעברית שינויים, אם שאלות אנגלית עזה. שמות בקלות מה סדר.';
		let lineParts = [createPart(lineText.length, 'mtk1')];
		let expectedOutput = [
			'<span dir="ltr" class="mtk1">את&nbsp;גרמנית&nbsp;בהתייחסות&nbsp;שמו,&nbsp;שנתי&nbsp;המשפט&nbsp;אל&nbsp;חפש,&nbsp;אם&nbsp;כתב&nbsp;אחרים&nbsp;ולחבר.&nbsp;של&nbsp;התוכן&nbsp;אודות&nbsp;בויקיפדיה&nbsp;כלל,&nbsp;של&nbsp;עזרה&nbsp;כימיה&nbsp;היא.&nbsp;על&nbsp;עמוד&nbsp;יוצרים&nbsp;מיתולוגיה&nbsp;סדר,&nbsp;אם&nbsp;שכל&nbsp;שתפו&nbsp;לעברית&nbsp;שינויים,&nbsp;אם&nbsp;שאלות&nbsp;אנגלית&nbsp;עזה.&nbsp;שמות&nbsp;בקלות&nbsp;מה&nbsp;סדר.</span>'
		];
		let actual = renderViewLine(new RenderLineInput(
475
			false,
476 477 478 479 480 481 482 483 484 485 486
			lineText,
			true,
			0,
			lineParts,
			[],
			4,
			10,
			-1,
			'none',
			false
		));
487
		assert.equal(actual.html, '<span>' + expectedOutput.join('') + '</span>');
488
		assert.equal(actual.containsRTL, true);
489 490
	});

491 492 493 494 495 496
	function assertCharacterMapping(actual: CharacterMapping, expected: number[][]): void {
		let charOffset = 0;
		for (let partIndex = 0; partIndex < expected.length; partIndex++) {
			let part = expected[partIndex];
			for (let i = 0; i < part.length; i++) {
				let charIndex = part[i];
497
				// here
498 499 500 501 502 503 504 505 506
				let _actualPartData = actual.charOffsetToPartData(charOffset);
				let actualPartIndex = CharacterMapping.getPartIndex(_actualPartData);
				let actualCharIndex = CharacterMapping.getCharIndex(_actualPartData);

				assert.deepEqual(
					{ partIndex: actualPartIndex, charIndex: actualCharIndex },
					{ partIndex: partIndex, charIndex: charIndex },
					`character mapping for offset ${charOffset}`
				);
507

508
				// here
509 510 511 512 513 514 515 516 517 518 519 520 521 522
				let actualOffset = actual.partDataToCharOffset(partIndex, part[part.length - 1] + 1, charIndex);

				assert.equal(
					actualOffset,
					charOffset,
					`character mapping for part ${partIndex}, ${charIndex}`
				);

				charOffset++;
			}
		}

		assert.equal(actual.length, charOffset);
	}
523 524 525 526 527 528 529 530 531

	function assertPartLengths(actual: CharacterMapping, expected: number[]): void {
		let _partLengths = actual.getPartLengths();
		let actualLengths: number[] = [];
		for (let i = 0; i < _partLengths.length; i++) {
			actualLengths[i] = _partLengths[i];
		}
		assert.deepEqual(actualLengths, expected, 'part lengths OK');
	}
A
Alex Dima 已提交
532
});