]> git.proxmox.com Git - mirror_xterm.js.git/blob - test/test.js
Merge pull request #351 from yuvipanda/docsome
[mirror_xterm.js.git] / test / test.js
1 var assert = require('chai').assert;
2 var expect = require('chai').expect;
3 var Terminal = require('../src/xterm');
4
5 describe('xterm.js', function() {
6 var xterm;
7
8 beforeEach(function () {
9 xterm = new Terminal();
10 xterm.refresh = function(){};
11 xterm.viewport = {
12 syncScrollArea: function(){}
13 };
14 });
15
16 describe('getOption', function() {
17 it('should retrieve the option correctly', function() {
18 // In the `options` namespace.
19 xterm.options.cursorBlink = true;
20 assert.equal(xterm.getOption('cursorBlink'), true);
21
22 // On the Terminal instance
23 delete xterm.options.cursorBlink;
24 xterm.cursorBlink = false;
25 assert.equal(xterm.getOption('cursorBlink'), false);
26 });
27 it('should throw when retrieving a non-existant option', function() {
28 assert.throws(xterm.getOption.bind(xterm, 'fake', true));
29 });
30 });
31
32 describe('setOption', function() {
33 it('should set the option correctly', function() {
34 xterm.setOption('cursorBlink', true);
35 assert.equal(xterm.cursorBlink, true);
36 assert.equal(xterm.options.cursorBlink, true);
37 xterm.setOption('cursorBlink', false);
38 assert.equal(xterm.cursorBlink, false);
39 assert.equal(xterm.options.cursorBlink, false);
40 });
41 it('should throw when setting a non-existant option', function() {
42 assert.throws(xterm.setOption.bind(xterm, 'fake', true));
43 });
44 });
45
46 describe('clear', function() {
47 it('should clear a buffer equal to rows', function() {
48 var promptLine = xterm.lines[xterm.ybase + xterm.y];
49 xterm.clear();
50 assert.equal(xterm.y, 0);
51 assert.equal(xterm.ybase, 0);
52 assert.equal(xterm.ydisp, 0);
53 assert.equal(xterm.lines.length, xterm.rows);
54 assert.deepEqual(xterm.lines[0], promptLine);
55 for (var i = 1; i < xterm.rows; i++) {
56 assert.deepEqual(xterm.lines[0], xterm.blankLine());
57 }
58 });
59 it('should clear a buffer larger than rows', function() {
60 // Fill the buffer with dummy rows
61 for (var i = 0; i < xterm.rows * 2; i++) {
62 xterm.write('test\n');
63 }
64
65 var promptLine = xterm.lines[xterm.ybase + xterm.y];
66 xterm.clear();
67 assert.equal(xterm.y, 0);
68 assert.equal(xterm.ybase, 0);
69 assert.equal(xterm.ydisp, 0);
70 assert.equal(xterm.lines.length, xterm.rows);
71 assert.deepEqual(xterm.lines[0], promptLine);
72 for (var i = 1; i < xterm.rows; i++) {
73 assert.deepEqual(xterm.lines[i], xterm.blankLine());
74 }
75 });
76 it('should not break the prompt when cleared twice', function() {
77 var promptLine = xterm.lines[xterm.ybase + xterm.y];
78 xterm.clear();
79 xterm.clear();
80 assert.equal(xterm.y, 0);
81 assert.equal(xterm.ybase, 0);
82 assert.equal(xterm.ydisp, 0);
83 assert.equal(xterm.lines.length, xterm.rows);
84 assert.deepEqual(xterm.lines[0], promptLine);
85 for (var i = 1; i < xterm.rows; i++) {
86 assert.deepEqual(xterm.lines[i], xterm.blankLine());
87 }
88 });
89 });
90
91 describe('scroll', function() {
92 describe('scrollDisp', function() {
93 var startYDisp;
94 beforeEach(function() {
95 for (var i = 0; i < xterm.rows * 2; i++) {
96 xterm.writeln('test');
97 }
98 startYDisp = xterm.rows + 1;
99 });
100 it('should scroll a single line', function() {
101 assert.equal(xterm.ydisp, startYDisp);
102 xterm.scrollDisp(-1);
103 assert.equal(xterm.ydisp, startYDisp - 1);
104 xterm.scrollDisp(1);
105 assert.equal(xterm.ydisp, startYDisp);
106 });
107 it('should scroll multiple lines', function() {
108 assert.equal(xterm.ydisp, startYDisp);
109 xterm.scrollDisp(-5);
110 assert.equal(xterm.ydisp, startYDisp - 5);
111 xterm.scrollDisp(5);
112 assert.equal(xterm.ydisp, startYDisp);
113 });
114 it('should not scroll beyond the bounds of the buffer', function() {
115 assert.equal(xterm.ydisp, startYDisp);
116 xterm.scrollDisp(1);
117 assert.equal(xterm.ydisp, startYDisp);
118 for (var i = 0; i < startYDisp; i++) {
119 xterm.scrollDisp(-1);
120 }
121 assert.equal(xterm.ydisp, 0);
122 xterm.scrollDisp(-1);
123 assert.equal(xterm.ydisp, 0);
124 });
125 });
126
127 describe('scrollPages', function() {
128 var startYDisp;
129 beforeEach(function() {
130 for (var i = 0; i < xterm.rows * 3; i++) {
131 xterm.writeln('test');
132 }
133 startYDisp = (xterm.rows * 2) + 1;
134 });
135 it('should scroll a single page', function() {
136 assert.equal(xterm.ydisp, startYDisp);
137 xterm.scrollPages(-1);
138 assert.equal(xterm.ydisp, startYDisp - (xterm.rows - 1));
139 xterm.scrollPages(1);
140 assert.equal(xterm.ydisp, startYDisp);
141 });
142 it('should scroll a multiple pages', function() {
143 assert.equal(xterm.ydisp, startYDisp);
144 xterm.scrollPages(-2);
145 assert.equal(xterm.ydisp, startYDisp - (xterm.rows - 1) * 2);
146 xterm.scrollPages(2);
147 assert.equal(xterm.ydisp, startYDisp);
148 });
149 });
150
151 describe('scrollToTop', function() {
152 beforeEach(function() {
153 for (var i = 0; i < xterm.rows * 3; i++) {
154 xterm.writeln('test');
155 }
156 });
157 it('should scroll to the top', function() {
158 assert.notEqual(xterm.ydisp, 0);
159 xterm.scrollToTop();
160 assert.equal(xterm.ydisp, 0);
161 });
162 });
163
164 describe('scrollToBottom', function() {
165 var startYDisp;
166 beforeEach(function() {
167 for (var i = 0; i < xterm.rows * 3; i++) {
168 xterm.writeln('test');
169 }
170 startYDisp = (xterm.rows * 2) + 1;
171 });
172 it('should scroll to the bottom', function() {
173 xterm.scrollDisp(-1);
174 xterm.scrollToBottom();
175 assert.equal(xterm.ydisp, startYDisp);
176 xterm.scrollPages(-1);
177 xterm.scrollToBottom();
178 assert.equal(xterm.ydisp, startYDisp);
179 xterm.scrollToTop();
180 xterm.scrollToBottom();
181 assert.equal(xterm.ydisp, startYDisp);
182 });
183 });
184
185 describe('keyDown', function () {
186 it('should scroll down, when a key is pressed and terminal is scrolled up', function () {
187 var terminal = new Terminal();
188
189 // Do not process the keyDown event, to avoid side-effects
190 terminal.attachCustomKeydownHandler(function () {
191 return false;
192 });
193
194 terminal.ydisp = 0;
195 terminal.ybase = 40;
196
197 terminal.keyDown();
198
199 // Ensure that now the terminal is scrolled to bottom
200 assert.equal(terminal.ydisp, terminal.ybase);
201 });
202 });
203 });
204
205 describe('evaluateKeyEscapeSequence', function() {
206 it('should return the correct escape sequence for unmodified keys', function() {
207 // Backspace
208 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 8 }).key, '\x7f'); // ^?
209 // Tab
210 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 9 }).key, '\t');
211 // Return/enter
212 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 13 }).key, '\r'); // CR
213 // Escape
214 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 27 }).key, '\x1b');
215 // Page up, page down
216 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 33 }).key, '\x1b[5~'); // CSI 5 ~
217 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 34 }).key, '\x1b[6~'); // CSI 6 ~
218 // End, Home
219 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 35 }).key, '\x1b[F'); // SS3 F
220 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 36 }).key, '\x1b[H'); // SS3 H
221 // Left, up, right, down arrows
222 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 37 }).key, '\x1b[D'); // CSI D
223 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 38 }).key, '\x1b[A'); // CSI A
224 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 39 }).key, '\x1b[C'); // CSI C
225 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 40 }).key, '\x1b[B'); // CSI B
226 // Insert
227 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 45 }).key, '\x1b[2~'); // CSI 2 ~
228 // Delete
229 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 46 }).key, '\x1b[3~'); // CSI 3 ~
230 // F1-F12
231 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 112 }).key, '\x1bOP'); // SS3 P
232 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 113 }).key, '\x1bOQ'); // SS3 Q
233 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 114 }).key, '\x1bOR'); // SS3 R
234 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 115 }).key, '\x1bOS'); // SS3 S
235 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 116 }).key, '\x1b[15~'); // CSI 1 5 ~
236 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 117 }).key, '\x1b[17~'); // CSI 1 7 ~
237 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 118 }).key, '\x1b[18~'); // CSI 1 8 ~
238 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 119 }).key, '\x1b[19~'); // CSI 1 9 ~
239 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 120 }).key, '\x1b[20~'); // CSI 2 0 ~
240 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 121 }).key, '\x1b[21~'); // CSI 2 1 ~
241 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 122 }).key, '\x1b[23~'); // CSI 2 3 ~
242 assert.equal(xterm.evaluateKeyEscapeSequence({ keyCode: 123 }).key, '\x1b[24~'); // CSI 2 4 ~
243 });
244 it('should return \\x1b[3;5~ for ctrl+delete', function() {
245 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 46 }).key, '\x1b[3;5~');
246 });
247 it('should return \\x1b[3;2~ for shift+delete', function() {
248 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 46 }).key, '\x1b[3;2~');
249 });
250 it('should return \\x1b[3;3~ for alt+delete', function() {
251 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 46 }).key, '\x1b[3;3~');
252 });
253 it('should return \\x1b[5D for ctrl+left', function() {
254 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D
255 });
256 it('should return \\x1b[5C for ctrl+right', function() {
257 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C
258 });
259 it('should return \\x1b[5A for ctrl+up', function() {
260 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A
261 });
262 it('should return \\x1b[5B for ctrl+down', function() {
263 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 40 }).key, '\x1b[1;5B'); // CSI 5 B
264 });
265 // Evalueate alt + arrow key movement, which is a feature of terminal emulators but not VT100
266 // http://unix.stackexchange.com/a/108106
267 it('should return \\x1b[5D for alt+left', function() {
268 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 37 }).key, '\x1b[1;5D'); // CSI 5 D
269 });
270 it('should return \\x1b[5C for alt+right', function() {
271 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 39 }).key, '\x1b[1;5C'); // CSI 5 C
272 });
273 it('should return \\x1b[5A for alt+up', function() {
274 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 38 }).key, '\x1b[1;5A'); // CSI 5 A
275 });
276 it('should return \\x1b[5B for alt+down', function() {
277 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 40 }).key, '\x1b[1;5B'); // CSI 5 B
278 });
279 it('should return the correct escape sequence for modified F1-F12 keys', function() {
280 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 112 }).key, '\x1b[1;2P');
281 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 113 }).key, '\x1b[1;2Q');
282 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 114 }).key, '\x1b[1;2R');
283 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 115 }).key, '\x1b[1;2S');
284 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 116 }).key, '\x1b[15;2~');
285 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 117 }).key, '\x1b[17;2~');
286 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 118 }).key, '\x1b[18;2~');
287 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 119 }).key, '\x1b[19;2~');
288 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 120 }).key, '\x1b[20;2~');
289 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 121 }).key, '\x1b[21;2~');
290 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 122 }).key, '\x1b[23;2~');
291 assert.equal(xterm.evaluateKeyEscapeSequence({ shiftKey: true, keyCode: 123 }).key, '\x1b[24;2~');
292 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 112 }).key, '\x1b[1;3P');
293 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 113 }).key, '\x1b[1;3Q');
294 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 114 }).key, '\x1b[1;3R');
295 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 115 }).key, '\x1b[1;3S');
296 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 116 }).key, '\x1b[15;3~');
297 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 117 }).key, '\x1b[17;3~');
298 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 118 }).key, '\x1b[18;3~');
299 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 119 }).key, '\x1b[19;3~');
300 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 120 }).key, '\x1b[20;3~');
301 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 121 }).key, '\x1b[21;3~');
302 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 122 }).key, '\x1b[23;3~');
303 assert.equal(xterm.evaluateKeyEscapeSequence({ altKey: true, keyCode: 123 }).key, '\x1b[24;3~');
304
305 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 112 }).key, '\x1b[1;5P');
306 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 113 }).key, '\x1b[1;5Q');
307 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 114 }).key, '\x1b[1;5R');
308 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 115 }).key, '\x1b[1;5S');
309 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 116 }).key, '\x1b[15;5~');
310 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 117 }).key, '\x1b[17;5~');
311 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 118 }).key, '\x1b[18;5~');
312 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 119 }).key, '\x1b[19;5~');
313 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 120 }).key, '\x1b[20;5~');
314 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 121 }).key, '\x1b[21;5~');
315 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 122 }).key, '\x1b[23;5~');
316 assert.equal(xterm.evaluateKeyEscapeSequence({ ctrlKey: true, keyCode: 123 }).key, '\x1b[24;5~');
317 });
318 });
319
320 describe('attachCustomEventHandler', function () {
321 var evKeyDown = {
322 preventDefault: function() {},
323 stopPropagation: function() {},
324 type: 'keydown'
325 }
326
327 beforeEach(function() {
328 xterm.handler = function() {};
329 xterm.showCursor = function() {};
330 xterm.clearSelection = function() {};
331 xterm.compositionHelper = {
332 keydown: {
333 bind: function() {
334 return function () { return true; }
335 }
336 }
337 }
338 });
339
340 it('should process the keydown event based on what the handler returns', function () {
341 assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), true);
342 xterm.attachCustomKeydownHandler(function (ev) {
343 return ev.keyCode === 77;
344 });
345 assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), true);
346 xterm.attachCustomKeydownHandler(function (ev) {
347 return ev.keyCode !== 77;
348 });
349 assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), false);
350 });
351
352 it('should alive after reset(ESC c Full Reset (RIS))', function () {
353 xterm.attachCustomKeydownHandler(function (ev) {
354 return ev.keyCode !== 77;
355 });
356 assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), false);
357 xterm.reset();
358 assert.equal(xterm.keyDown(Object.assign({}, evKeyDown, { keyCode: 77 })), false);
359 });
360 });
361
362 describe('Third level shift', function() {
363 var evKeyDown = {
364 preventDefault: function() {},
365 stopPropagation: function() {},
366 type: 'keydown'
367 },
368 evKeyPress = {
369 preventDefault: function() {},
370 stopPropagation: function() {},
371 type: 'keypress'
372 };
373
374 beforeEach(function() {
375 xterm.handler = function() {};
376 xterm.showCursor = function() {};
377 xterm.clearSelection = function() {};
378 xterm.compositionHelper = {
379 isComposing: false,
380 keydown: {
381 bind: function() {
382 return function() { return true; };
383 }
384 }
385 };
386 });
387
388 describe('On Mac OS', function() {
389 beforeEach(function() {
390 xterm.browser.isMac = true;
391 });
392
393 it('should not interfere with the alt key on keyDown', function() {
394 assert.equal(
395 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, keyCode: 81 })),
396 true
397 );
398 assert.equal(
399 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, keyCode: 192 })),
400 true
401 );
402 });
403
404 it('should interefere with the alt + arrow keys', function() {
405 assert.equal(
406 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, keyCode: 37 })),
407 false
408 );
409 assert.equal(
410 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, keyCode: 39 })),
411 false
412 );
413 });
414
415 it('should emit key with alt + key on keyPress', function(done) {
416 var keys = ['@', '@', '\\', '\\', '|', '|'];
417
418 xterm.on('keypress', function(key) {
419 if (key) {
420 var index = keys.indexOf(key);
421 assert(index !== -1, "Emitted wrong key: " + key);
422 keys.splice(index, 1);
423 }
424 if (keys.length === 0) done();
425 });
426
427 xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 64 })); // @
428 // Firefox
429 xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, charCode: 64, keyCode: 0 }));
430 xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 92 })); // \
431 xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, charCode: 92, keyCode: 0 }));
432 xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, keyCode: 124 })); // |
433 xterm.keyPress(Object.assign({}, evKeyPress, { altKey: true, charCode: 124, keyCode: 0 }));
434 });
435 });
436
437 describe('On MS Windows', function() {
438 beforeEach(function() {
439 xterm.browser.isMSWindows = true;
440 });
441
442 it('should not interfere with the alt + ctrl key on keyDown', function() {
443 assert.equal(
444 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, ctrlKey: true, keyCode: 81 })),
445 true
446 );
447 assert.equal(
448 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, ctrlKey: true, keyCode: 192 })),
449 true
450 );
451 });
452
453 it('should interefere with the alt + ctrl + arrow keys', function() {
454 assert.equal(
455 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, ctrlKey: true, keyCode: 37 })),
456 false
457 );
458 assert.equal(
459 xterm.keyDown(Object.assign({}, evKeyDown, { altKey: true, ctrlKey: true, keyCode: 39 })),
460 false
461 );
462 });
463
464 it('should emit key with alt + ctrl + key on keyPress', function(done) {
465 var keys = ['@', '@', '\\', '\\', '|', '|'];
466
467 xterm.on('keypress', function(key) {
468 if (key) {
469 var index = keys.indexOf(key);
470 assert(index !== -1, "Emitted wrong key: " + key);
471 keys.splice(index, 1);
472 }
473 if (keys.length === 0) done();
474 });
475
476 xterm.keyPress(
477 Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 64 })
478 ); // @
479 xterm.keyPress(
480 Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, charCode: 64, keyCode: 0 })
481 );
482 xterm.keyPress(
483 Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 92 })
484 ); // \
485 xterm.keyPress(
486 Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, charCode: 92, keyCode: 0 })
487 );
488 xterm.keyPress(
489 Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, keyCode: 124 })
490 ); // |
491 xterm.keyPress(
492 Object.assign({}, evKeyPress, { altKey: true, ctrlKey: true, charCode: 124, keyCode: 0 })
493 );
494 });
495 });
496 });
497
498 describe('unicode - surrogates', function() {
499 it('2 characters per cell', function () {
500 var high = String.fromCharCode(0xD800);
501 for (var i=0xDC00; i<=0xDCFF; ++i) {
502 xterm.write(high + String.fromCharCode(i));
503 var tchar = xterm.lines[0][0];
504 expect(tchar[1]).eql(high + String.fromCharCode(i));
505 expect(tchar[1].length).eql(2);
506 expect(tchar[2]).eql(1);
507 expect(xterm.lines[0][1][1]).eql(' ');
508 xterm.reset();
509 }
510 });
511 it('2 characters at last cell', function() {
512 var high = String.fromCharCode(0xD800);
513 for (var i=0xDC00; i<=0xDCFF; ++i) {
514 xterm.x = xterm.cols - 1;
515 xterm.write(high + String.fromCharCode(i));
516 expect(xterm.lines[0][xterm.x-1][1]).eql(high + String.fromCharCode(i));
517 expect(xterm.lines[0][xterm.x-1][1].length).eql(2);
518 expect(xterm.lines[1][0][1]).eql(' ');
519 xterm.reset();
520 }
521 });
522 it('2 characters per cell over line end with autowrap', function() {
523 var high = String.fromCharCode(0xD800);
524 for (var i=0xDC00; i<=0xDCFF; ++i) {
525 xterm.x = xterm.cols - 1;
526 xterm.wraparoundMode = true;
527 xterm.write('a' + high + String.fromCharCode(i));
528 expect(xterm.lines[0][xterm.cols-1][1]).eql('a');
529 expect(xterm.lines[1][0][1]).eql(high + String.fromCharCode(i));
530 expect(xterm.lines[1][0][1].length).eql(2);
531 expect(xterm.lines[1][1][1]).eql(' ');
532 xterm.reset();
533 }
534 });
535 it('2 characters per cell over line end without autowrap', function() {
536 var high = String.fromCharCode(0xD800);
537 for (var i=0xDC00; i<=0xDCFF; ++i) {
538 xterm.x = xterm.cols - 1;
539 xterm.wraparoundMode = false;
540 xterm.write('a' + high + String.fromCharCode(i));
541 expect(xterm.lines[0][xterm.cols-1][1]).eql(high + String.fromCharCode(i));
542 expect(xterm.lines[0][xterm.cols-1][1].length).eql(2);
543 expect(xterm.lines[1][1][1]).eql(' ');
544 xterm.reset();
545 }
546 });
547 it('splitted surrogates', function() {
548 var high = String.fromCharCode(0xD800);
549 for (var i=0xDC00; i<=0xDCFF; ++i) {
550 xterm.write(high);
551 xterm.write(String.fromCharCode(i));
552 var tchar = xterm.lines[0][0];
553 expect(tchar[1]).eql(high + String.fromCharCode(i));
554 expect(tchar[1].length).eql(2);
555 expect(tchar[2]).eql(1);
556 expect(xterm.lines[0][1][1]).eql(' ');
557 xterm.reset();
558 }
559 });
560 });
561
562 describe('unicode - combining characters', function() {
563 it('café', function () {
564 xterm.write('cafe\u0301');
565 expect(xterm.lines[0][3][1]).eql('e\u0301');
566 expect(xterm.lines[0][3][1].length).eql(2);
567 expect(xterm.lines[0][3][2]).eql(1);
568 });
569 it('café - end of line', function() {
570 xterm.x = xterm.cols - 1 - 3;
571 xterm.write('cafe\u0301');
572 expect(xterm.lines[0][xterm.cols-1][1]).eql('e\u0301');
573 expect(xterm.lines[0][xterm.cols-1][1].length).eql(2);
574 expect(xterm.lines[0][xterm.cols-1][2]).eql(1);
575 expect(xterm.lines[0][1][1]).eql(' ');
576 expect(xterm.lines[0][1][1].length).eql(1);
577 expect(xterm.lines[0][1][2]).eql(1);
578 });
579 it('multiple combined é', function() {
580 xterm.wraparoundMode = true;
581 xterm.write(Array(100).join('e\u0301'));
582 for (var i=0; i<xterm.cols; ++i) {
583 var tchar = xterm.lines[0][i];
584 expect(tchar[1]).eql('e\u0301');
585 expect(tchar[1].length).eql(2);
586 expect(tchar[2]).eql(1);
587 }
588 tchar = xterm.lines[1][0];
589 expect(tchar[1]).eql('e\u0301');
590 expect(tchar[1].length).eql(2);
591 expect(tchar[2]).eql(1);
592 });
593 it('multiple surrogate with combined', function() {
594 xterm.wraparoundMode = true;
595 xterm.write(Array(100).join('\uD800\uDC00\u0301'));
596 for (var i=0; i<xterm.cols; ++i) {
597 var tchar = xterm.lines[0][i];
598 expect(tchar[1]).eql('\uD800\uDC00\u0301');
599 expect(tchar[1].length).eql(3);
600 expect(tchar[2]).eql(1);
601 }
602 tchar = xterm.lines[1][0];
603 expect(tchar[1]).eql('\uD800\uDC00\u0301');
604 expect(tchar[1].length).eql(3);
605 expect(tchar[2]).eql(1);
606 });
607 });
608
609 describe('unicode - fullwidth characters', function() {
610 it('cursor movement even', function() {
611 expect(xterm.x).eql(0);
612 xterm.write('¥');
613 expect(xterm.x).eql(2);
614 });
615 it('cursor movement odd', function() {
616 xterm.x = 1;
617 expect(xterm.x).eql(1);
618 xterm.write('¥');
619 expect(xterm.x).eql(3);
620 });
621 it('line of ¥ even', function() {
622 xterm.wraparoundMode = true;
623 xterm.write(Array(50).join('¥'));
624 for (var i=0; i<xterm.cols; ++i) {
625 var tchar = xterm.lines[0][i];
626 if (i % 2) {
627 expect(tchar[1]).eql('');
628 expect(tchar[1].length).eql(0);
629 expect(tchar[2]).eql(0);
630 } else {
631 expect(tchar[1]).eql('¥');
632 expect(tchar[1].length).eql(1);
633 expect(tchar[2]).eql(2);
634 }
635 }
636 tchar = xterm.lines[1][0];
637 expect(tchar[1]).eql('¥');
638 expect(tchar[1].length).eql(1);
639 expect(tchar[2]).eql(2);
640 });
641 it('line of ¥ odd', function() {
642 xterm.wraparoundMode = true;
643 xterm.x = 1;
644 xterm.write(Array(50).join('¥'));
645 for (var i=1; i<xterm.cols-1; ++i) {
646 var tchar = xterm.lines[0][i];
647 if (!(i % 2)) {
648 expect(tchar[1]).eql('');
649 expect(tchar[1].length).eql(0);
650 expect(tchar[2]).eql(0);
651 } else {
652 expect(tchar[1]).eql('¥');
653 expect(tchar[1].length).eql(1);
654 expect(tchar[2]).eql(2);
655 }
656 }
657 tchar = xterm.lines[0][xterm.cols-1];
658 expect(tchar[1]).eql(' ');
659 expect(tchar[1].length).eql(1);
660 expect(tchar[2]).eql(1);
661 tchar = xterm.lines[1][0];
662 expect(tchar[1]).eql('¥');
663 expect(tchar[1].length).eql(1);
664 expect(tchar[2]).eql(2);
665 });
666 it('line of ¥ with combining odd', function() {
667 xterm.wraparoundMode = true;
668 xterm.x = 1;
669 xterm.write(Array(50).join('¥\u0301'));
670 for (var i=1; i<xterm.cols-1; ++i) {
671 var tchar = xterm.lines[0][i];
672 if (!(i % 2)) {
673 expect(tchar[1]).eql('');
674 expect(tchar[1].length).eql(0);
675 expect(tchar[2]).eql(0);
676 } else {
677 expect(tchar[1]).eql('¥\u0301');
678 expect(tchar[1].length).eql(2);
679 expect(tchar[2]).eql(2);
680 }
681 }
682 tchar = xterm.lines[0][xterm.cols-1];
683 expect(tchar[1]).eql(' ');
684 expect(tchar[1].length).eql(1);
685 expect(tchar[2]).eql(1);
686 tchar = xterm.lines[1][0];
687 expect(tchar[1]).eql('¥\u0301');
688 expect(tchar[1].length).eql(2);
689 expect(tchar[2]).eql(2);
690 });
691 it('line of ¥ with combining even', function() {
692 xterm.wraparoundMode = true;
693 xterm.write(Array(50).join('¥\u0301'));
694 for (var i=0; i<xterm.cols; ++i) {
695 var tchar = xterm.lines[0][i];
696 if (i % 2) {
697 expect(tchar[1]).eql('');
698 expect(tchar[1].length).eql(0);
699 expect(tchar[2]).eql(0);
700 } else {
701 expect(tchar[1]).eql('¥\u0301');
702 expect(tchar[1].length).eql(2);
703 expect(tchar[2]).eql(2);
704 }
705 }
706 tchar = xterm.lines[1][0];
707 expect(tchar[1]).eql('¥\u0301');
708 expect(tchar[1].length).eql(2);
709 expect(tchar[2]).eql(2);
710 });
711 it('line of surrogate fullwidth with combining odd', function() {
712 xterm.wraparoundMode = true;
713 xterm.x = 1;
714 xterm.write(Array(50).join('\ud843\ude6d\u0301'));
715 for (var i=1; i<xterm.cols-1; ++i) {
716 var tchar = xterm.lines[0][i];
717 if (!(i % 2)) {
718 expect(tchar[1]).eql('');
719 expect(tchar[1].length).eql(0);
720 expect(tchar[2]).eql(0);
721 } else {
722 expect(tchar[1]).eql('\ud843\ude6d\u0301');
723 expect(tchar[1].length).eql(3);
724 expect(tchar[2]).eql(2);
725 }
726 }
727 tchar = xterm.lines[0][xterm.cols-1];
728 expect(tchar[1]).eql(' ');
729 expect(tchar[1].length).eql(1);
730 expect(tchar[2]).eql(1);
731 tchar = xterm.lines[1][0];
732 expect(tchar[1]).eql('\ud843\ude6d\u0301');
733 expect(tchar[1].length).eql(3);
734 expect(tchar[2]).eql(2);
735 });
736 it('line of surrogate fullwidth with combining even', function() {
737 xterm.wraparoundMode = true;
738 xterm.write(Array(50).join('\ud843\ude6d\u0301'));
739 for (var i=0; i<xterm.cols; ++i) {
740 var tchar = xterm.lines[0][i];
741 if (i % 2) {
742 expect(tchar[1]).eql('');
743 expect(tchar[1].length).eql(0);
744 expect(tchar[2]).eql(0);
745 } else {
746 expect(tchar[1]).eql('\ud843\ude6d\u0301');
747 expect(tchar[1].length).eql(3);
748 expect(tchar[2]).eql(2);
749 }
750 }
751 tchar = xterm.lines[1][0];
752 expect(tchar[1]).eql('\ud843\ude6d\u0301');
753 expect(tchar[1].length).eql(3);
754 expect(tchar[2]).eql(2);
755 });
756 });
757
758 describe('insert mode', function() {
759 it('halfwidth - all', function () {
760 xterm.write(Array(9).join('0123456789').slice(-80));
761 xterm.x = 10;
762 xterm.y = 0;
763 xterm.insertMode = true;
764 xterm.write('abcde');
765 expect(xterm.lines[0].length).eql(xterm.cols);
766 expect(xterm.lines[0][10][1]).eql('a');
767 expect(xterm.lines[0][14][1]).eql('e');
768 expect(xterm.lines[0][15][1]).eql('0');
769 expect(xterm.lines[0][79][1]).eql('4');
770 });
771 it('fullwidth - insert', function() {
772 xterm.write(Array(9).join('0123456789').slice(-80));
773 xterm.x = 10;
774 xterm.y = 0;
775 xterm.insertMode = true;
776 xterm.write('¥¥¥');
777 expect(xterm.lines[0].length).eql(xterm.cols);
778 expect(xterm.lines[0][10][1]).eql('¥');
779 expect(xterm.lines[0][11][1]).eql('');
780 expect(xterm.lines[0][14][1]).eql('¥');
781 expect(xterm.lines[0][15][1]).eql('');
782 expect(xterm.lines[0][79][1]).eql('3');
783 });
784 it('fullwidth - right border', function() {
785 xterm.write(Array(41).join('¥'));
786 xterm.x = 10;
787 xterm.y = 0;
788 xterm.insertMode = true;
789 xterm.write('a');
790 expect(xterm.lines[0].length).eql(xterm.cols);
791 expect(xterm.lines[0][10][1]).eql('a');
792 expect(xterm.lines[0][11][1]).eql('¥');
793 expect(xterm.lines[0][79][1]).eql(' '); // fullwidth char got replaced
794 xterm.write('b');
795 expect(xterm.lines[0].length).eql(xterm.cols);
796 expect(xterm.lines[0][11][1]).eql('b');
797 expect(xterm.lines[0][12][1]).eql('¥');
798 expect(xterm.lines[0][79][1]).eql(''); // empty cell after fullwidth
799 });
800 });
801 });