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