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