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