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