]> git.proxmox.com Git - mirror_xterm.js.git/blame - src/term.js
more css color work.
[mirror_xterm.js.git] / src / term.js
CommitLineData
8bc844c0 1/**
91273161 2 * term.js - an xterm emulator
6cc8b3cd
CJ
3 * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
4 * https://github.com/chjj/term.js
8bc844c0
CJ
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 * Originally forked from (with the author's permission):
25 * Fabrice Bellard's javascript vt100 for jslinux:
26 * http://bellard.org/jslinux/
27 * Copyright (c) 2011 Fabrice Bellard
28 * The original design remains. The terminal itself
29 * has been extended to include xterm CSI codes, among
30 * other features.
31 */
32
33;(function() {
34
35/**
36 * Terminal Emulation References:
37 * http://vt100.net/
38 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt
39 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
40 * http://invisible-island.net/vttest/
41 * http://www.inwap.com/pdp10/ansicode.txt
42 * http://linux.die.net/man/4/console_codes
43 * http://linux.die.net/man/7/urxvt
44 */
45
46'use strict';
47
48/**
49 * Shared
50 */
51
52var window = this
53 , document = this.document;
54
55/**
56 * EventEmitter
57 */
58
59function EventEmitter() {
60 this._events = this._events || {};
61}
62
63EventEmitter.prototype.addListener = function(type, listener) {
64 this._events[type] = this._events[type] || [];
65 this._events[type].push(listener);
66};
67
68EventEmitter.prototype.on = EventEmitter.prototype.addListener;
69
70EventEmitter.prototype.removeListener = function(type, listener) {
71 if (!this._events[type]) return;
72
73 var obj = this._events[type]
74 , i = obj.length;
75
76 while (i--) {
77 if (obj[i] === listener || obj[i].listener === listener) {
78 obj.splice(i, 1);
79 return;
80 }
81 }
82};
83
84EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
85
86EventEmitter.prototype.removeAllListeners = function(type) {
87 if (this._events[type]) delete this._events[type];
88};
89
90EventEmitter.prototype.once = function(type, listener) {
91 function on() {
92 var args = Array.prototype.slice.call(arguments);
93 this.removeListener(type, on);
94 return listener.apply(this, args);
95 }
96 on.listener = listener;
97 return this.on(type, on);
98};
99
100EventEmitter.prototype.emit = function(type) {
101 if (!this._events[type]) return;
102
103 var args = Array.prototype.slice.call(arguments, 1)
104 , obj = this._events[type]
105 , l = obj.length
106 , i = 0;
107
108 for (; i < l; i++) {
109 obj[i].apply(this, args);
8bc844c0
CJ
110 }
111};
112
113EventEmitter.prototype.listeners = function(type) {
114 return this._events[type] = this._events[type] || [];
115};
116
117/**
118 * States
119 */
120
121var normal = 0
122 , escaped = 1
123 , csi = 2
124 , osc = 3
125 , charset = 4
126 , dcs = 5
127 , ignore = 6;
128
129/**
130 * Terminal
131 */
132
91273161 133function Terminal(options) {
86dad1b0
CJ
134 var self = this;
135
91273161
CJ
136 if (!(this instanceof Terminal)) {
137 return new Terminal(arguments[0], arguments[1], arguments[2]);
138 }
139
8bc844c0
CJ
140 EventEmitter.call(this);
141
2f212c6e 142 if (typeof options === 'number') {
91273161
CJ
143 options = {
144 cols: arguments[0],
145 rows: arguments[1],
146 handler: arguments[2]
147 };
8bc844c0 148 }
91273161 149
86dad1b0
CJ
150 options = options || {};
151
152 each(keys(Terminal.defaults), function(key) {
153 if (options[key] == null) {
844c4d72
CJ
154 options[key] = Terminal.options[key];
155 // Legacy:
86dad1b0
CJ
156 if (Terminal[key] !== Terminal.defaults[key]) {
157 options[key] = Terminal[key];
86dad1b0 158 }
86dad1b0
CJ
159 }
160 self[key] = options[key];
161 });
162
163 if (options.colors.length === 8) {
164 options.colors = options.colors.concat(Terminal._colors.slice(8));
165 } else if (options.colors.length === 16) {
166 options.colors = options.colors.concat(Terminal._colors.slice(16));
167 } else if (options.colors.length === 10) {
168 options.colors = options.colors.slice(0, -2).concat(
169 Terminal._colors.slice(8, -2), options.colors.slice(-2));
170 } else if (options.colors.length === 18) {
171 options.colors = options.colors.concat(
172 Terminal._colors.slice(16, -2), options.colors.slice(-2));
173 }
174 this.colors = options.colors;
175
176 this.options = options;
8bc844c0 177
2f212c6e
CJ
178 // this.context = options.context || window;
179 // this.document = options.document || document;
180 this.parent = options.body || options.parent
cd956bca 181 || (document ? document.getElementsByTagName('body')[0] : null);
8bc844c0 182
86dad1b0
CJ
183 this.cols = options.cols || options.geometry[0];
184 this.rows = options.rows || options.geometry[1];
91273161
CJ
185
186 if (options.handler) {
187 this.on('data', options.handler);
8bc844c0
CJ
188 }
189
190 this.ybase = 0;
191 this.ydisp = 0;
192 this.x = 0;
193 this.y = 0;
194 this.cursorState = 0;
195 this.cursorHidden = false;
86dad1b0 196 this.convertEol;
8bc844c0
CJ
197 this.state = 0;
198 this.queue = '';
199 this.scrollTop = 0;
200 this.scrollBottom = this.rows - 1;
201
202 // modes
203 this.applicationKeypad = false;
204 this.applicationCursor = false;
205 this.originMode = false;
206 this.insertMode = false;
207 this.wraparoundMode = false;
208 this.normal = null;
209
bcecbcd9
CJ
210 // select modes
211 this.prefixMode = false;
212 this.selectMode = false;
213 this.visualMode = false;
214 this.searchMode = false;
215 this.searchDown;
216 this.entry = '';
217 this.entryPrefix = '';
218 this._real;
74848936
CJ
219 this._selected;
220 this._textarea;
bcecbcd9 221
8bc844c0
CJ
222 // charset
223 this.charset = null;
224 this.gcharset = null;
225 this.glevel = 0;
226 this.charsets = [null];
227
228 // mouse properties
229 this.decLocator;
230 this.x10Mouse;
231 this.vt200Mouse;
232 this.vt300Mouse;
233 this.normalMouse;
234 this.mouseEvents;
235 this.sendFocus;
236 this.utfMouse;
237 this.sgrMouse;
238 this.urxvtMouse;
239
240 // misc
241 this.element;
242 this.children;
243 this.refreshStart;
244 this.refreshEnd;
245 this.savedX;
246 this.savedY;
247 this.savedCols;
248
249 // stream
250 this.readable = true;
251 this.writable = true;
252
15f68335 253 this.defAttr = (0 << 18) | (257 << 9) | (256 << 0);
8bc844c0
CJ
254 this.curAttr = this.defAttr;
255
256 this.params = [];
257 this.currentParam = 0;
258 this.prefix = '';
259 this.postfix = '';
260
261 this.lines = [];
262 var i = this.rows;
263 while (i--) {
264 this.lines.push(this.blankLine());
265 }
266
267 this.tabs;
268 this.setupStops();
269}
270
271inherits(Terminal, EventEmitter);
272
273// back_color_erase feature for xterm.
274Terminal.prototype.eraseAttr = function() {
275 // if (this.is('screen')) return this.defAttr;
276 return (this.defAttr & ~0x1ff) | (this.curAttr & 0x1ff);
277};
278
279/**
280 * Colors
281 */
282
283// Colors 0-15
86dad1b0 284Terminal.tangoColors = [
8bc844c0
CJ
285 // dark:
286 '#2e3436',
287 '#cc0000',
288 '#4e9a06',
289 '#c4a000',
290 '#3465a4',
291 '#75507b',
292 '#06989a',
293 '#d3d7cf',
294 // bright:
295 '#555753',
296 '#ef2929',
297 '#8ae234',
298 '#fce94f',
299 '#729fcf',
300 '#ad7fa8',
301 '#34e2e2',
302 '#eeeeec'
303];
304
6cc8b3cd 305Terminal.xtermColors = [
86dad1b0 306 // dark:
6cc8b3cd
CJ
307 '#000000', // black
308 '#cd0000', // red3
309 '#00cd00', // green3
310 '#cdcd00', // yellow3
311 '#0000ee', // blue2
312 '#cd00cd', // magenta3
313 '#00cdcd', // cyan3
314 '#e5e5e5', // gray90
86dad1b0 315 // bright:
6cc8b3cd
CJ
316 '#7f7f7f', // gray50
317 '#ff0000', // red
318 '#00ff00', // green
319 '#ffff00', // yellow
320 '#5c5cff', // rgb:5c/5c/ff
321 '#ff00ff', // magenta
322 '#00ffff', // cyan
323 '#ffffff' // white
324];
325
86dad1b0 326// Colors 0-15 + 16-255
8bc844c0
CJ
327// Much thanks to TooTallNate for writing this.
328Terminal.colors = (function() {
86dad1b0 329 var colors = Terminal.tangoColors.slice()
8bc844c0
CJ
330 , r = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
331 , i;
332
333 // 16-231
334 i = 0;
335 for (; i < 216; i++) {
336 out(r[(i / 36) % 6 | 0], r[(i / 6) % 6 | 0], r[i % 6]);
337 }
338
339 // 232-255 (grey)
340 i = 0;
341 for (; i < 24; i++) {
342 r = 8 + i * 10;
343 out(r, r, r);
344 }
345
346 function out(r, g, b) {
347 colors.push('#' + hex(r) + hex(g) + hex(b));
348 }
349
350 function hex(c) {
351 c = c.toString(16);
352 return c.length < 2 ? '0' + c : c;
353 }
354
355 return colors;
356})();
357
86dad1b0
CJ
358// Default BG/FG
359Terminal.colors[256] = '#000000';
360Terminal.colors[257] = '#f0f0f0';
361
362Terminal._colors = Terminal.colors.slice();
363
a68c8336
CJ
364Terminal.vcolors = (function() {
365 var out = []
366 , colors = Terminal.colors
367 , i = 0
368 , color;
369
86dad1b0 370 for (; i < 256; i++) {
a68c8336
CJ
371 color = parseInt(colors[i].substring(1), 16);
372 out.push([
373 (color >> 16) & 0xff,
374 (color >> 8) & 0xff,
375 color & 0xff
376 ]);
377 }
378
379 return out;
380})();
381
8bc844c0
CJ
382/**
383 * Options
384 */
385
86dad1b0
CJ
386Terminal.defaults = {
387 colors: Terminal.colors,
388 convertEol: false,
389 termName: 'xterm',
390 geometry: [80, 24],
391 cursorBlink: true,
392 visualBell: false,
393 popOnBell: false,
394 scrollback: 1000,
74848936 395 screenKeys: false,
86dad1b0 396 debug: false,
86eeaf83
CJ
397 useStyle: false
398 // programFeatures: false,
399 // focusKeys: false,
86dad1b0
CJ
400};
401
402Terminal.options = {};
403
404each(keys(Terminal.defaults), function(key) {
405 Terminal[key] = Terminal.defaults[key];
406 Terminal.options[key] = Terminal.defaults[key];
407});
8bc844c0
CJ
408
409/**
410 * Focused Terminal
411 */
412
413Terminal.focus = null;
414
415Terminal.prototype.focus = function() {
416 if (Terminal.focus === this) return;
6cc8b3cd 417
8bc844c0 418 if (Terminal.focus) {
6cc8b3cd 419 Terminal.focus.blur();
8bc844c0 420 }
6cc8b3cd 421
8bc844c0
CJ
422 if (this.sendFocus) this.send('\x1b[I');
423 this.showCursor();
6cc8b3cd
CJ
424
425 // try {
426 // this.element.focus();
427 // } catch (e) {
428 // ;
429 // }
430
431 // this.emit('focus');
432
433 Terminal.focus = this;
434};
435
436Terminal.prototype.blur = function() {
437 if (Terminal.focus !== this) return;
438
439 this.cursorState = 0;
440 this.refresh(this.y, this.y);
441 if (this.sendFocus) this.send('\x1b[O');
442
443 // try {
444 // this.element.blur();
445 // } catch (e) {
446 // ;
447 // }
448
449 // this.emit('blur');
450
451 Terminal.focus = null;
8bc844c0
CJ
452};
453
454/**
3b322929 455 * Initialize global behavior
8bc844c0
CJ
456 */
457
3b322929
CJ
458Terminal.prototype.initGlobal = function() {
459 var document = this.document;
6cc8b3cd 460
3b322929 461 Terminal._boundDocs = Terminal._boundDocs || [];
6cc8b3cd
CJ
462 if (~indexOf(Terminal._boundDocs, document)) {
463 return;
464 }
6cc8b3cd 465 Terminal._boundDocs.push(document);
8bc844c0 466
214d3e09
CJ
467 Terminal.bindPaste(document);
468
3b322929
CJ
469 Terminal.bindKeys(document);
470
cc7f4d0d
CJ
471 Terminal.bindCopy(document);
472
cd956bca
CJ
473 if (this.isIpad) {
474 Terminal.fixIpad(document);
475 }
476
86dad1b0 477 if (this.useStyle) {
cd956bca 478 Terminal.insertStyle(document, this.colors[256], this.colors[257]);
3b322929
CJ
479 }
480};
481
214d3e09
CJ
482/**
483 * Bind to paste event
484 */
485
486Terminal.bindPaste = function(document) {
487 // This seems to work well for ctrl-V and middle-click,
488 // even without the contentEditable workaround.
489 var window = document.defaultView;
490 on(window, 'paste', function(ev) {
491 var term = Terminal.focus;
492 if (!term) return;
493 if (ev.clipboardData) {
494 term.send(ev.clipboardData.getData('text/plain'));
495 } else if (term.context.clipboardData) {
496 term.send(term.context.clipboardData.getData('Text'));
497 }
498 // Not necessary. Do it anyway for good measure.
499 term.element.contentEditable = 'inherit';
500 return cancel(ev);
501 });
502};
503
3b322929
CJ
504/**
505 * Global Events for key handling
506 */
507
508Terminal.bindKeys = function(document) {
cd956bca
CJ
509 // We should only need to check `target === body` below,
510 // but we can check everything for good measure.
8bc844c0 511 on(document, 'keydown', function(ev) {
6cc8b3cd
CJ
512 if (!Terminal.focus) return;
513 var target = ev.target || ev.srcElement;
cd956bca 514 if (!target) return;
6cc8b3cd
CJ
515 if (target === Terminal.focus.element
516 || target === Terminal.focus.context
517 || target === Terminal.focus.document
cd956bca
CJ
518 || target === Terminal.focus.body
519 || target === Terminal._textarea
6cc8b3cd
CJ
520 || target === Terminal.focus.parent) {
521 return Terminal.focus.keyDown(ev);
522 }
8bc844c0
CJ
523 }, true);
524
525 on(document, 'keypress', function(ev) {
6cc8b3cd
CJ
526 if (!Terminal.focus) return;
527 var target = ev.target || ev.srcElement;
cd956bca 528 if (!target) return;
6cc8b3cd
CJ
529 if (target === Terminal.focus.element
530 || target === Terminal.focus.context
531 || target === Terminal.focus.document
cd956bca
CJ
532 || target === Terminal.focus.body
533 || target === Terminal._textarea
6cc8b3cd
CJ
534 || target === Terminal.focus.parent) {
535 return Terminal.focus.keyPress(ev);
536 }
8bc844c0 537 }, true);
6cc8b3cd
CJ
538
539 // If we click somewhere other than a
540 // terminal, unfocus the terminal.
541 on(document, 'mousedown', function(ev) {
542 if (!Terminal.focus) return;
543
544 var el = ev.target || ev.srcElement;
f46cb519 545 if (!el) return;
6cc8b3cd
CJ
546
547 do {
548 if (el === Terminal.focus.element) return;
549 } while (el = el.parentNode);
550
551 Terminal.focus.blur();
552 });
8bc844c0
CJ
553};
554
cc7f4d0d
CJ
555/**
556 * Copy Selection w/ Ctrl-C (Select Mode)
557 */
558
559Terminal.bindCopy = function(document) {
560 var window = document.defaultView;
561
562 // if (!('onbeforecopy' in document)) {
563 // // Copies to *only* the clipboard.
564 // on(window, 'copy', function fn(ev) {
565 // var term = Terminal.focus;
566 // if (!term) return;
567 // if (!term._selected) return;
568 // var text = term.grabText(
569 // term._selected.x1, term._selected.x2,
570 // term._selected.y1, term._selected.y2);
571 // term.emit('copy', text);
572 // ev.clipboardData.setData('text/plain', text);
573 // });
574 // return;
575 // }
576
577 // Copies to primary selection *and* clipboard.
578 // NOTE: This may work better on capture phase,
579 // or using the `beforecopy` event.
580 on(window, 'copy', function(ev) {
581 var term = Terminal.focus;
582 if (!term) return;
583 if (!term._selected) return;
9e6cb6b6 584 var textarea = term.getCopyTextarea();
cc7f4d0d
CJ
585 var text = term.grabText(
586 term._selected.x1, term._selected.x2,
587 term._selected.y1, term._selected.y2);
588 term.emit('copy', text);
589 textarea.focus();
590 textarea.textContent = text;
591 textarea.value = text;
592 textarea.setSelectionRange(0, text.length);
593 setTimeout(function() {
594 term.element.focus();
595 term.focus();
596 }, 1);
597 });
598};
599
cd956bca
CJ
600/**
601 * Fix iPad - no idea if this works
602 */
603
604Terminal.fixIpad = function(document) {
605 var textarea = document.createElement('textarea');
606 textarea.style.position = 'absolute';
607 textarea.style.left = '-32000px';
608 textarea.style.top = '-32000px';
5d3f8786
CJ
609 textarea.style.width = '0px';
610 textarea.style.height = '0px';
cd956bca
CJ
611 textarea.style.opacity = '0';
612 textarea.style.backgroundColor = 'transparent';
613 textarea.style.borderStyle = 'none';
614 textarea.style.outlineStyle = 'none';
615
616 document.getElementsByTagName('body')[0].appendChild(textarea);
617
618 Terminal._textarea = textarea;
619
620 setTimeout(function() {
621 textarea.focus();
622 }, 1000);
623};
624
3b322929
CJ
625/**
626 * Insert a default style
627 */
628
cd956bca
CJ
629Terminal.insertStyle = function(document, bg, fg) {
630 var style = document.getElementById('term-style');
3b322929
CJ
631 if (style) return;
632
633 var head = document.getElementsByTagName('head')[0];
634 if (!head) return;
635
636 var style = document.createElement('style');
214d3e09 637 style.id = 'term-style';
3b322929
CJ
638
639 // textContent doesn't work well with IE for <style> elements.
640 style.innerHTML = ''
641 + '.terminal {\n'
642 + ' float: left;\n'
cd956bca 643 + ' border: ' + bg + ' solid 5px;\n'
3b322929
CJ
644 + ' font-family: "DejaVu Sans Mono", "Liberation Mono", monospace;\n'
645 + ' font-size: 11px;\n'
cd956bca
CJ
646 + ' color: ' + fg + ';\n'
647 + ' background: ' + bg + ';\n'
3b322929
CJ
648 + '}\n'
649 + '\n'
650 + '.terminal-cursor {\n'
cd956bca
CJ
651 + ' color: ' + bg + ';\n'
652 + ' background: ' + fg + ';\n'
3b322929
CJ
653 + '}\n';
654
e11208f5
CJ
655 // var out = '';
656 // each(Terminal.colors, function(color, i) {
657 // if (i === 256) {
658 // i = 'default';
659 // out += '\n.term-bg-color-' + i + ' { background-color: ' + color + '; }';
660 // return;
661 // }
662 // if (i === 257) {
663 // i = 'default';
664 // out += '\n.term-fg-color-' + i + ' { color: ' + color + '; }';
665 // return;
666 // }
667 // out += '\n.term-bg-color-' + i + ' { background-color: ' + color + '; }';
668 // out += '\n.term-fg-color-' + i + ' { color: ' + color + '; }';
669 // });
670 // style.innerHTML += out + '\n';
671
3b322929
CJ
672 head.insertBefore(style, head.firstChild);
673};
674
8bc844c0
CJ
675/**
676 * Open Terminal
677 */
678
91273161 679Terminal.prototype.open = function(parent) {
8bc844c0
CJ
680 var self = this
681 , i = 0
682 , div;
683
2f212c6e
CJ
684 this.parent = parent || this.parent;
685
686 if (!this.parent) {
687 throw new Error('Terminal requires a parent element.');
688 }
689
cd956bca 690 // Grab global elements.
2f212c6e
CJ
691 this.context = this.parent.ownerDocument.defaultView;
692 this.document = this.parent.ownerDocument;
cd956bca
CJ
693 this.body = this.document.getElementsByTagName('body')[0];
694
695 // Parse user-agent strings.
696 if (this.context.navigator && this.context.navigator.userAgent) {
697 this.isMac = !!~this.context.navigator.userAgent.indexOf('Mac');
698 this.isIpad = !!~this.context.navigator.userAgent.indexOf('iPad');
699 this.isMSIE = !!~this.context.navigator.userAgent.indexOf('MSIE');
700 }
91273161 701
cd956bca 702 // Create our main terminal element.
91273161 703 this.element = this.document.createElement('div');
8bc844c0 704 this.element.className = 'terminal';
6cc8b3cd
CJ
705 this.element.style.outline = 'none';
706 this.element.setAttribute('tabindex', 0);
cd956bca
CJ
707 this.element.style.backgroundColor = this.colors[256];
708 this.element.style.color = this.colors[257];
6cc8b3cd 709
cd956bca 710 // Create the lines for our terminal.
8bc844c0 711 this.children = [];
8bc844c0 712 for (; i < this.rows; i++) {
91273161 713 div = this.document.createElement('div');
8bc844c0
CJ
714 this.element.appendChild(div);
715 this.children.push(div);
716 }
91273161 717 this.parent.appendChild(this.element);
8bc844c0 718
cd956bca 719 // Draw the screen.
8bc844c0
CJ
720 this.refresh(0, this.rows - 1);
721
cd956bca
CJ
722 // Initialize global actions that
723 // need to be taken on the document.
3b322929 724 this.initGlobal();
91273161 725
cd956bca 726 // Ensure there is a Terminal.focus.
8bc844c0
CJ
727 this.focus();
728
cd956bca 729 // Start blinking the cursor.
8bc844c0
CJ
730 this.startBlink();
731
cd956bca
CJ
732 // Bind to DOM events related
733 // to focus and paste behavior.
6cc8b3cd
CJ
734 on(this.element, 'focus', function() {
735 self.focus();
214d3e09 736 if (self.isIpad) {
cd956bca
CJ
737 Terminal._textarea.focus();
738 }
6cc8b3cd
CJ
739 });
740
cd956bca 741 // This causes slightly funky behavior.
6cc8b3cd
CJ
742 // on(this.element, 'blur', function() {
743 // self.blur();
744 // });
745
8bc844c0
CJ
746 on(this.element, 'mousedown', function() {
747 self.focus();
748 });
749
cd956bca 750 // Clickable paste workaround, using contentEditable.
8bc844c0
CJ
751 // This probably shouldn't work,
752 // ... but it does. Firefox's paste
753 // event seems to only work for textareas?
754 on(this.element, 'mousedown', function(ev) {
755 var button = ev.button != null
756 ? +ev.button
757 : ev.which != null
758 ? ev.which - 1
759 : null;
760
761 // Does IE9 do this?
791127bc 762 if (self.isMSIE) {
8bc844c0
CJ
763 button = button === 1 ? 0 : button === 4 ? 1 : button;
764 }
765
766 if (button !== 2) return;
767
768 self.element.contentEditable = 'true';
769 setTimeout(function() {
770 self.element.contentEditable = 'inherit'; // 'false';
771 }, 1);
772 }, true);
773
cd956bca
CJ
774 // Listen for mouse events and translate
775 // them into terminal mouse protocols.
8bc844c0
CJ
776 this.bindMouse();
777
3b322929
CJ
778 // Figure out whether boldness affects
779 // the character width of monospace fonts.
8bc844c0 780 if (Terminal.brokenBold == null) {
91273161 781 Terminal.brokenBold = isBoldBroken(this.document);
8bc844c0
CJ
782 }
783
f46cb519 784 // this.emit('open');
cd956bca
CJ
785
786 // This can be useful for pasting,
787 // as well as the iPad fix.
788 setTimeout(function() {
789 self.element.focus();
790 }, 100);
8bc844c0
CJ
791};
792
793// XTerm mouse events
794// http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
795// To better understand these
796// the xterm code is very helpful:
797// Relevant files:
798// button.c, charproc.c, misc.c
799// Relevant functions in xterm/button.c:
800// BtnCode, EmitButtonCode, EditorButton, SendMousePosition
801Terminal.prototype.bindMouse = function() {
802 var el = this.element
803 , self = this
804 , pressed = 32;
805
91273161 806 var wheelEvent = 'onmousewheel' in this.context
8bc844c0
CJ
807 ? 'mousewheel'
808 : 'DOMMouseScroll';
809
810 // mouseup, mousedown, mousewheel
811 // left click: ^[[M 3<^[[M#3<
812 // mousewheel up: ^[[M`3>
813 function sendButton(ev) {
814 var button
815 , pos;
816
817 // get the xterm-style button
818 button = getButton(ev);
819
820 // get mouse coordinates
821 pos = getCoords(ev);
822 if (!pos) return;
823
824 sendEvent(button, pos);
825
826 switch (ev.type) {
827 case 'mousedown':
828 pressed = button;
829 break;
830 case 'mouseup':
831 // keep it at the left
832 // button, just in case.
833 pressed = 32;
834 break;
835 case wheelEvent:
836 // nothing. don't
837 // interfere with
838 // `pressed`.
839 break;
840 }
841 }
842
843 // motion example of a left click:
844 // ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
845 function sendMove(ev) {
846 var button = pressed
847 , pos;
848
849 pos = getCoords(ev);
850 if (!pos) return;
851
852 // buttons marked as motions
853 // are incremented by 32
854 button += 32;
855
856 sendEvent(button, pos);
857 }
858
859 // encode button and
860 // position to characters
861 function encode(data, ch) {
862 if (!self.utfMouse) {
863 if (ch === 255) return data.push(0);
864 if (ch > 127) ch = 127;
865 data.push(ch);
866 } else {
867 if (ch === 2047) return data.push(0);
868 if (ch < 127) {
869 data.push(ch);
870 } else {
871 if (ch > 2047) ch = 2047;
872 data.push(0xC0 | (ch >> 6));
873 data.push(0x80 | (ch & 0x3F));
874 }
875 }
876 }
877
878 // send a mouse event:
879 // regular/utf8: ^[[M Cb Cx Cy
880 // urxvt: ^[[ Cb ; Cx ; Cy M
881 // sgr: ^[[ Cb ; Cx ; Cy M/m
882 // vt300: ^[[ 24(1/3/5)~ [ Cx , Cy ] \r
883 // locator: CSI P e ; P b ; P r ; P c ; P p & w
884 function sendEvent(button, pos) {
885 // self.emit('mouse', {
886 // x: pos.x - 32,
887 // y: pos.x - 32,
888 // button: button
889 // });
890
891 if (self.vt300Mouse) {
892 // NOTE: Unstable.
893 // http://www.vt100.net/docs/vt3xx-gp/chapter15.html
894 button &= 3;
895 pos.x -= 32;
896 pos.y -= 32;
897 var data = '\x1b[24';
898 if (button === 0) data += '1';
899 else if (button === 1) data += '3';
900 else if (button === 2) data += '5';
901 else if (button === 3) return;
902 else data += '0';
903 data += '~[' + pos.x + ',' + pos.y + ']\r';
904 self.send(data);
905 return;
906 }
907
908 if (self.decLocator) {
909 // NOTE: Unstable.
910 button &= 3;
911 pos.x -= 32;
912 pos.y -= 32;
913 if (button === 0) button = 2;
914 else if (button === 1) button = 4;
915 else if (button === 2) button = 6;
916 else if (button === 3) button = 3;
917 self.send('\x1b['
918 + button
919 + ';'
920 + (button === 3 ? 4 : 0)
921 + ';'
922 + pos.y
923 + ';'
924 + pos.x
925 + ';'
926 + (pos.page || 0)
927 + '&w');
928 return;
929 }
930
931 if (self.urxvtMouse) {
932 pos.x -= 32;
933 pos.y -= 32;
934 pos.x++;
935 pos.y++;
936 self.send('\x1b[' + button + ';' + pos.x + ';' + pos.y + 'M');
937 return;
938 }
939
940 if (self.sgrMouse) {
941 pos.x -= 32;
942 pos.y -= 32;
943 self.send('\x1b[<'
944 + ((button & 3) === 3 ? button & ~3 : button)
945 + ';'
946 + pos.x
947 + ';'
948 + pos.y
949 + ((button & 3) === 3 ? 'm' : 'M'));
950 return;
951 }
952
953 var data = [];
954
955 encode(data, button);
956 encode(data, pos.x);
957 encode(data, pos.y);
958
959 self.send('\x1b[M' + String.fromCharCode.apply(String, data));
960 }
961
962 function getButton(ev) {
963 var button
964 , shift
965 , meta
966 , ctrl
967 , mod;
968
969 // two low bits:
970 // 0 = left
971 // 1 = middle
972 // 2 = right
973 // 3 = release
974 // wheel up/down:
975 // 1, and 2 - with 64 added
976 switch (ev.type) {
977 case 'mousedown':
978 button = ev.button != null
979 ? +ev.button
980 : ev.which != null
981 ? ev.which - 1
982 : null;
983
791127bc 984 if (self.isMSIE) {
8bc844c0
CJ
985 button = button === 1 ? 0 : button === 4 ? 1 : button;
986 }
987 break;
988 case 'mouseup':
989 button = 3;
990 break;
991 case 'DOMMouseScroll':
992 button = ev.detail < 0
993 ? 64
994 : 65;
995 break;
996 case 'mousewheel':
997 button = ev.wheelDeltaY > 0
998 ? 64
999 : 65;
1000 break;
1001 }
1002
1003 // next three bits are the modifiers:
1004 // 4 = shift, 8 = meta, 16 = control
1005 shift = ev.shiftKey ? 4 : 0;
1006 meta = ev.metaKey ? 8 : 0;
1007 ctrl = ev.ctrlKey ? 16 : 0;
1008 mod = shift | meta | ctrl;
1009
1010 // no mods
1011 if (self.vt200Mouse) {
1012 // ctrl only
1013 mod &= ctrl;
1014 } else if (!self.normalMouse) {
1015 mod = 0;
1016 }
1017
1018 // increment to SP
1019 button = (32 + (mod << 2)) + button;
1020
1021 return button;
1022 }
1023
1024 // mouse coordinates measured in cols/rows
1025 function getCoords(ev) {
1026 var x, y, w, h, el;
1027
1028 // ignore browsers without pageX for now
1029 if (ev.pageX == null) return;
1030
1031 x = ev.pageX;
1032 y = ev.pageY;
1033 el = self.element;
1034
1035 // should probably check offsetParent
1036 // but this is more portable
49d3a20f 1037 while (el && el !== self.document.documentElement) {
8bc844c0
CJ
1038 x -= el.offsetLeft;
1039 y -= el.offsetTop;
49d3a20f
CJ
1040 el = 'offsetParent' in el
1041 ? el.offsetParent
1042 : el.parentNode;
8bc844c0
CJ
1043 }
1044
1045 // convert to cols/rows
1046 w = self.element.clientWidth;
1047 h = self.element.clientHeight;
49d3a20f
CJ
1048 x = Math.round((x / w) * self.cols);
1049 y = Math.round((y / h) * self.rows);
8bc844c0
CJ
1050
1051 // be sure to avoid sending
1052 // bad positions to the program
1053 if (x < 0) x = 0;
628af053 1054 if (x > self.cols) x = self.cols;
8bc844c0 1055 if (y < 0) y = 0;
628af053 1056 if (y > self.rows) y = self.rows;
8bc844c0
CJ
1057
1058 // xterm sends raw bytes and
1059 // starts at 32 (SP) for each.
1060 x += 32;
1061 y += 32;
1062
1063 return {
1064 x: x,
1065 y: y,
49d3a20f
CJ
1066 type: ev.type === wheelEvent
1067 ? 'mousewheel'
1068 : ev.type
8bc844c0
CJ
1069 };
1070 }
1071
1072 on(el, 'mousedown', function(ev) {
1073 if (!self.mouseEvents) return;
1074
1075 // send the button
1076 sendButton(ev);
1077
1078 // ensure focus
1079 self.focus();
1080
1081 // fix for odd bug
49d3a20f 1082 //if (self.vt200Mouse && !self.normalMouse) {
8bc844c0
CJ
1083 if (self.vt200Mouse) {
1084 sendButton({ __proto__: ev, type: 'mouseup' });
1085 return cancel(ev);
1086 }
1087
1088 // bind events
91273161 1089 if (self.normalMouse) on(self.document, 'mousemove', sendMove);
8bc844c0
CJ
1090
1091 // x10 compatibility mode can't send button releases
1092 if (!self.x10Mouse) {
91273161 1093 on(self.document, 'mouseup', function up(ev) {
8bc844c0 1094 sendButton(ev);
91273161
CJ
1095 if (self.normalMouse) off(self.document, 'mousemove', sendMove);
1096 off(self.document, 'mouseup', up);
8bc844c0
CJ
1097 return cancel(ev);
1098 });
1099 }
1100
1101 return cancel(ev);
1102 });
1103
49d3a20f
CJ
1104 //if (self.normalMouse) {
1105 // on(self.document, 'mousemove', sendMove);
1106 //}
1107
8bc844c0
CJ
1108 on(el, wheelEvent, function(ev) {
1109 if (!self.mouseEvents) return;
1110 if (self.x10Mouse
1111 || self.vt300Mouse
1112 || self.decLocator) return;
1113 sendButton(ev);
1114 return cancel(ev);
1115 });
1116
1117 // allow mousewheel scrolling in
1118 // the shell for example
1119 on(el, wheelEvent, function(ev) {
1120 if (self.mouseEvents) return;
1121 if (self.applicationKeypad) return;
1122 if (ev.type === 'DOMMouseScroll') {
1123 self.scrollDisp(ev.detail < 0 ? -5 : 5);
1124 } else {
1125 self.scrollDisp(ev.wheelDeltaY > 0 ? -5 : 5);
1126 }
1127 return cancel(ev);
1128 });
1129};
1130
1131/**
1132 * Destroy Terminal
1133 */
1134
1135Terminal.prototype.destroy = function() {
1136 this.readable = false;
1137 this.writable = false;
1138 this._events = {};
1139 this.handler = function() {};
1140 this.write = function() {};
628af053
CJ
1141 if (this.element.parentNode) {
1142 this.element.parentNode.removeChild(this.element);
1143 }
8bc844c0
CJ
1144 //this.emit('close');
1145};
1146
1147/**
1148 * Rendering Engine
1149 */
1150
1151// In the screen buffer, each character
1152// is stored as a an array with a character
1153// and a 32-bit integer.
1154// First value: a utf-16 character.
1155// Second value:
1156// Next 9 bits: background color (0-511).
1157// Next 9 bits: foreground color (0-511).
1158// Next 14 bits: a mask for misc. flags:
2eb1a7bd 1159// 1=bold, 2=underline, 4=blink, 8=inverse, 16=invisible
8bc844c0
CJ
1160
1161Terminal.prototype.refresh = function(start, end) {
1162 var x
1163 , y
1164 , i
1165 , line
1166 , out
1167 , ch
1168 , width
1169 , data
1170 , attr
0152104b
CJ
1171 , bg
1172 , fg
8bc844c0
CJ
1173 , flags
1174 , row
1175 , parent;
1176
1177 if (end - start >= this.rows / 2) {
1178 parent = this.element.parentNode;
1179 if (parent) parent.removeChild(this.element);
1180 }
1181
1182 width = this.cols;
1183 y = start;
1184
628af053
CJ
1185 if (end >= this.lines.length) {
1186 this.log('`end` is too large. Most likely a bad CSR.');
1187 end = this.lines.length - 1;
1188 }
8bc844c0
CJ
1189
1190 for (; y <= end; y++) {
1191 row = y + this.ydisp;
1192
1193 line = this.lines[row];
1194 out = '';
1195
1196 if (y === this.y
1197 && this.cursorState
0d60718f 1198 && (this.ydisp === this.ybase || this.selectMode)
8bc844c0
CJ
1199 && !this.cursorHidden) {
1200 x = this.x;
1201 } else {
1202 x = -1;
1203 }
1204
1205 attr = this.defAttr;
1206 i = 0;
1207
1208 for (; i < width; i++) {
1209 data = line[i][0];
1210 ch = line[i][1];
1211
1212 if (i === x) data = -1;
1213
1214 if (data !== attr) {
1215 if (attr !== this.defAttr) {
1216 out += '</span>';
1217 }
1218 if (data !== this.defAttr) {
1219 if (data === -1) {
628af053 1220 out += '<span class="reverse-video terminal-cursor">';
8bc844c0
CJ
1221 } else {
1222 out += '<span style="';
1223
0152104b
CJ
1224 bg = data & 0x1ff;
1225 fg = (data >> 9) & 0x1ff;
8bc844c0
CJ
1226 flags = data >> 18;
1227
15f68335 1228 // bold
8bc844c0
CJ
1229 if (flags & 1) {
1230 if (!Terminal.brokenBold) {
1231 out += 'font-weight:bold;';
1232 }
628af053 1233 // See: XTerm*boldColors
0152104b 1234 if (fg < 8) fg += 8;
8bc844c0
CJ
1235 }
1236
15f68335 1237 // underline
8bc844c0
CJ
1238 if (flags & 2) {
1239 out += 'text-decoration:underline;';
1240 }
1241
15f68335
CJ
1242 // blink
1243 if (flags & 4) {
1244 if (flags & 2) {
1245 out = out.slice(0, -1);
1246 out += ' blink;';
1247 } else {
1248 out += 'text-decoration:blink;';
1249 }
1250 }
1251
1252 // inverse
1253 if (flags & 8) {
0152104b
CJ
1254 bg = (data >> 9) & 0x1ff;
1255 fg = data & 0x1ff;
15f68335
CJ
1256 // Should inverse just be before the
1257 // above boldColors effect instead?
0152104b 1258 if ((flags & 1) && fg < 8) fg += 8;
15f68335
CJ
1259 }
1260
1261 // invisible
1262 if (flags & 16) {
1263 out += 'visibility:hidden;';
1264 }
1265
e11208f5
CJ
1266 // out += '" class="'
1267 // + 'term-bg-color-' + (bg === 256 ? 'default' : bg)
1268 // + ' '
1269 // + 'term-fg-color-' + (fg === 257 ? 'default' : fg)
1270 // + '">';
1271
0152104b 1272 if (bg !== 256) {
8bc844c0 1273 out += 'background-color:'
0152104b 1274 + this.colors[bg]
8bc844c0
CJ
1275 + ';';
1276 }
1277
0152104b 1278 if (fg !== 257) {
8bc844c0 1279 out += 'color:'
0152104b 1280 + this.colors[fg]
8bc844c0
CJ
1281 + ';';
1282 }
1283
1284 out += '">';
1285 }
1286 }
1287 }
1288
1289 switch (ch) {
1290 case '&':
1291 out += '&amp;';
1292 break;
1293 case '<':
1294 out += '&lt;';
1295 break;
1296 case '>':
1297 out += '&gt;';
1298 break;
1299 default:
1300 if (ch <= ' ') {
1301 out += '&nbsp;';
1302 } else {
a7f50531 1303 if (isWide(ch)) i++;
8bc844c0
CJ
1304 out += ch;
1305 }
1306 break;
1307 }
1308
1309 attr = data;
1310 }
1311
1312 if (attr !== this.defAttr) {
1313 out += '</span>';
1314 }
1315
1316 this.children[y].innerHTML = out;
1317 }
1318
1319 if (parent) parent.appendChild(this.element);
1320};
1321
86dad1b0 1322Terminal.prototype._cursorBlink = function() {
8bc844c0
CJ
1323 if (Terminal.focus !== this) return;
1324 this.cursorState ^= 1;
1325 this.refresh(this.y, this.y);
1326};
1327
1328Terminal.prototype.showCursor = function() {
1329 if (!this.cursorState) {
1330 this.cursorState = 1;
1331 this.refresh(this.y, this.y);
1332 } else {
1333 // Temporarily disabled:
1334 // this.refreshBlink();
1335 }
1336};
1337
1338Terminal.prototype.startBlink = function() {
86dad1b0 1339 if (!this.cursorBlink) return;
8bc844c0
CJ
1340 var self = this;
1341 this._blinker = function() {
86dad1b0 1342 self._cursorBlink();
8bc844c0
CJ
1343 };
1344 this._blink = setInterval(this._blinker, 500);
1345};
1346
1347Terminal.prototype.refreshBlink = function() {
86dad1b0 1348 if (!this.cursorBlink) return;
8bc844c0
CJ
1349 clearInterval(this._blink);
1350 this._blink = setInterval(this._blinker, 500);
1351};
1352
1353Terminal.prototype.scroll = function() {
1354 var row;
1355
86dad1b0 1356 if (++this.ybase === this.scrollback) {
8bc844c0
CJ
1357 this.ybase = this.ybase / 2 | 0;
1358 this.lines = this.lines.slice(-(this.ybase + this.rows) + 1);
1359 }
1360
1361 this.ydisp = this.ybase;
1362
1363 // last line
1364 row = this.ybase + this.rows - 1;
1365
1366 // subtract the bottom scroll region
1367 row -= this.rows - 1 - this.scrollBottom;
1368
1369 if (row === this.lines.length) {
1370 // potential optimization:
1371 // pushing is faster than splicing
1372 // when they amount to the same
1373 // behavior.
1374 this.lines.push(this.blankLine());
1375 } else {
1376 // add our new line
1377 this.lines.splice(row, 0, this.blankLine());
1378 }
1379
1380 if (this.scrollTop !== 0) {
1381 if (this.ybase !== 0) {
1382 this.ybase--;
1383 this.ydisp = this.ybase;
1384 }
1385 this.lines.splice(this.ybase + this.scrollTop, 1);
1386 }
1387
1388 // this.maxRange();
1389 this.updateRange(this.scrollTop);
1390 this.updateRange(this.scrollBottom);
1391};
1392
1393Terminal.prototype.scrollDisp = function(disp) {
1394 this.ydisp += disp;
1395
1396 if (this.ydisp > this.ybase) {
1397 this.ydisp = this.ybase;
1398 } else if (this.ydisp < 0) {
1399 this.ydisp = 0;
1400 }
1401
1402 this.refresh(0, this.rows - 1);
1403};
1404
1405Terminal.prototype.write = function(data) {
1406 var l = data.length
1407 , i = 0
b5839cad 1408 , j
8bc844c0
CJ
1409 , cs
1410 , ch;
1411
1412 this.refreshStart = this.y;
1413 this.refreshEnd = this.y;
1414
1415 if (this.ybase !== this.ydisp) {
1416 this.ydisp = this.ybase;
1417 this.maxRange();
1418 }
1419
1420 // this.log(JSON.stringify(data.replace(/\x1b/g, '^[')));
1421
1422 for (; i < l; i++) {
1423 ch = data[i];
1424 switch (this.state) {
1425 case normal:
1426 switch (ch) {
1427 // '\0'
1428 // case '\0':
1429 // case '\200':
1430 // break;
1431
1432 // '\a'
1433 case '\x07':
1434 this.bell();
1435 break;
1436
1437 // '\n', '\v', '\f'
1438 case '\n':
1439 case '\x0b':
1440 case '\x0c':
1441 if (this.convertEol) {
1442 this.x = 0;
1443 }
1444 // TODO: Implement eat_newline_glitch.
86922c7c 1445 // if (this.realX >= this.cols) break;
8bc844c0
CJ
1446 // this.realX = 0;
1447 this.y++;
1448 if (this.y > this.scrollBottom) {
1449 this.y--;
1450 this.scroll();
1451 }
1452 break;
1453
1454 // '\r'
1455 case '\r':
1456 this.x = 0;
1457 break;
1458
1459 // '\b'
1460 case '\x08':
1461 if (this.x > 0) {
1462 this.x--;
1463 }
1464 break;
1465
1466 // '\t'
1467 case '\t':
1468 this.x = this.nextStop();
1469 break;
1470
1471 // shift out
1472 case '\x0e':
1473 this.setgLevel(1);
1474 break;
1475
1476 // shift in
1477 case '\x0f':
1478 this.setgLevel(0);
1479 break;
1480
1481 // '\e'
1482 case '\x1b':
1483 this.state = escaped;
1484 break;
1485
1486 default:
1487 // ' '
1488 if (ch >= ' ') {
1489 if (this.charset && this.charset[ch]) {
1490 ch = this.charset[ch];
1491 }
a7f50531 1492
8bc844c0
CJ
1493 if (this.x >= this.cols) {
1494 this.x = 0;
1495 this.y++;
1496 if (this.y > this.scrollBottom) {
1497 this.y--;
1498 this.scroll();
1499 }
1500 }
a7f50531 1501
8bc844c0
CJ
1502 this.lines[this.y + this.ybase][this.x] = [this.curAttr, ch];
1503 this.x++;
1504 this.updateRange(this.y);
efa0e3c1 1505
a7f50531 1506 if (isWide(ch)) {
b5839cad 1507 j = this.y + this.ybase;
a7f50531 1508 if (this.cols < 2 || this.x >= this.cols) {
b5839cad
CJ
1509 this.lines[j][this.x - 1] = [this.curAttr, ' '];
1510 break;
1511 }
a7f50531 1512 this.lines[j][this.x] = [this.curAttr, ' '];
b5839cad 1513 this.x++;
b5839cad 1514 }
8bc844c0
CJ
1515 }
1516 break;
1517 }
1518 break;
1519 case escaped:
1520 switch (ch) {
1521 // ESC [ Control Sequence Introducer ( CSI is 0x9b).
1522 case '[':
1523 this.params = [];
1524 this.currentParam = 0;
1525 this.state = csi;
1526 break;
1527
1528 // ESC ] Operating System Command ( OSC is 0x9d).
1529 case ']':
1530 this.params = [];
1531 this.currentParam = 0;
1532 this.state = osc;
1533 break;
1534
1535 // ESC P Device Control String ( DCS is 0x90).
1536 case 'P':
1537 this.params = [];
1538 this.currentParam = 0;
1539 this.state = dcs;
1540 break;
1541
1542 // ESC _ Application Program Command ( APC is 0x9f).
1543 case '_':
1544 this.state = ignore;
1545 break;
1546
1547 // ESC ^ Privacy Message ( PM is 0x9e).
1548 case '^':
1549 this.state = ignore;
1550 break;
1551
1552 // ESC c Full Reset (RIS).
1553 case 'c':
1554 this.reset();
1555 break;
1556
1557 // ESC E Next Line ( NEL is 0x85).
1558 // ESC D Index ( IND is 0x84).
1559 case 'E':
1560 this.x = 0;
1561 ;
1562 case 'D':
1563 this.index();
1564 break;
1565
1566 // ESC M Reverse Index ( RI is 0x8d).
1567 case 'M':
1568 this.reverseIndex();
1569 break;
1570
1571 // ESC % Select default/utf-8 character set.
1572 // @ = default, G = utf-8
1573 case '%':
1574 //this.charset = null;
1575 this.setgLevel(0);
1576 this.setgCharset(0, Terminal.charsets.US);
1577 this.state = normal;
1578 i++;
1579 break;
1580
1581 // ESC (,),*,+,-,. Designate G0-G2 Character Set.
1582 case '(': // <-- this seems to get all the attention
1583 case ')':
1584 case '*':
1585 case '+':
1586 case '-':
1587 case '.':
1588 switch (ch) {
1589 case '(':
1590 this.gcharset = 0;
1591 break;
1592 case ')':
1593 this.gcharset = 1;
1594 break;
1595 case '*':
1596 this.gcharset = 2;
1597 break;
1598 case '+':
1599 this.gcharset = 3;
1600 break;
1601 case '-':
1602 this.gcharset = 1;
1603 break;
1604 case '.':
1605 this.gcharset = 2;
1606 break;
1607 }
1608 this.state = charset;
1609 break;
1610
1611 // Designate G3 Character Set (VT300).
1612 // A = ISO Latin-1 Supplemental.
1613 // Not implemented.
1614 case '/':
1615 this.gcharset = 3;
1616 this.state = charset;
1617 i--;
1618 break;
1619
1620 // ESC N
1621 // Single Shift Select of G2 Character Set
1622 // ( SS2 is 0x8e). This affects next character only.
1623 case 'N':
1624 break;
1625 // ESC O
1626 // Single Shift Select of G3 Character Set
1627 // ( SS3 is 0x8f). This affects next character only.
1628 case 'O':
1629 break;
1630 // ESC n
1631 // Invoke the G2 Character Set as GL (LS2).
1632 case 'n':
1633 this.setgLevel(2);
1634 break;
1635 // ESC o
1636 // Invoke the G3 Character Set as GL (LS3).
1637 case 'o':
1638 this.setgLevel(3);
1639 break;
1640 // ESC |
1641 // Invoke the G3 Character Set as GR (LS3R).
1642 case '|':
1643 this.setgLevel(3);
1644 break;
1645 // ESC }
1646 // Invoke the G2 Character Set as GR (LS2R).
1647 case '}':
1648 this.setgLevel(2);
1649 break;
1650 // ESC ~
1651 // Invoke the G1 Character Set as GR (LS1R).
1652 case '~':
1653 this.setgLevel(1);
1654 break;
1655
1656 // ESC 7 Save Cursor (DECSC).
1657 case '7':
1658 this.saveCursor();
1659 this.state = normal;
1660 break;
1661
1662 // ESC 8 Restore Cursor (DECRC).
1663 case '8':
1664 this.restoreCursor();
1665 this.state = normal;
1666 break;
1667
1668 // ESC # 3 DEC line height/width
1669 case '#':
1670 this.state = normal;
1671 i++;
1672 break;
1673
1674 // ESC H Tab Set (HTS is 0x88).
1675 case 'H':
1676 this.tabSet();
1677 break;
1678
1679 // ESC = Application Keypad (DECPAM).
1680 case '=':
1681 this.log('Serial port requested application keypad.');
1682 this.applicationKeypad = true;
1683 this.state = normal;
1684 break;
1685
1686 // ESC > Normal Keypad (DECPNM).
1687 case '>':
1688 this.log('Switching back to normal keypad.');
1689 this.applicationKeypad = false;
1690 this.state = normal;
1691 break;
1692
1693 default:
1694 this.state = normal;
1695 this.error('Unknown ESC control: %s.', ch);
1696 break;
1697 }
1698 break;
1699
1700 case charset:
1701 switch (ch) {
1702 case '0': // DEC Special Character and Line Drawing Set.
1703 cs = Terminal.charsets.SCLD;
1704 break;
1705 case 'A': // UK
1706 cs = Terminal.charsets.UK;
1707 break;
1708 case 'B': // United States (USASCII).
1709 cs = Terminal.charsets.US;
1710 break;
1711 case '4': // Dutch
1712 cs = Terminal.charsets.Dutch;
1713 break;
1714 case 'C': // Finnish
1715 case '5':
1716 cs = Terminal.charsets.Finnish;
1717 break;
1718 case 'R': // French
1719 cs = Terminal.charsets.French;
1720 break;
1721 case 'Q': // FrenchCanadian
1722 cs = Terminal.charsets.FrenchCanadian;
1723 break;
1724 case 'K': // German
1725 cs = Terminal.charsets.German;
1726 break;
1727 case 'Y': // Italian
1728 cs = Terminal.charsets.Italian;
1729 break;
1730 case 'E': // NorwegianDanish
1731 case '6':
1732 cs = Terminal.charsets.NorwegianDanish;
1733 break;
1734 case 'Z': // Spanish
1735 cs = Terminal.charsets.Spanish;
1736 break;
1737 case 'H': // Swedish
1738 case '7':
1739 cs = Terminal.charsets.Swedish;
1740 break;
1741 case '=': // Swiss
1742 cs = Terminal.charsets.Swiss;
1743 break;
1744 case '/': // ISOLatin (actually /A)
1745 cs = Terminal.charsets.ISOLatin;
1746 i++;
1747 break;
1748 default: // Default
1749 cs = Terminal.charsets.US;
1750 break;
1751 }
1752 this.setgCharset(this.gcharset, cs);
1753 this.gcharset = null;
1754 this.state = normal;
1755 break;
1756
1757 case osc:
1758 // OSC Ps ; Pt ST
1759 // OSC Ps ; Pt BEL
1760 // Set Text Parameters.
1761 if (ch === '\x1b' || ch === '\x07') {
1762 if (ch === '\x1b') i++;
1763
1764 this.params.push(this.currentParam);
1765
1766 switch (this.params[0]) {
1767 case 0:
1768 case 1:
1769 case 2:
1770 if (this.params[1]) {
1771 this.title = this.params[1];
1772 this.handleTitle(this.title);
1773 }
1774 break;
1775 case 3:
1776 // set X property
1777 break;
1778 case 4:
1779 case 5:
1780 // change dynamic colors
1781 break;
1782 case 10:
1783 case 11:
1784 case 12:
1785 case 13:
1786 case 14:
1787 case 15:
1788 case 16:
1789 case 17:
1790 case 18:
1791 case 19:
1792 // change dynamic ui colors
1793 break;
1794 case 46:
1795 // change log file
1796 break;
1797 case 50:
1798 // dynamic font
1799 break;
1800 case 51:
1801 // emacs shell
1802 break;
1803 case 52:
1804 // manipulate selection data
1805 break;
1806 case 104:
1807 case 105:
1808 case 110:
1809 case 111:
1810 case 112:
1811 case 113:
1812 case 114:
1813 case 115:
1814 case 116:
1815 case 117:
1816 case 118:
1817 // reset colors
1818 break;
1819 }
1820
1821 this.params = [];
1822 this.currentParam = 0;
1823 this.state = normal;
1824 } else {
1825 if (!this.params.length) {
1826 if (ch >= '0' && ch <= '9') {
1827 this.currentParam =
1828 this.currentParam * 10 + ch.charCodeAt(0) - 48;
1829 } else if (ch === ';') {
1830 this.params.push(this.currentParam);
1831 this.currentParam = '';
1832 }
1833 } else {
1834 this.currentParam += ch;
1835 }
1836 }
1837 break;
1838
1839 case csi:
1840 // '?', '>', '!'
1841 if (ch === '?' || ch === '>' || ch === '!') {
1842 this.prefix = ch;
1843 break;
1844 }
1845
1846 // 0 - 9
1847 if (ch >= '0' && ch <= '9') {
1848 this.currentParam = this.currentParam * 10 + ch.charCodeAt(0) - 48;
1849 break;
1850 }
1851
1852 // '$', '"', ' ', '\''
1853 if (ch === '$' || ch === '"' || ch === ' ' || ch === '\'') {
1854 this.postfix = ch;
1855 break;
1856 }
1857
1858 this.params.push(this.currentParam);
1859 this.currentParam = 0;
1860
1861 // ';'
1862 if (ch === ';') break;
1863
1864 this.state = normal;
1865
1866 switch (ch) {
1867 // CSI Ps A
1868 // Cursor Up Ps Times (default = 1) (CUU).
1869 case 'A':
1870 this.cursorUp(this.params);
1871 break;
1872
1873 // CSI Ps B
1874 // Cursor Down Ps Times (default = 1) (CUD).
1875 case 'B':
1876 this.cursorDown(this.params);
1877 break;
1878
1879 // CSI Ps C
1880 // Cursor Forward Ps Times (default = 1) (CUF).
1881 case 'C':
1882 this.cursorForward(this.params);
1883 break;
1884
1885 // CSI Ps D
1886 // Cursor Backward Ps Times (default = 1) (CUB).
1887 case 'D':
1888 this.cursorBackward(this.params);
1889 break;
1890
1891 // CSI Ps ; Ps H
1892 // Cursor Position [row;column] (default = [1,1]) (CUP).
1893 case 'H':
1894 this.cursorPos(this.params);
1895 break;
1896
1897 // CSI Ps J Erase in Display (ED).
1898 case 'J':
1899 this.eraseInDisplay(this.params);
1900 break;
1901
1902 // CSI Ps K Erase in Line (EL).
1903 case 'K':
1904 this.eraseInLine(this.params);
1905 break;
1906
1907 // CSI Pm m Character Attributes (SGR).
1908 case 'm':
1909 this.charAttributes(this.params);
1910 break;
1911
1912 // CSI Ps n Device Status Report (DSR).
1913 case 'n':
1914 this.deviceStatus(this.params);
1915 break;
1916
1917 /**
1918 * Additions
1919 */
1920
1921 // CSI Ps @
1922 // Insert Ps (Blank) Character(s) (default = 1) (ICH).
1923 case '@':
1924 this.insertChars(this.params);
1925 break;
1926
1927 // CSI Ps E
1928 // Cursor Next Line Ps Times (default = 1) (CNL).
1929 case 'E':
1930 this.cursorNextLine(this.params);
1931 break;
1932
1933 // CSI Ps F
1934 // Cursor Preceding Line Ps Times (default = 1) (CNL).
1935 case 'F':
1936 this.cursorPrecedingLine(this.params);
1937 break;
1938
1939 // CSI Ps G
1940 // Cursor Character Absolute [column] (default = [row,1]) (CHA).
1941 case 'G':
1942 this.cursorCharAbsolute(this.params);
1943 break;
1944
1945 // CSI Ps L
1946 // Insert Ps Line(s) (default = 1) (IL).
1947 case 'L':
1948 this.insertLines(this.params);
1949 break;
1950
1951 // CSI Ps M
1952 // Delete Ps Line(s) (default = 1) (DL).
1953 case 'M':
1954 this.deleteLines(this.params);
1955 break;
1956
1957 // CSI Ps P
1958 // Delete Ps Character(s) (default = 1) (DCH).
1959 case 'P':
1960 this.deleteChars(this.params);
1961 break;
1962
1963 // CSI Ps X
1964 // Erase Ps Character(s) (default = 1) (ECH).
1965 case 'X':
1966 this.eraseChars(this.params);
1967 break;
1968
1969 // CSI Pm ` Character Position Absolute
1970 // [column] (default = [row,1]) (HPA).
1971 case '`':
1972 this.charPosAbsolute(this.params);
1973 break;
1974
1975 // 141 61 a * HPR -
1976 // Horizontal Position Relative
1977 case 'a':
1978 this.HPositionRelative(this.params);
1979 break;
1980
1981 // CSI P s c
1982 // Send Device Attributes (Primary DA).
1983 // CSI > P s c
1984 // Send Device Attributes (Secondary DA)
1985 case 'c':
1986 this.sendDeviceAttributes(this.params);
1987 break;
1988
1989 // CSI Pm d
1990 // Line Position Absolute [row] (default = [1,column]) (VPA).
1991 case 'd':
1992 this.linePosAbsolute(this.params);
1993 break;
1994
1995 // 145 65 e * VPR - Vertical Position Relative
1996 case 'e':
1997 this.VPositionRelative(this.params);
1998 break;
1999
2000 // CSI Ps ; Ps f
2001 // Horizontal and Vertical Position [row;column] (default =
2002 // [1,1]) (HVP).
2003 case 'f':
2004 this.HVPosition(this.params);
2005 break;
2006
2007 // CSI Pm h Set Mode (SM).
2008 // CSI ? Pm h - mouse escape codes, cursor escape codes
2009 case 'h':
2010 this.setMode(this.params);
2011 break;
2012
2013 // CSI Pm l Reset Mode (RM).
2014 // CSI ? Pm l
2015 case 'l':
2016 this.resetMode(this.params);
2017 break;
2018
2019 // CSI Ps ; Ps r
2020 // Set Scrolling Region [top;bottom] (default = full size of win-
2021 // dow) (DECSTBM).
2022 // CSI ? Pm r
2023 case 'r':
2024 this.setScrollRegion(this.params);
2025 break;
2026
2027 // CSI s
2028 // Save cursor (ANSI.SYS).
2029 case 's':
2030 this.saveCursor(this.params);
2031 break;
2032
2033 // CSI u
2034 // Restore cursor (ANSI.SYS).
2035 case 'u':
2036 this.restoreCursor(this.params);
2037 break;
2038
2039 /**
2040 * Lesser Used
2041 */
2042
2043 // CSI Ps I
2044 // Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
2045 case 'I':
2046 this.cursorForwardTab(this.params);
2047 break;
2048
2049 // CSI Ps S Scroll up Ps lines (default = 1) (SU).
2050 case 'S':
2051 this.scrollUp(this.params);
2052 break;
2053
2054 // CSI Ps T Scroll down Ps lines (default = 1) (SD).
2055 // CSI Ps ; Ps ; Ps ; Ps ; Ps T
2056 // CSI > Ps; Ps T
2057 case 'T':
2058 // if (this.prefix === '>') {
2059 // this.resetTitleModes(this.params);
2060 // break;
2061 // }
2062 // if (this.params.length > 2) {
2063 // this.initMouseTracking(this.params);
2064 // break;
2065 // }
2066 if (this.params.length < 2 && !this.prefix) {
2067 this.scrollDown(this.params);
2068 }
2069 break;
2070
2071 // CSI Ps Z
2072 // Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
2073 case 'Z':
2074 this.cursorBackwardTab(this.params);
2075 break;
2076
2077 // CSI Ps b Repeat the preceding graphic character Ps times (REP).
2078 case 'b':
2079 this.repeatPrecedingCharacter(this.params);
2080 break;
2081
2082 // CSI Ps g Tab Clear (TBC).
2083 case 'g':
2084 this.tabClear(this.params);
2085 break;
2086
2087 // CSI Pm i Media Copy (MC).
2088 // CSI ? Pm i
2089 // case 'i':
2090 // this.mediaCopy(this.params);
2091 // break;
2092
2093 // CSI Pm m Character Attributes (SGR).
2094 // CSI > Ps; Ps m
2095 // case 'm': // duplicate
2096 // if (this.prefix === '>') {
2097 // this.setResources(this.params);
2098 // } else {
2099 // this.charAttributes(this.params);
2100 // }
2101 // break;
2102
2103 // CSI Ps n Device Status Report (DSR).
2104 // CSI > Ps n
2105 // case 'n': // duplicate
2106 // if (this.prefix === '>') {
2107 // this.disableModifiers(this.params);
2108 // } else {
2109 // this.deviceStatus(this.params);
2110 // }
2111 // break;
2112
2113 // CSI > Ps p Set pointer mode.
2114 // CSI ! p Soft terminal reset (DECSTR).
2115 // CSI Ps$ p
2116 // Request ANSI mode (DECRQM).
2117 // CSI ? Ps$ p
2118 // Request DEC private mode (DECRQM).
2119 // CSI Ps ; Ps " p
2120 case 'p':
2121 switch (this.prefix) {
2122 // case '>':
2123 // this.setPointerMode(this.params);
2124 // break;
2125 case '!':
2126 this.softReset(this.params);
2127 break;
2128 // case '?':
2129 // if (this.postfix === '$') {
2130 // this.requestPrivateMode(this.params);
2131 // }
2132 // break;
2133 // default:
2134 // if (this.postfix === '"') {
2135 // this.setConformanceLevel(this.params);
2136 // } else if (this.postfix === '$') {
2137 // this.requestAnsiMode(this.params);
2138 // }
2139 // break;
2140 }
2141 break;
2142
2143 // CSI Ps q Load LEDs (DECLL).
2144 // CSI Ps SP q
2145 // CSI Ps " q
2146 // case 'q':
2147 // if (this.postfix === ' ') {
2148 // this.setCursorStyle(this.params);
2149 // break;
2150 // }
2151 // if (this.postfix === '"') {
2152 // this.setCharProtectionAttr(this.params);
2153 // break;
2154 // }
2155 // this.loadLEDs(this.params);
2156 // break;
2157
2158 // CSI Ps ; Ps r
2159 // Set Scrolling Region [top;bottom] (default = full size of win-
2160 // dow) (DECSTBM).
2161 // CSI ? Pm r
2162 // CSI Pt; Pl; Pb; Pr; Ps$ r
2163 // case 'r': // duplicate
2164 // if (this.prefix === '?') {
2165 // this.restorePrivateValues(this.params);
2166 // } else if (this.postfix === '$') {
2167 // this.setAttrInRectangle(this.params);
2168 // } else {
2169 // this.setScrollRegion(this.params);
2170 // }
2171 // break;
2172
2173 // CSI s Save cursor (ANSI.SYS).
2174 // CSI ? Pm s
2175 // case 's': // duplicate
2176 // if (this.prefix === '?') {
2177 // this.savePrivateValues(this.params);
2178 // } else {
2179 // this.saveCursor(this.params);
2180 // }
2181 // break;
2182
2183 // CSI Ps ; Ps ; Ps t
2184 // CSI Pt; Pl; Pb; Pr; Ps$ t
2185 // CSI > Ps; Ps t
2186 // CSI Ps SP t
2187 // case 't':
2188 // if (this.postfix === '$') {
2189 // this.reverseAttrInRectangle(this.params);
2190 // } else if (this.postfix === ' ') {
2191 // this.setWarningBellVolume(this.params);
2192 // } else {
2193 // if (this.prefix === '>') {
2194 // this.setTitleModeFeature(this.params);
2195 // } else {
2196 // this.manipulateWindow(this.params);
2197 // }
2198 // }
2199 // break;
2200
2201 // CSI u Restore cursor (ANSI.SYS).
2202 // CSI Ps SP u
2203 // case 'u': // duplicate
2204 // if (this.postfix === ' ') {
2205 // this.setMarginBellVolume(this.params);
2206 // } else {
2207 // this.restoreCursor(this.params);
2208 // }
2209 // break;
2210
2211 // CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v
2212 // case 'v':
2213 // if (this.postfix === '$') {
2214 // this.copyRectagle(this.params);
2215 // }
2216 // break;
2217
2218 // CSI Pt ; Pl ; Pb ; Pr ' w
2219 // case 'w':
2220 // if (this.postfix === '\'') {
2221 // this.enableFilterRectangle(this.params);
2222 // }
2223 // break;
2224
2225 // CSI Ps x Request Terminal Parameters (DECREQTPARM).
2226 // CSI Ps x Select Attribute Change Extent (DECSACE).
2227 // CSI Pc; Pt; Pl; Pb; Pr$ x
2228 // case 'x':
2229 // if (this.postfix === '$') {
2230 // this.fillRectangle(this.params);
2231 // } else {
2232 // this.requestParameters(this.params);
2233 // //this.__(this.params);
2234 // }
2235 // break;
2236
2237 // CSI Ps ; Pu ' z
2238 // CSI Pt; Pl; Pb; Pr$ z
2239 // case 'z':
2240 // if (this.postfix === '\'') {
2241 // this.enableLocatorReporting(this.params);
2242 // } else if (this.postfix === '$') {
2243 // this.eraseRectangle(this.params);
2244 // }
2245 // break;
2246
2247 // CSI Pm ' {
2248 // CSI Pt; Pl; Pb; Pr$ {
2249 // case '{':
2250 // if (this.postfix === '\'') {
2251 // this.setLocatorEvents(this.params);
2252 // } else if (this.postfix === '$') {
2253 // this.selectiveEraseRectangle(this.params);
2254 // }
2255 // break;
2256
2257 // CSI Ps ' |
2258 // case '|':
2259 // if (this.postfix === '\'') {
2260 // this.requestLocatorPosition(this.params);
2261 // }
2262 // break;
2263
2264 // CSI P m SP }
2265 // Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
2266 // case '}':
2267 // if (this.postfix === ' ') {
2268 // this.insertColumns(this.params);
2269 // }
2270 // break;
2271
2272 // CSI P m SP ~
2273 // Delete P s Column(s) (default = 1) (DECDC), VT420 and up
2274 // case '~':
2275 // if (this.postfix === ' ') {
2276 // this.deleteColumns(this.params);
2277 // }
2278 // break;
2279
2280 default:
2281 this.error('Unknown CSI code: %s.', ch);
2282 break;
2283 }
2284
2285 this.prefix = '';
2286 this.postfix = '';
2287 break;
2288
2289 case dcs:
2290 if (ch === '\x1b' || ch === '\x07') {
2291 if (ch === '\x1b') i++;
2292
2293 switch (this.prefix) {
2294 // User-Defined Keys (DECUDK).
2295 case '':
2296 break;
2297
2298 // Request Status String (DECRQSS).
2299 // test: echo -e '\eP$q"p\e\\'
2300 case '$q':
2301 var pt = this.currentParam
2302 , valid = false;
2303
2304 switch (pt) {
2305 // DECSCA
2306 case '"q':
2307 pt = '0"q';
2308 break;
2309
2310 // DECSCL
2311 case '"p':
2312 pt = '61"p';
2313 break;
2314
2315 // DECSTBM
2316 case 'r':
2317 pt = ''
2318 + (this.scrollTop + 1)
2319 + ';'
2320 + (this.scrollBottom + 1)
2321 + 'r';
2322 break;
2323
2324 // SGR
2325 case 'm':
2326 pt = '0m';
2327 break;
2328
2329 default:
2330 this.error('Unknown DCS Pt: %s.', pt);
2331 pt = '';
2332 break;
2333 }
2334
2335 this.send('\x1bP' + +valid + '$r' + pt + '\x1b\\');
2336 break;
2337
2338 // Set Termcap/Terminfo Data (xterm, experimental).
2339 case '+p':
2340 break;
2341
2342 // Request Termcap/Terminfo String (xterm, experimental)
2343 // Regular xterm does not even respond to this sequence.
2344 // This can cause a small glitch in vim.
2345 // test: echo -ne '\eP+q6b64\e\\'
2346 case '+q':
2347 var pt = this.currentParam
2348 , valid = false;
2349
2350 this.send('\x1bP' + +valid + '+r' + pt + '\x1b\\');
2351 break;
2352
2353 default:
2354 this.error('Unknown DCS prefix: %s.', this.prefix);
2355 break;
2356 }
2357
2358 this.currentParam = 0;
2359 this.prefix = '';
2360 this.state = normal;
2361 } else if (!this.currentParam) {
2362 if (!this.prefix && ch !== '$' && ch !== '+') {
2363 this.currentParam = ch;
2364 } else if (this.prefix.length === 2) {
2365 this.currentParam = ch;
2366 } else {
2367 this.prefix += ch;
2368 }
2369 } else {
2370 this.currentParam += ch;
2371 }
2372 break;
2373
2374 case ignore:
2375 // For PM and APC.
2376 if (ch === '\x1b' || ch === '\x07') {
2377 if (ch === '\x1b') i++;
2378 this.state = normal;
2379 }
2380 break;
2381 }
2382 }
2383
2384 this.updateRange(this.y);
2385 this.refresh(this.refreshStart, this.refreshEnd);
2386};
2387
2388Terminal.prototype.writeln = function(data) {
2389 this.write(data + '\r\n');
2390};
2391
2392// Key Resources:
2393// https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
2394Terminal.prototype.keyDown = function(ev) {
bcecbcd9
CJ
2395 var self = this
2396 , key;
8bc844c0
CJ
2397
2398 switch (ev.keyCode) {
2399 // backspace
2400 case 8:
2401 if (ev.shiftKey) {
2402 key = '\x08'; // ^H
2403 break;
2404 }
2405 key = '\x7f'; // ^?
2406 break;
2407 // tab
2408 case 9:
2409 if (ev.shiftKey) {
2410 key = '\x1b[Z';
2411 break;
2412 }
2413 key = '\t';
2414 break;
2415 // return/enter
2416 case 13:
2417 key = '\r';
2418 break;
2419 // escape
2420 case 27:
2421 key = '\x1b';
2422 break;
2423 // left-arrow
2424 case 37:
2425 if (this.applicationCursor) {
2426 key = '\x1bOD'; // SS3 as ^[O for 7-bit
2427 //key = '\x8fD'; // SS3 as 0x8f for 8-bit
2428 break;
2429 }
2430 key = '\x1b[D';
2431 break;
2432 // right-arrow
2433 case 39:
2434 if (this.applicationCursor) {
2435 key = '\x1bOC';
2436 break;
2437 }
2438 key = '\x1b[C';
2439 break;
2440 // up-arrow
2441 case 38:
2442 if (this.applicationCursor) {
2443 key = '\x1bOA';
2444 break;
2445 }
2446 if (ev.ctrlKey) {
2447 this.scrollDisp(-1);
2448 return cancel(ev);
2449 } else {
2450 key = '\x1b[A';
2451 }
2452 break;
2453 // down-arrow
2454 case 40:
2455 if (this.applicationCursor) {
2456 key = '\x1bOB';
2457 break;
2458 }
2459 if (ev.ctrlKey) {
2460 this.scrollDisp(1);
2461 return cancel(ev);
2462 } else {
2463 key = '\x1b[B';
2464 }
2465 break;
2466 // delete
2467 case 46:
2468 key = '\x1b[3~';
2469 break;
2470 // insert
2471 case 45:
2472 key = '\x1b[2~';
2473 break;
2474 // home
2475 case 36:
2476 if (this.applicationKeypad) {
2477 key = '\x1bOH';
2478 break;
2479 }
2480 key = '\x1bOH';
2481 break;
2482 // end
2483 case 35:
2484 if (this.applicationKeypad) {
2485 key = '\x1bOF';
2486 break;
2487 }
2488 key = '\x1bOF';
2489 break;
2490 // page up
2491 case 33:
2492 if (ev.shiftKey) {
2493 this.scrollDisp(-(this.rows - 1));
2494 return cancel(ev);
2495 } else {
2496 key = '\x1b[5~';
2497 }
2498 break;
2499 // page down
2500 case 34:
2501 if (ev.shiftKey) {
2502 this.scrollDisp(this.rows - 1);
2503 return cancel(ev);
2504 } else {
2505 key = '\x1b[6~';
2506 }
2507 break;
2508 // F1
2509 case 112:
2510 key = '\x1bOP';
2511 break;
2512 // F2
2513 case 113:
2514 key = '\x1bOQ';
2515 break;
2516 // F3
2517 case 114:
2518 key = '\x1bOR';
2519 break;
2520 // F4
2521 case 115:
2522 key = '\x1bOS';
2523 break;
2524 // F5
2525 case 116:
2526 key = '\x1b[15~';
2527 break;
2528 // F6
2529 case 117:
2530 key = '\x1b[17~';
2531 break;
2532 // F7
2533 case 118:
2534 key = '\x1b[18~';
2535 break;
2536 // F8
2537 case 119:
2538 key = '\x1b[19~';
2539 break;
2540 // F9
2541 case 120:
2542 key = '\x1b[20~';
2543 break;
2544 // F10
2545 case 121:
2546 key = '\x1b[21~';
2547 break;
2548 // F11
2549 case 122:
2550 key = '\x1b[23~';
2551 break;
2552 // F12
2553 case 123:
2554 key = '\x1b[24~';
2555 break;
2556 default:
2557 // a-z and space
2558 if (ev.ctrlKey) {
2559 if (ev.keyCode >= 65 && ev.keyCode <= 90) {
ffcbfdec 2560 // Ctrl-A
74848936
CJ
2561 if (this.screenKeys) {
2562 if (!this.prefixMode && !this.selectMode && ev.keyCode === 65) {
2563 this.enterPrefix();
2564 return cancel(ev);
2565 }
da887cf4
CJ
2566 }
2567 // Ctrl-V
2568 if (this.prefixMode && ev.keyCode === 86) {
9e6cb6b6 2569 this.leavePrefix();
da887cf4
CJ
2570 return;
2571 }
2572 // Ctrl-C
9e6cb6b6 2573 if ((this.prefixMode || this.selectMode) && ev.keyCode === 67) {
bcecbcd9
CJ
2574 if (this.visualMode) {
2575 setTimeout(function() {
2576 self.leaveVisual();
2577 }, 1);
2578 }
da887cf4 2579 return;
0d60718f 2580 }
8bc844c0
CJ
2581 key = String.fromCharCode(ev.keyCode - 64);
2582 } else if (ev.keyCode === 32) {
2583 // NUL
2584 key = String.fromCharCode(0);
2585 } else if (ev.keyCode >= 51 && ev.keyCode <= 55) {
2586 // escape, file sep, group sep, record sep, unit sep
2587 key = String.fromCharCode(ev.keyCode - 51 + 27);
2588 } else if (ev.keyCode === 56) {
2589 // delete
2590 key = String.fromCharCode(127);
2591 } else if (ev.keyCode === 219) {
2592 // ^[ - escape
2593 key = String.fromCharCode(27);
2594 } else if (ev.keyCode === 221) {
2595 // ^] - group sep
2596 key = String.fromCharCode(29);
2597 }
791127bc 2598 } else if ((!this.isMac && ev.altKey) || (this.isMac && ev.metaKey)) {
8bc844c0
CJ
2599 if (ev.keyCode >= 65 && ev.keyCode <= 90) {
2600 key = '\x1b' + String.fromCharCode(ev.keyCode + 32);
2601 } else if (ev.keyCode === 192) {
2602 key = '\x1b`';
2603 } else if (ev.keyCode >= 48 && ev.keyCode <= 57) {
2604 key = '\x1b' + (ev.keyCode - 48);
2605 }
2606 }
2607 break;
2608 }
2609
9e6cb6b6
CJ
2610 if (!key) return true;
2611
2612 if (this.prefixMode) {
2613 this.leavePrefix();
da887cf4
CJ
2614 return cancel(ev);
2615 }
0d60718f 2616
9e6cb6b6 2617 if (this.selectMode) {
0d60718f
CJ
2618 this.keySelect(ev, key);
2619 return cancel(ev);
2620 }
2621
8bc844c0 2622 this.emit('keydown', ev);
9e6cb6b6 2623 this.emit('key', key, ev);
8bc844c0 2624
9e6cb6b6
CJ
2625 this.showCursor();
2626 this.handler(key);
8bc844c0 2627
9e6cb6b6 2628 return cancel(ev);
8bc844c0
CJ
2629};
2630
9e6cb6b6
CJ
2631Terminal.prototype.setgLevel = function(g) {
2632 this.glevel = g;
2633 this.charset = this.charsets[g];
0d60718f
CJ
2634};
2635
9e6cb6b6
CJ
2636Terminal.prototype.setgCharset = function(g, charset) {
2637 this.charsets[g] = charset;
2638 if (this.glevel === g) {
2639 this.charset = charset;
2640 }
0d60718f
CJ
2641};
2642
9e6cb6b6
CJ
2643Terminal.prototype.keyPress = function(ev) {
2644 var key;
0d60718f 2645
9e6cb6b6 2646 cancel(ev);
ffcbfdec 2647
9e6cb6b6
CJ
2648 if (ev.charCode) {
2649 key = ev.charCode;
2650 } else if (ev.which == null) {
2651 key = ev.keyCode;
2652 } else if (ev.which !== 0 && ev.charCode !== 0) {
2653 key = ev.which;
2654 } else {
2655 return false;
ffcbfdec
CJ
2656 }
2657
9e6cb6b6 2658 if (!key || ev.ctrlKey || ev.altKey || ev.metaKey) return false;
ffcbfdec 2659
9e6cb6b6 2660 key = String.fromCharCode(key);
ffcbfdec 2661
9e6cb6b6
CJ
2662 if (this.prefixMode) {
2663 this.leavePrefix();
2664 this.keyPrefix(ev, key);
2665 return false;
ffcbfdec
CJ
2666 }
2667
9e6cb6b6
CJ
2668 if (this.selectMode) {
2669 this.keySelect(ev, key);
2670 return false;
ffcbfdec
CJ
2671 }
2672
9e6cb6b6
CJ
2673 this.emit('keypress', key, ev);
2674 this.emit('key', key, ev);
ffcbfdec 2675
9e6cb6b6
CJ
2676 this.showCursor();
2677 this.handler(key);
ffcbfdec 2678
9e6cb6b6
CJ
2679 return false;
2680};
ffcbfdec 2681
9e6cb6b6
CJ
2682Terminal.prototype.send = function(data) {
2683 var self = this;
ffcbfdec 2684
9e6cb6b6
CJ
2685 if (!this.queue) {
2686 setTimeout(function() {
2687 self.handler(self.queue);
2688 self.queue = '';
2689 }, 1);
ffcbfdec
CJ
2690 }
2691
9e6cb6b6
CJ
2692 this.queue += data;
2693};
ffcbfdec 2694
9e6cb6b6
CJ
2695Terminal.prototype.bell = function() {
2696 if (!this.visualBell) return;
2697 var self = this;
2698 this.element.style.borderColor = 'white';
2699 setTimeout(function() {
2700 self.element.style.borderColor = '';
2701 }, 10);
2702 if (this.popOnBell) this.focus();
2703};
ffcbfdec 2704
9e6cb6b6
CJ
2705Terminal.prototype.log = function() {
2706 if (!this.debug) return;
2707 if (!this.context.console || !this.context.console.log) return;
2708 var args = Array.prototype.slice.call(arguments);
2709 this.context.console.log.apply(this.context.console, args);
2710};
ffcbfdec 2711
9e6cb6b6
CJ
2712Terminal.prototype.error = function() {
2713 if (!this.debug) return;
2714 if (!this.context.console || !this.context.console.error) return;
2715 var args = Array.prototype.slice.call(arguments);
2716 this.context.console.error.apply(this.context.console, args);
2717};
ffcbfdec 2718
9e6cb6b6
CJ
2719Terminal.prototype.resize = function(x, y) {
2720 var line
2721 , el
2722 , i
2723 , j
2724 , ch;
ffcbfdec 2725
9e6cb6b6
CJ
2726 if (x < 1) x = 1;
2727 if (y < 1) y = 1;
ffcbfdec 2728
9e6cb6b6
CJ
2729 // resize cols
2730 j = this.cols;
2731 if (j < x) {
2732 ch = [this.defAttr, ' ']; // does xterm use the default attr?
2733 i = this.lines.length;
2734 while (i--) {
2735 while (this.lines[i].length < x) {
2736 this.lines[i].push(ch);
ffcbfdec 2737 }
ffcbfdec 2738 }
9e6cb6b6
CJ
2739 } else if (j > x) {
2740 i = this.lines.length;
2741 while (i--) {
2742 while (this.lines[i].length > x) {
2743 this.lines[i].pop();
2744 }
ffcbfdec 2745 }
ffcbfdec 2746 }
9e6cb6b6
CJ
2747 this.setupStops(j);
2748 this.cols = x;
ffcbfdec 2749
9e6cb6b6
CJ
2750 // resize rows
2751 j = this.rows;
2752 if (j < y) {
2753 el = this.element;
2754 while (j++ < y) {
2755 if (this.lines.length < y + this.ybase) {
2756 this.lines.push(this.blankLine());
ffcbfdec 2757 }
9e6cb6b6
CJ
2758 if (this.children.length < y) {
2759 line = this.document.createElement('div');
2760 el.appendChild(line);
2761 this.children.push(line);
ffcbfdec 2762 }
9e6cb6b6
CJ
2763 }
2764 } else if (j > y) {
2765 while (j-- > y) {
2766 if (this.lines.length > y + this.ybase) {
2767 this.lines.pop();
2768 }
2769 if (this.children.length > y) {
2770 el = this.children.pop();
2771 if (!el) continue;
2772 el.parentNode.removeChild(el);
ffcbfdec 2773 }
ffcbfdec 2774 }
9e6cb6b6
CJ
2775 }
2776 this.rows = y;
ffcbfdec 2777
9e6cb6b6
CJ
2778 // make sure the cursor stays on screen
2779 if (this.y >= y) this.y = y - 1;
2780 if (this.x >= x) this.x = x - 1;
ffcbfdec 2781
9e6cb6b6
CJ
2782 this.scrollTop = 0;
2783 this.scrollBottom = y - 1;
ffcbfdec 2784
9e6cb6b6 2785 this.refresh(0, this.rows - 1);
ffcbfdec 2786
9e6cb6b6
CJ
2787 // it's a real nightmare trying
2788 // to resize the original
2789 // screen buffer. just set it
2790 // to null for now.
2791 this.normal = null;
2792};
ffcbfdec 2793
9e6cb6b6
CJ
2794Terminal.prototype.updateRange = function(y) {
2795 if (y < this.refreshStart) this.refreshStart = y;
2796 if (y > this.refreshEnd) this.refreshEnd = y;
2797 // if (y > this.refreshEnd) {
2798 // this.refreshEnd = y;
2799 // if (y > this.rows - 1) {
2800 // this.refreshEnd = this.rows - 1;
2801 // }
2802 // }
2803};
ffcbfdec 2804
9e6cb6b6
CJ
2805Terminal.prototype.maxRange = function() {
2806 this.refreshStart = 0;
2807 this.refreshEnd = this.rows - 1;
2808};
ffcbfdec 2809
9e6cb6b6
CJ
2810Terminal.prototype.setupStops = function(i) {
2811 if (i != null) {
2812 if (!this.tabs[i]) {
2813 i = this.prevStop(i);
ffcbfdec 2814 }
9e6cb6b6
CJ
2815 } else {
2816 this.tabs = {};
2817 i = 0;
ffcbfdec
CJ
2818 }
2819
9e6cb6b6
CJ
2820 for (; i < this.cols; i += 8) {
2821 this.tabs[i] = true;
c5e8a7ab 2822 }
9e6cb6b6 2823};
c5e8a7ab 2824
9e6cb6b6
CJ
2825Terminal.prototype.prevStop = function(x) {
2826 if (x == null) x = this.x;
2827 while (!this.tabs[--x] && x > 0);
2828 return x >= this.cols
2829 ? this.cols - 1
2830 : x < 0 ? 0 : x;
2831};
ffcbfdec 2832
9e6cb6b6
CJ
2833Terminal.prototype.nextStop = function(x) {
2834 if (x == null) x = this.x;
2835 while (!this.tabs[++x] && x < this.cols);
2836 return x >= this.cols
2837 ? this.cols - 1
2838 : x < 0 ? 0 : x;
ffcbfdec
CJ
2839};
2840
9e6cb6b6
CJ
2841Terminal.prototype.eraseRight = function(x, y) {
2842 var line = this.lines[this.ybase + y]
2843 , ch = [this.eraseAttr(), ' ']; // xterm
cc7f4d0d 2844
cc7f4d0d 2845
9e6cb6b6
CJ
2846 for (; x < this.cols; x++) {
2847 line[x] = ch;
cc7f4d0d
CJ
2848 }
2849
9e6cb6b6 2850 this.updateRange(y);
cc7f4d0d
CJ
2851};
2852
9e6cb6b6
CJ
2853Terminal.prototype.eraseLeft = function(x, y) {
2854 var line = this.lines[this.ybase + y]
2855 , ch = [this.eraseAttr(), ' ']; // xterm
cc7f4d0d 2856
9e6cb6b6
CJ
2857 x++;
2858 while (x--) line[x] = ch;
cc7f4d0d 2859
9e6cb6b6
CJ
2860 this.updateRange(y);
2861};
cc7f4d0d 2862
9e6cb6b6
CJ
2863Terminal.prototype.eraseLine = function(y) {
2864 this.eraseRight(0, y);
cc7f4d0d
CJ
2865};
2866
9e6cb6b6
CJ
2867Terminal.prototype.blankLine = function(cur) {
2868 var attr = cur
2869 ? this.eraseAttr()
2870 : this.defAttr;
ffcbfdec 2871
9e6cb6b6
CJ
2872 var ch = [attr, ' ']
2873 , line = []
2874 , i = 0;
ffcbfdec 2875
9e6cb6b6
CJ
2876 for (; i < this.cols; i++) {
2877 line[i] = ch;
2878 }
ffcbfdec 2879
9e6cb6b6
CJ
2880 return line;
2881};
ffcbfdec 2882
9e6cb6b6
CJ
2883Terminal.prototype.ch = function(cur) {
2884 return cur
2885 ? [this.eraseAttr(), ' ']
2886 : [this.defAttr, ' '];
2887};
ffcbfdec 2888
9e6cb6b6
CJ
2889Terminal.prototype.is = function(term) {
2890 var name = this.termName;
2891 return (name + '').indexOf(term) === 0;
2892};
ffcbfdec 2893
9e6cb6b6
CJ
2894Terminal.prototype.handler = function(data) {
2895 this.emit('data', data);
2896};
ffcbfdec 2897
9e6cb6b6
CJ
2898Terminal.prototype.handleTitle = function(title) {
2899 this.emit('title', title);
2900};
ffcbfdec 2901
9e6cb6b6
CJ
2902/**
2903 * ESC
2904 */
ffcbfdec 2905
9e6cb6b6
CJ
2906// ESC D Index (IND is 0x84).
2907Terminal.prototype.index = function() {
2908 this.y++;
2909 if (this.y > this.scrollBottom) {
2910 this.y--;
2911 this.scroll();
2912 }
2913 this.state = normal;
2914};
ffcbfdec 2915
9e6cb6b6
CJ
2916// ESC M Reverse Index (RI is 0x8d).
2917Terminal.prototype.reverseIndex = function() {
2918 var j;
2919 this.y--;
2920 if (this.y < this.scrollTop) {
2921 this.y++;
2922 // possibly move the code below to term.reverseScroll();
2923 // test: echo -ne '\e[1;1H\e[44m\eM\e[0m'
2924 // blankLine(true) is xterm/linux behavior
2925 this.lines.splice(this.y + this.ybase, 0, this.blankLine(true));
2926 j = this.rows - 1 - this.scrollBottom;
2927 this.lines.splice(this.rows - 1 + this.ybase - j + 1, 1);
2928 // this.maxRange();
2929 this.updateRange(this.scrollTop);
2930 this.updateRange(this.scrollBottom);
2931 }
2932 this.state = normal;
2933};
ffcbfdec 2934
9e6cb6b6
CJ
2935// ESC c Full Reset (RIS).
2936Terminal.prototype.reset = function() {
2937 Terminal.call(this, this.options);
2938 this.refresh(0, this.rows - 1);
2939};
ffcbfdec 2940
9e6cb6b6
CJ
2941// ESC H Tab Set (HTS is 0x88).
2942Terminal.prototype.tabSet = function() {
2943 this.tabs[this.x] = true;
2944 this.state = normal;
2945};
ffcbfdec 2946
9e6cb6b6
CJ
2947/**
2948 * CSI
2949 */
ffcbfdec 2950
9e6cb6b6
CJ
2951// CSI Ps A
2952// Cursor Up Ps Times (default = 1) (CUU).
2953Terminal.prototype.cursorUp = function(params) {
2954 var param = params[0];
2955 if (param < 1) param = 1;
2956 this.y -= param;
2957 if (this.y < 0) this.y = 0;
2958};
ffcbfdec 2959
9e6cb6b6
CJ
2960// CSI Ps B
2961// Cursor Down Ps Times (default = 1) (CUD).
2962Terminal.prototype.cursorDown = function(params) {
2963 var param = params[0];
2964 if (param < 1) param = 1;
2965 this.y += param;
2966 if (this.y >= this.rows) {
2967 this.y = this.rows - 1;
0d60718f
CJ
2968 }
2969};
2970
9e6cb6b6
CJ
2971// CSI Ps C
2972// Cursor Forward Ps Times (default = 1) (CUF).
2973Terminal.prototype.cursorForward = function(params) {
2974 var param = params[0];
2975 if (param < 1) param = 1;
2976 this.x += param;
2977 if (this.x >= this.cols) {
2978 this.x = this.cols - 1;
0d60718f 2979 }
9e6cb6b6 2980};
0d60718f 2981
9e6cb6b6
CJ
2982// CSI Ps D
2983// Cursor Backward Ps Times (default = 1) (CUB).
2984Terminal.prototype.cursorBackward = function(params) {
2985 var param = params[0];
2986 if (param < 1) param = 1;
2987 this.x -= param;
2988 if (this.x < 0) this.x = 0;
2989};
0d60718f 2990
9e6cb6b6
CJ
2991// CSI Ps ; Ps H
2992// Cursor Position [row;column] (default = [1,1]) (CUP).
2993Terminal.prototype.cursorPos = function(params) {
2994 var row, col;
0d60718f 2995
9e6cb6b6 2996 row = params[0] - 1;
0d60718f 2997
9e6cb6b6
CJ
2998 if (params.length >= 2) {
2999 col = params[1] - 1;
3000 } else {
3001 col = 0;
0d60718f
CJ
3002 }
3003
9e6cb6b6
CJ
3004 if (row < 0) {
3005 row = 0;
3006 } else if (row >= this.rows) {
3007 row = this.rows - 1;
0d60718f
CJ
3008 }
3009
9e6cb6b6
CJ
3010 if (col < 0) {
3011 col = 0;
3012 } else if (col >= this.cols) {
3013 col = this.cols - 1;
ffcbfdec 3014 }
0d60718f 3015
9e6cb6b6
CJ
3016 this.x = col;
3017 this.y = row;
0d60718f
CJ
3018};
3019
9e6cb6b6
CJ
3020// CSI Ps J Erase in Display (ED).
3021// Ps = 0 -> Erase Below (default).
3022// Ps = 1 -> Erase Above.
3023// Ps = 2 -> Erase All.
3024// Ps = 3 -> Erase Saved Lines (xterm).
3025// CSI ? Ps J
3026// Erase in Display (DECSED).
3027// Ps = 0 -> Selective Erase Below (default).
3028// Ps = 1 -> Selective Erase Above.
3029// Ps = 2 -> Selective Erase All.
3030Terminal.prototype.eraseInDisplay = function(params) {
3031 var j;
3032 switch (params[0]) {
3033 case 0:
3034 this.eraseRight(this.x, this.y);
3035 j = this.y + 1;
3036 for (; j < this.rows; j++) {
3037 this.eraseLine(j);
0d60718f 3038 }
9e6cb6b6
CJ
3039 break;
3040 case 1:
3041 this.eraseLeft(this.x, this.y);
3042 j = this.y;
3043 while (j--) {
3044 this.eraseLine(j);
0d60718f 3045 }
9e6cb6b6
CJ
3046 break;
3047 case 2:
3048 j = this.rows;
3049 while (j--) this.eraseLine(j);
3050 break;
3051 case 3:
3052 ; // no saved lines
3053 break;
0d60718f 3054 }
9e6cb6b6 3055};
0d60718f 3056
9e6cb6b6
CJ
3057// CSI Ps K Erase in Line (EL).
3058// Ps = 0 -> Erase to Right (default).
3059// Ps = 1 -> Erase to Left.
3060// Ps = 2 -> Erase All.
3061// CSI ? Ps K
3062// Erase in Line (DECSEL).
3063// Ps = 0 -> Selective Erase to Right (default).
3064// Ps = 1 -> Selective Erase to Left.
3065// Ps = 2 -> Selective Erase All.
3066Terminal.prototype.eraseInLine = function(params) {
3067 switch (params[0]) {
3068 case 0:
3069 this.eraseRight(this.x, this.y);
3070 break;
3071 case 1:
3072 this.eraseLeft(this.x, this.y);
3073 break;
3074 case 2:
3075 this.eraseLine(this.y);
9d1a14d0 3076 break;
9d1a14d0 3077 }
0d60718f
CJ
3078};
3079
9e6cb6b6
CJ
3080// CSI Pm m Character Attributes (SGR).
3081// Ps = 0 -> Normal (default).
3082// Ps = 1 -> Bold.
3083// Ps = 4 -> Underlined.
3084// Ps = 5 -> Blink (appears as Bold).
3085// Ps = 7 -> Inverse.
3086// Ps = 8 -> Invisible, i.e., hidden (VT300).
3087// Ps = 2 2 -> Normal (neither bold nor faint).
3088// Ps = 2 4 -> Not underlined.
3089// Ps = 2 5 -> Steady (not blinking).
3090// Ps = 2 7 -> Positive (not inverse).
3091// Ps = 2 8 -> Visible, i.e., not hidden (VT300).
3092// Ps = 3 0 -> Set foreground color to Black.
3093// Ps = 3 1 -> Set foreground color to Red.
3094// Ps = 3 2 -> Set foreground color to Green.
3095// Ps = 3 3 -> Set foreground color to Yellow.
3096// Ps = 3 4 -> Set foreground color to Blue.
3097// Ps = 3 5 -> Set foreground color to Magenta.
3098// Ps = 3 6 -> Set foreground color to Cyan.
3099// Ps = 3 7 -> Set foreground color to White.
3100// Ps = 3 9 -> Set foreground color to default (original).
3101// Ps = 4 0 -> Set background color to Black.
3102// Ps = 4 1 -> Set background color to Red.
3103// Ps = 4 2 -> Set background color to Green.
3104// Ps = 4 3 -> Set background color to Yellow.
3105// Ps = 4 4 -> Set background color to Blue.
3106// Ps = 4 5 -> Set background color to Magenta.
3107// Ps = 4 6 -> Set background color to Cyan.
3108// Ps = 4 7 -> Set background color to White.
3109// Ps = 4 9 -> Set background color to default (original).
8bc844c0 3110
9e6cb6b6
CJ
3111// If 16-color support is compiled, the following apply. Assume
3112// that xterm's resources are set so that the ISO color codes are
3113// the first 8 of a set of 16. Then the aixterm colors are the
3114// bright versions of the ISO colors:
3115// Ps = 9 0 -> Set foreground color to Black.
3116// Ps = 9 1 -> Set foreground color to Red.
3117// Ps = 9 2 -> Set foreground color to Green.
3118// Ps = 9 3 -> Set foreground color to Yellow.
3119// Ps = 9 4 -> Set foreground color to Blue.
3120// Ps = 9 5 -> Set foreground color to Magenta.
3121// Ps = 9 6 -> Set foreground color to Cyan.
3122// Ps = 9 7 -> Set foreground color to White.
3123// Ps = 1 0 0 -> Set background color to Black.
3124// Ps = 1 0 1 -> Set background color to Red.
3125// Ps = 1 0 2 -> Set background color to Green.
3126// Ps = 1 0 3 -> Set background color to Yellow.
3127// Ps = 1 0 4 -> Set background color to Blue.
3128// Ps = 1 0 5 -> Set background color to Magenta.
3129// Ps = 1 0 6 -> Set background color to Cyan.
3130// Ps = 1 0 7 -> Set background color to White.
8bc844c0 3131
9e6cb6b6
CJ
3132// If xterm is compiled with the 16-color support disabled, it
3133// supports the following, from rxvt:
3134// Ps = 1 0 0 -> Set foreground and background color to
3135// default.
8bc844c0 3136
9e6cb6b6
CJ
3137// If 88- or 256-color support is compiled, the following apply.
3138// Ps = 3 8 ; 5 ; Ps -> Set foreground color to the second
3139// Ps.
3140// Ps = 4 8 ; 5 ; Ps -> Set background color to the second
3141// Ps.
3142Terminal.prototype.charAttributes = function(params) {
3143 // Optimize a single SGR0.
3144 if (params.length === 1 && params[0] === 0) {
3145 this.curAttr = this.defAttr;
3146 return;
8bc844c0
CJ
3147 }
3148
9e6cb6b6
CJ
3149 var l = params.length
3150 , i = 0
3151 , flags = this.curAttr >> 18
3152 , fg = (this.curAttr >> 9) & 0x1ff
3153 , bg = this.curAttr & 0x1ff
3154 , p;
8bc844c0 3155
9e6cb6b6
CJ
3156 for (; i < l; i++) {
3157 p = params[i];
3158 if (p >= 30 && p <= 37) {
3159 // fg color 8
3160 fg = p - 30;
3161 } else if (p >= 40 && p <= 47) {
3162 // bg color 8
3163 bg = p - 40;
3164 } else if (p >= 90 && p <= 97) {
3165 // fg color 16
3166 p += 8;
3167 fg = p - 90;
3168 } else if (p >= 100 && p <= 107) {
3169 // bg color 16
3170 p += 8;
3171 bg = p - 100;
3172 } else if (p === 0) {
3173 // default
3174 flags = this.defAttr >> 18;
3175 fg = (this.defAttr >> 9) & 0x1ff;
3176 bg = this.defAttr & 0x1ff;
3177 // flags = 0;
3178 // fg = 0x1ff;
3179 // bg = 0x1ff;
3180 } else if (p === 1) {
3181 // bold text
3182 flags |= 1;
3183 } else if (p === 4) {
3184 // underlined text
3185 flags |= 2;
3186 } else if (p === 5) {
3187 // blink
3188 flags |= 4;
3189 } else if (p === 7) {
3190 // inverse and positive
3191 // test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m'
3192 flags |= 8;
3193 } else if (p === 8) {
3194 // invisible
3195 flags |= 16;
3196 } else if (p === 22) {
3197 // not bold
3198 flags &= ~1;
3199 } else if (p === 24) {
3200 // not underlined
3201 flags &= ~2;
3202 } else if (p === 25) {
3203 // not blink
3204 flags &= ~4;
3205 } else if (p === 27) {
3206 // not inverse
3207 flags &= ~8;
3208 } else if (p === 28) {
3209 // not invisible
3210 flags &= ~16;
3211 } else if (p === 39) {
3212 // reset fg
3213 fg = (this.defAttr >> 9) & 0x1ff;
3214 } else if (p === 49) {
3215 // reset bg
3216 bg = this.defAttr & 0x1ff;
3217 } else if (p === 38) {
3218 // fg color 256
3219 if (params[i + 1] === 2) {
3220 i += 2;
3221 fg = matchColor(
3222 params[i] & 0xff,
3223 params[i + 1] & 0xff,
3224 params[i + 2] & 0xff);
3225 if (fg === -1) fg = 0x1ff;
3226 i += 2;
3227 } else if (params[i + 1] === 5) {
3228 i += 2;
3229 p = params[i] & 0xff;
3230 fg = p;
3231 }
3232 } else if (p === 48) {
3233 // bg color 256
3234 if (params[i + 1] === 2) {
3235 i += 2;
3236 bg = matchColor(
3237 params[i] & 0xff,
3238 params[i + 1] & 0xff,
3239 params[i + 2] & 0xff);
3240 if (bg === -1) bg = 0x1ff;
3241 i += 2;
3242 } else if (params[i + 1] === 5) {
3243 i += 2;
3244 p = params[i] & 0xff;
3245 bg = p;
3246 }
3247 } else if (p === 100) {
3248 // reset fg/bg
3249 fg = (this.defAttr >> 9) & 0x1ff;
3250 bg = this.defAttr & 0x1ff;
3251 } else {
3252 this.error('Unknown SGR attribute: %d.', p);
da887cf4 3253 }
8bc844c0
CJ
3254 }
3255
9e6cb6b6 3256 this.curAttr = (flags << 18) | (fg << 9) | bg;
8bc844c0
CJ
3257};
3258
9e6cb6b6
CJ
3259// CSI Ps n Device Status Report (DSR).
3260// Ps = 5 -> Status Report. Result (``OK'') is
3261// CSI 0 n
3262// Ps = 6 -> Report Cursor Position (CPR) [row;column].
3263// Result is
3264// CSI r ; c R
3265// CSI ? Ps n
3266// Device Status Report (DSR, DEC-specific).
3267// Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI
3268// ? r ; c R (assumes page is zero).
3269// Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready).
3270// or CSI ? 1 1 n (not ready).
3271// Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked)
3272// or CSI ? 2 1 n (locked).
3273// Ps = 2 6 -> Report Keyboard status as
3274// CSI ? 2 7 ; 1 ; 0 ; 0 n (North American).
3275// The last two parameters apply to VT400 & up, and denote key-
3276// board ready and LK01 respectively.
3277// Ps = 5 3 -> Report Locator status as
3278// CSI ? 5 3 n Locator available, if compiled-in, or
3279// CSI ? 5 0 n No Locator, if not.
3280Terminal.prototype.deviceStatus = function(params) {
3281 if (!this.prefix) {
3282 switch (params[0]) {
3283 case 5:
3284 // status report
3285 this.send('\x1b[0n');
3286 break;
3287 case 6:
3288 // cursor position
3289 this.send('\x1b['
3290 + (this.y + 1)
3291 + ';'
3292 + (this.x + 1)
3293 + 'R');
3294 break;
8bc844c0 3295 }
9e6cb6b6
CJ
3296 } else if (this.prefix === '?') {
3297 // modern xterm doesnt seem to
3298 // respond to any of these except ?6, 6, and 5
3299 switch (params[0]) {
3300 case 6:
3301 // cursor position
3302 this.send('\x1b[?'
3303 + (this.y + 1)
3304 + ';'
3305 + (this.x + 1)
3306 + 'R');
3307 break;
3308 case 15:
3309 // no printer
3310 // this.send('\x1b[?11n');
3311 break;
3312 case 25:
3313 // dont support user defined keys
3314 // this.send('\x1b[?21n');
3315 break;
3316 case 26:
3317 // north american keyboard
3318 // this.send('\x1b[?27;1;0;0n');
3319 break;
3320 case 53:
3321 // no dec locator/mouse
3322 // this.send('\x1b[?50n');
3323 break;
8bc844c0
CJ
3324 }
3325 }
9e6cb6b6 3326};
8bc844c0 3327
9e6cb6b6
CJ
3328/**
3329 * Additions
3330 */
8bc844c0 3331
9e6cb6b6
CJ
3332// CSI Ps @
3333// Insert Ps (Blank) Character(s) (default = 1) (ICH).
3334Terminal.prototype.insertChars = function(params) {
3335 var param, row, j, ch;
8bc844c0 3336
9e6cb6b6
CJ
3337 param = params[0];
3338 if (param < 1) param = 1;
8bc844c0 3339
9e6cb6b6
CJ
3340 row = this.y + this.ybase;
3341 j = this.x;
3342 ch = [this.eraseAttr(), ' ']; // xterm
8bc844c0 3343
9e6cb6b6
CJ
3344 while (param-- && j < this.cols) {
3345 this.lines[row].splice(j++, 0, ch);
3346 this.lines[row].pop();
3347 }
8bc844c0
CJ
3348};
3349
9e6cb6b6
CJ
3350// CSI Ps E
3351// Cursor Next Line Ps Times (default = 1) (CNL).
3352// same as CSI Ps B ?
3353Terminal.prototype.cursorNextLine = function(params) {
3354 var param = params[0];
3355 if (param < 1) param = 1;
3356 this.y += param;
3357 if (this.y >= this.rows) {
3358 this.y = this.rows - 1;
3359 }
3360 this.x = 0;
8bc844c0
CJ
3361};
3362
9e6cb6b6
CJ
3363// CSI Ps F
3364// Cursor Preceding Line Ps Times (default = 1) (CNL).
3365// reuse CSI Ps A ?
3366Terminal.prototype.cursorPrecedingLine = function(params) {
3367 var param = params[0];
3368 if (param < 1) param = 1;
3369 this.y -= param;
3370 if (this.y < 0) this.y = 0;
3371 this.x = 0;
8bc844c0
CJ
3372};
3373
9e6cb6b6
CJ
3374// CSI Ps G
3375// Cursor Character Absolute [column] (default = [row,1]) (CHA).
3376Terminal.prototype.cursorCharAbsolute = function(params) {
3377 var param = params[0];
3378 if (param < 1) param = 1;
3379 this.x = param - 1;
3380};
8bc844c0 3381
9e6cb6b6
CJ
3382// CSI Ps L
3383// Insert Ps Line(s) (default = 1) (IL).
3384Terminal.prototype.insertLines = function(params) {
3385 var param, row, j;
3386
3387 param = params[0];
3388 if (param < 1) param = 1;
3389 row = this.y + this.ybase;
3390
3391 j = this.rows - 1 - this.scrollBottom;
3392 j = this.rows - 1 + this.ybase - j + 1;
3393
3394 while (param--) {
3395 // test: echo -e '\e[44m\e[1L\e[0m'
3396 // blankLine(true) - xterm/linux behavior
3397 this.lines.splice(row, 0, this.blankLine(true));
3398 this.lines.splice(j, 1);
8bc844c0 3399 }
8bc844c0 3400
9e6cb6b6
CJ
3401 // this.maxRange();
3402 this.updateRange(this.y);
3403 this.updateRange(this.scrollBottom);
8bc844c0
CJ
3404};
3405
9e6cb6b6
CJ
3406// CSI Ps M
3407// Delete Ps Line(s) (default = 1) (DL).
3408Terminal.prototype.deleteLines = function(params) {
3409 var param, row, j;
8bc844c0 3410
9e6cb6b6
CJ
3411 param = params[0];
3412 if (param < 1) param = 1;
3413 row = this.y + this.ybase;
8bc844c0 3414
9e6cb6b6
CJ
3415 j = this.rows - 1 - this.scrollBottom;
3416 j = this.rows - 1 + this.ybase - j;
8bc844c0 3417
9e6cb6b6
CJ
3418 while (param--) {
3419 // test: echo -e '\e[44m\e[1M\e[0m'
3420 // blankLine(true) - xterm/linux behavior
3421 this.lines.splice(j + 1, 0, this.blankLine(true));
3422 this.lines.splice(row, 1);
8bc844c0
CJ
3423 }
3424
9e6cb6b6
CJ
3425 // this.maxRange();
3426 this.updateRange(this.y);
3427 this.updateRange(this.scrollBottom);
8bc844c0
CJ
3428};
3429
9e6cb6b6
CJ
3430// CSI Ps P
3431// Delete Ps Character(s) (default = 1) (DCH).
3432Terminal.prototype.deleteChars = function(params) {
3433 var param, row, ch;
8bc844c0 3434
9e6cb6b6
CJ
3435 param = params[0];
3436 if (param < 1) param = 1;
8bc844c0 3437
9e6cb6b6
CJ
3438 row = this.y + this.ybase;
3439 ch = [this.eraseAttr(), ' ']; // xterm
3440
3441 while (param--) {
3442 this.lines[row].splice(this.x, 1);
3443 this.lines[row].push(ch);
3444 }
8bc844c0
CJ
3445};
3446
9e6cb6b6
CJ
3447// CSI Ps X
3448// Erase Ps Character(s) (default = 1) (ECH).
3449Terminal.prototype.eraseChars = function(params) {
3450 var param, row, j, ch;
8bc844c0 3451
9e6cb6b6
CJ
3452 param = params[0];
3453 if (param < 1) param = 1;
8bc844c0 3454
9e6cb6b6
CJ
3455 row = this.y + this.ybase;
3456 j = this.x;
3457 ch = [this.eraseAttr(), ' ']; // xterm
8bc844c0 3458
9e6cb6b6
CJ
3459 while (param-- && j < this.cols) {
3460 this.lines[row][j++] = ch;
8bc844c0 3461 }
8bc844c0
CJ
3462};
3463
9e6cb6b6
CJ
3464// CSI Pm ` Character Position Absolute
3465// [column] (default = [row,1]) (HPA).
3466Terminal.prototype.charPosAbsolute = function(params) {
3467 var param = params[0];
3468 if (param < 1) param = 1;
3469 this.x = param - 1;
3470 if (this.x >= this.cols) {
3471 this.x = this.cols - 1;
8bc844c0 3472 }
8bc844c0
CJ
3473};
3474
9e6cb6b6
CJ
3475// 141 61 a * HPR -
3476// Horizontal Position Relative
3477// reuse CSI Ps C ?
3478Terminal.prototype.HPositionRelative = function(params) {
3479 var param = params[0];
3480 if (param < 1) param = 1;
3481 this.x += param;
3482 if (this.x >= this.cols) {
3483 this.x = this.cols - 1;
8bc844c0 3484 }
8bc844c0
CJ
3485};
3486
9e6cb6b6
CJ
3487// CSI Ps c Send Device Attributes (Primary DA).
3488// Ps = 0 or omitted -> request attributes from terminal. The
3489// response depends on the decTerminalID resource setting.
3490// -> CSI ? 1 ; 2 c (``VT100 with Advanced Video Option'')
3491// -> CSI ? 1 ; 0 c (``VT101 with No Options'')
3492// -> CSI ? 6 c (``VT102'')
3493// -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c (``VT220'')
3494// The VT100-style response parameters do not mean anything by
3495// themselves. VT220 parameters do, telling the host what fea-
3496// tures the terminal supports:
3497// Ps = 1 -> 132-columns.
3498// Ps = 2 -> Printer.
3499// Ps = 6 -> Selective erase.
3500// Ps = 8 -> User-defined keys.
3501// Ps = 9 -> National replacement character sets.
3502// Ps = 1 5 -> Technical characters.
3503// Ps = 2 2 -> ANSI color, e.g., VT525.
3504// Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode).
3505// CSI > Ps c
3506// Send Device Attributes (Secondary DA).
3507// Ps = 0 or omitted -> request the terminal's identification
3508// code. The response depends on the decTerminalID resource set-
3509// ting. It should apply only to VT220 and up, but xterm extends
3510// this to VT100.
3511// -> CSI > Pp ; Pv ; Pc c
3512// where Pp denotes the terminal type
3513// Pp = 0 -> ``VT100''.
3514// Pp = 1 -> ``VT220''.
3515// and Pv is the firmware version (for xterm, this was originally
3516// the XFree86 patch number, starting with 95). In a DEC termi-
3517// nal, Pc indicates the ROM cartridge registration number and is
3518// always zero.
3519// More information:
3520// xterm/charproc.c - line 2012, for more information.
3521// vim responds with ^[[?0c or ^[[?1c after the terminal's response (?)
3522Terminal.prototype.sendDeviceAttributes = function(params) {
3523 if (params[0] > 0) return;
8bc844c0 3524
9e6cb6b6
CJ
3525 if (!this.prefix) {
3526 if (this.is('xterm')
3527 || this.is('rxvt-unicode')
3528 || this.is('screen')) {
3529 this.send('\x1b[?1;2c');
3530 } else if (this.is('linux')) {
3531 this.send('\x1b[?6c');
3532 }
3533 } else if (this.prefix === '>') {
3534 // xterm and urxvt
3535 // seem to spit this
3536 // out around ~370 times (?).
3537 if (this.is('xterm')) {
3538 this.send('\x1b[>0;276;0c');
3539 } else if (this.is('rxvt-unicode')) {
3540 this.send('\x1b[>85;95;0c');
3541 } else if (this.is('linux')) {
3542 // not supported by linux console.
3543 // linux console echoes parameters.
3544 this.send(params[0] + 'c');
3545 } else if (this.is('screen')) {
3546 this.send('\x1b[>83;40003;0c');
3547 }
3548 }
8bc844c0
CJ
3549};
3550
9e6cb6b6
CJ
3551// CSI Pm d
3552// Line Position Absolute [row] (default = [1,column]) (VPA).
3553Terminal.prototype.linePosAbsolute = function(params) {
8bc844c0
CJ
3554 var param = params[0];
3555 if (param < 1) param = 1;
9e6cb6b6 3556 this.y = param - 1;
8bc844c0
CJ
3557 if (this.y >= this.rows) {
3558 this.y = this.rows - 1;
3559 }
3560};
3561
9e6cb6b6
CJ
3562// 145 65 e * VPR - Vertical Position Relative
3563// reuse CSI Ps B ?
3564Terminal.prototype.VPositionRelative = function(params) {
8bc844c0
CJ
3565 var param = params[0];
3566 if (param < 1) param = 1;
9e6cb6b6
CJ
3567 this.y += param;
3568 if (this.y >= this.rows) {
3569 this.y = this.rows - 1;
8bc844c0
CJ
3570 }
3571};
3572
9e6cb6b6
CJ
3573// CSI Ps ; Ps f
3574// Horizontal and Vertical Position [row;column] (default =
3575// [1,1]) (HVP).
3576Terminal.prototype.HVPosition = function(params) {
3577 if (params[0] < 1) params[0] = 1;
3578 if (params[1] < 1) params[1] = 1;
8bc844c0 3579
9e6cb6b6
CJ
3580 this.y = params[0] - 1;
3581 if (this.y >= this.rows) {
3582 this.y = this.rows - 1;
8bc844c0
CJ
3583 }
3584
9e6cb6b6
CJ
3585 this.x = params[1] - 1;
3586 if (this.x >= this.cols) {
3587 this.x = this.cols - 1;
8bc844c0 3588 }
8bc844c0
CJ
3589};
3590
9e6cb6b6
CJ
3591// CSI Pm h Set Mode (SM).
3592// Ps = 2 -> Keyboard Action Mode (AM).
3593// Ps = 4 -> Insert Mode (IRM).
3594// Ps = 1 2 -> Send/receive (SRM).
3595// Ps = 2 0 -> Automatic Newline (LNM).
3596// CSI ? Pm h
3597// DEC Private Mode Set (DECSET).
3598// Ps = 1 -> Application Cursor Keys (DECCKM).
3599// Ps = 2 -> Designate USASCII for character sets G0-G3
3600// (DECANM), and set VT100 mode.
3601// Ps = 3 -> 132 Column Mode (DECCOLM).
3602// Ps = 4 -> Smooth (Slow) Scroll (DECSCLM).
3603// Ps = 5 -> Reverse Video (DECSCNM).
3604// Ps = 6 -> Origin Mode (DECOM).
3605// Ps = 7 -> Wraparound Mode (DECAWM).
3606// Ps = 8 -> Auto-repeat Keys (DECARM).
3607// Ps = 9 -> Send Mouse X & Y on button press. See the sec-
3608// tion Mouse Tracking.
3609// Ps = 1 0 -> Show toolbar (rxvt).
3610// Ps = 1 2 -> Start Blinking Cursor (att610).
3611// Ps = 1 8 -> Print form feed (DECPFF).
3612// Ps = 1 9 -> Set print extent to full screen (DECPEX).
3613// Ps = 2 5 -> Show Cursor (DECTCEM).
3614// Ps = 3 0 -> Show scrollbar (rxvt).
3615// Ps = 3 5 -> Enable font-shifting functions (rxvt).
3616// Ps = 3 8 -> Enter Tektronix Mode (DECTEK).
3617// Ps = 4 0 -> Allow 80 -> 132 Mode.
3618// Ps = 4 1 -> more(1) fix (see curses resource).
3619// Ps = 4 2 -> Enable Nation Replacement Character sets (DECN-
3620// RCM).
3621// Ps = 4 4 -> Turn On Margin Bell.
3622// Ps = 4 5 -> Reverse-wraparound Mode.
3623// Ps = 4 6 -> Start Logging. This is normally disabled by a
3624// compile-time option.
3625// Ps = 4 7 -> Use Alternate Screen Buffer. (This may be dis-
3626// abled by the titeInhibit resource).
3627// Ps = 6 6 -> Application keypad (DECNKM).
3628// Ps = 6 7 -> Backarrow key sends backspace (DECBKM).
3629// Ps = 1 0 0 0 -> Send Mouse X & Y on button press and
3630// release. See the section Mouse Tracking.
3631// Ps = 1 0 0 1 -> Use Hilite Mouse Tracking.
3632// Ps = 1 0 0 2 -> Use Cell Motion Mouse Tracking.
3633// Ps = 1 0 0 3 -> Use All Motion Mouse Tracking.
3634// Ps = 1 0 0 4 -> Send FocusIn/FocusOut events.
3635// Ps = 1 0 0 5 -> Enable Extended Mouse Mode.
3636// Ps = 1 0 1 0 -> Scroll to bottom on tty output (rxvt).
3637// Ps = 1 0 1 1 -> Scroll to bottom on key press (rxvt).
3638// Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit.
3639// (enables the eightBitInput resource).
3640// Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num-
3641// Lock keys. (This enables the numLock resource).
3642// Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This
3643// enables the metaSendsEscape resource).
3644// Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete
3645// key.
3646// Ps = 1 0 3 9 -> Send ESC when Alt modifies a key. (This
3647// enables the altSendsEscape resource).
3648// Ps = 1 0 4 0 -> Keep selection even if not highlighted.
3649// (This enables the keepSelection resource).
3650// Ps = 1 0 4 1 -> Use the CLIPBOARD selection. (This enables
3651// the selectToClipboard resource).
3652// Ps = 1 0 4 2 -> Enable Urgency window manager hint when
3653// Control-G is received. (This enables the bellIsUrgent
3654// resource).
3655// Ps = 1 0 4 3 -> Enable raising of the window when Control-G
3656// is received. (enables the popOnBell resource).
3657// Ps = 1 0 4 7 -> Use Alternate Screen Buffer. (This may be
3658// disabled by the titeInhibit resource).
3659// Ps = 1 0 4 8 -> Save cursor as in DECSC. (This may be dis-
3660// abled by the titeInhibit resource).
3661// Ps = 1 0 4 9 -> Save cursor as in DECSC and use Alternate
3662// Screen Buffer, clearing it first. (This may be disabled by
3663// the titeInhibit resource). This combines the effects of the 1
3664// 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based
3665// applications rather than the 4 7 mode.
3666// Ps = 1 0 5 0 -> Set terminfo/termcap function-key mode.
3667// Ps = 1 0 5 1 -> Set Sun function-key mode.
3668// Ps = 1 0 5 2 -> Set HP function-key mode.
3669// Ps = 1 0 5 3 -> Set SCO function-key mode.
3670// Ps = 1 0 6 0 -> Set legacy keyboard emulation (X11R6).
3671// Ps = 1 0 6 1 -> Set VT220 keyboard emulation.
3672// Ps = 2 0 0 4 -> Set bracketed paste mode.
3673// Modes:
3674// http://vt100.net/docs/vt220-rm/chapter4.html
3675Terminal.prototype.setMode = function(params) {
3676 if (typeof params === 'object') {
3677 var l = params.length
3678 , i = 0;
3679
3680 for (; i < l; i++) {
3681 this.setMode(params[i]);
3682 }
3683
3684 return;
3685 }
3686
3687 if (!this.prefix) {
3688 switch (params) {
3689 case 4:
3690 this.insertMode = true;
3691 break;
3692 case 20:
3693 //this.convertEol = true;
3694 break;
3695 }
3696 } else if (this.prefix === '?') {
3697 switch (params) {
3698 case 1:
3699 this.applicationCursor = true;
3700 break;
3701 case 2:
3702 this.setgCharset(0, Terminal.charsets.US);
3703 this.setgCharset(1, Terminal.charsets.US);
3704 this.setgCharset(2, Terminal.charsets.US);
3705 this.setgCharset(3, Terminal.charsets.US);
3706 // set VT100 mode here
3707 break;
3708 case 3: // 132 col mode
3709 this.savedCols = this.cols;
3710 this.resize(132, this.rows);
3711 break;
3712 case 6:
3713 this.originMode = true;
3714 break;
3715 case 7:
3716 this.wraparoundMode = true;
3717 break;
3718 case 12:
3719 // this.cursorBlink = true;
3720 break;
3721 case 66:
3722 this.log('Serial port requested application keypad.');
3723 this.applicationKeypad = true;
3724 break;
3725 case 9: // X10 Mouse
3726 // no release, no motion, no wheel, no modifiers.
3727 case 1000: // vt200 mouse
3728 // no motion.
3729 // no modifiers, except control on the wheel.
3730 case 1002: // button event mouse
3731 case 1003: // any event mouse
3732 // any event - sends motion events,
3733 // even if there is no button held down.
3734 this.x10Mouse = params === 9;
3735 this.vt200Mouse = params === 1000;
3736 this.normalMouse = params > 1000;
3737 this.mouseEvents = true;
3738 this.element.style.cursor = 'default';
3739 this.log('Binding to mouse events.');
3740 break;
3741 case 1004: // send focusin/focusout events
3742 // focusin: ^[[I
3743 // focusout: ^[[O
3744 this.sendFocus = true;
3745 break;
3746 case 1005: // utf8 ext mode mouse
3747 this.utfMouse = true;
3748 // for wide terminals
3749 // simply encodes large values as utf8 characters
3750 break;
3751 case 1006: // sgr ext mode mouse
3752 this.sgrMouse = true;
3753 // for wide terminals
3754 // does not add 32 to fields
3755 // press: ^[[<b;x;yM
3756 // release: ^[[<b;x;ym
3757 break;
3758 case 1015: // urxvt ext mode mouse
3759 this.urxvtMouse = true;
3760 // for wide terminals
3761 // numbers for fields
3762 // press: ^[[b;x;yM
3763 // motion: ^[[b;x;yT
3764 break;
3765 case 25: // show cursor
3766 this.cursorHidden = false;
3767 break;
3768 case 1049: // alt screen buffer cursor
3769 //this.saveCursor();
3770 ; // FALL-THROUGH
3771 case 47: // alt screen buffer
3772 case 1047: // alt screen buffer
3773 if (!this.normal) {
3774 var normal = {
3775 lines: this.lines,
3776 ybase: this.ybase,
3777 ydisp: this.ydisp,
3778 x: this.x,
3779 y: this.y,
3780 scrollTop: this.scrollTop,
3781 scrollBottom: this.scrollBottom,
3782 tabs: this.tabs
3783 // XXX save charset(s) here?
3784 // charset: this.charset,
3785 // glevel: this.glevel,
3786 // charsets: this.charsets
3787 };
3788 this.reset();
3789 this.normal = normal;
3790 this.showCursor();
3791 }
3792 break;
3793 }
3794 }
3795};
3796
3797// CSI Pm l Reset Mode (RM).
3798// Ps = 2 -> Keyboard Action Mode (AM).
3799// Ps = 4 -> Replace Mode (IRM).
3800// Ps = 1 2 -> Send/receive (SRM).
3801// Ps = 2 0 -> Normal Linefeed (LNM).
3802// CSI ? Pm l
3803// DEC Private Mode Reset (DECRST).
3804// Ps = 1 -> Normal Cursor Keys (DECCKM).
3805// Ps = 2 -> Designate VT52 mode (DECANM).
3806// Ps = 3 -> 80 Column Mode (DECCOLM).
3807// Ps = 4 -> Jump (Fast) Scroll (DECSCLM).
3808// Ps = 5 -> Normal Video (DECSCNM).
3809// Ps = 6 -> Normal Cursor Mode (DECOM).
3810// Ps = 7 -> No Wraparound Mode (DECAWM).
3811// Ps = 8 -> No Auto-repeat Keys (DECARM).
3812// Ps = 9 -> Don't send Mouse X & Y on button press.
3813// Ps = 1 0 -> Hide toolbar (rxvt).
3814// Ps = 1 2 -> Stop Blinking Cursor (att610).
3815// Ps = 1 8 -> Don't print form feed (DECPFF).
3816// Ps = 1 9 -> Limit print to scrolling region (DECPEX).
3817// Ps = 2 5 -> Hide Cursor (DECTCEM).
3818// Ps = 3 0 -> Don't show scrollbar (rxvt).
3819// Ps = 3 5 -> Disable font-shifting functions (rxvt).
3820// Ps = 4 0 -> Disallow 80 -> 132 Mode.
3821// Ps = 4 1 -> No more(1) fix (see curses resource).
3822// Ps = 4 2 -> Disable Nation Replacement Character sets (DEC-
3823// NRCM).
3824// Ps = 4 4 -> Turn Off Margin Bell.
3825// Ps = 4 5 -> No Reverse-wraparound Mode.
3826// Ps = 4 6 -> Stop Logging. (This is normally disabled by a
3827// compile-time option).
3828// Ps = 4 7 -> Use Normal Screen Buffer.
3829// Ps = 6 6 -> Numeric keypad (DECNKM).
3830// Ps = 6 7 -> Backarrow key sends delete (DECBKM).
3831// Ps = 1 0 0 0 -> Don't send Mouse X & Y on button press and
3832// release. See the section Mouse Tracking.
3833// Ps = 1 0 0 1 -> Don't use Hilite Mouse Tracking.
3834// Ps = 1 0 0 2 -> Don't use Cell Motion Mouse Tracking.
3835// Ps = 1 0 0 3 -> Don't use All Motion Mouse Tracking.
3836// Ps = 1 0 0 4 -> Don't send FocusIn/FocusOut events.
3837// Ps = 1 0 0 5 -> Disable Extended Mouse Mode.
3838// Ps = 1 0 1 0 -> Don't scroll to bottom on tty output
3839// (rxvt).
3840// Ps = 1 0 1 1 -> Don't scroll to bottom on key press (rxvt).
3841// Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables
3842// the eightBitInput resource).
3843// Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num-
3844// Lock keys. (This disables the numLock resource).
3845// Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key.
3846// (This disables the metaSendsEscape resource).
3847// Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad
3848// Delete key.
3849// Ps = 1 0 3 9 -> Don't send ESC when Alt modifies a key.
3850// (This disables the altSendsEscape resource).
3851// Ps = 1 0 4 0 -> Do not keep selection when not highlighted.
3852// (This disables the keepSelection resource).
3853// Ps = 1 0 4 1 -> Use the PRIMARY selection. (This disables
3854// the selectToClipboard resource).
3855// Ps = 1 0 4 2 -> Disable Urgency window manager hint when
3856// Control-G is received. (This disables the bellIsUrgent
3857// resource).
3858// Ps = 1 0 4 3 -> Disable raising of the window when Control-
3859// G is received. (This disables the popOnBell resource).
3860// Ps = 1 0 4 7 -> Use Normal Screen Buffer, clearing screen
3861// first if in the Alternate Screen. (This may be disabled by
3862// the titeInhibit resource).
3863// Ps = 1 0 4 8 -> Restore cursor as in DECRC. (This may be
3864// disabled by the titeInhibit resource).
3865// Ps = 1 0 4 9 -> Use Normal Screen Buffer and restore cursor
3866// as in DECRC. (This may be disabled by the titeInhibit
3867// resource). This combines the effects of the 1 0 4 7 and 1 0
3868// 4 8 modes. Use this with terminfo-based applications rather
3869// than the 4 7 mode.
3870// Ps = 1 0 5 0 -> Reset terminfo/termcap function-key mode.
3871// Ps = 1 0 5 1 -> Reset Sun function-key mode.
3872// Ps = 1 0 5 2 -> Reset HP function-key mode.
3873// Ps = 1 0 5 3 -> Reset SCO function-key mode.
3874// Ps = 1 0 6 0 -> Reset legacy keyboard emulation (X11R6).
3875// Ps = 1 0 6 1 -> Reset keyboard emulation to Sun/PC style.
3876// Ps = 2 0 0 4 -> Reset bracketed paste mode.
3877Terminal.prototype.resetMode = function(params) {
3878 if (typeof params === 'object') {
3879 var l = params.length
3880 , i = 0;
3881
3882 for (; i < l; i++) {
3883 this.resetMode(params[i]);
3884 }
3885
3886 return;
3887 }
3888
3889 if (!this.prefix) {
3890 switch (params) {
3891 case 4:
3892 this.insertMode = false;
3893 break;
3894 case 20:
3895 //this.convertEol = false;
3896 break;
3897 }
3898 } else if (this.prefix === '?') {
3899 switch (params) {
3900 case 1:
3901 this.applicationCursor = false;
3902 break;
3903 case 3:
3904 if (this.cols === 132 && this.savedCols) {
3905 this.resize(this.savedCols, this.rows);
3906 }
3907 delete this.savedCols;
3908 break;
3909 case 6:
3910 this.originMode = false;
3911 break;
3912 case 7:
3913 this.wraparoundMode = false;
3914 break;
3915 case 12:
3916 // this.cursorBlink = false;
3917 break;
3918 case 66:
3919 this.log('Switching back to normal keypad.');
3920 this.applicationKeypad = false;
3921 break;
3922 case 9: // X10 Mouse
3923 case 1000: // vt200 mouse
3924 case 1002: // button event mouse
3925 case 1003: // any event mouse
3926 this.x10Mouse = false;
3927 this.vt200Mouse = false;
3928 this.normalMouse = false;
3929 this.mouseEvents = false;
3930 this.element.style.cursor = '';
3931 break;
3932 case 1004: // send focusin/focusout events
3933 this.sendFocus = false;
3934 break;
3935 case 1005: // utf8 ext mode mouse
3936 this.utfMouse = false;
3937 break;
3938 case 1006: // sgr ext mode mouse
3939 this.sgrMouse = false;
3940 break;
3941 case 1015: // urxvt ext mode mouse
3942 this.urxvtMouse = false;
3943 break;
3944 case 25: // hide cursor
3945 this.cursorHidden = true;
3946 break;
3947 case 1049: // alt screen buffer cursor
3948 ; // FALL-THROUGH
3949 case 47: // normal screen buffer
3950 case 1047: // normal screen buffer - clearing it first
3951 if (this.normal) {
3952 this.lines = this.normal.lines;
3953 this.ybase = this.normal.ybase;
3954 this.ydisp = this.normal.ydisp;
3955 this.x = this.normal.x;
3956 this.y = this.normal.y;
3957 this.scrollTop = this.normal.scrollTop;
3958 this.scrollBottom = this.normal.scrollBottom;
3959 this.tabs = this.normal.tabs;
3960 this.normal = null;
3961 // if (params === 1049) {
3962 // this.x = this.savedX;
3963 // this.y = this.savedY;
3964 // }
3965 this.refresh(0, this.rows - 1);
3966 this.showCursor();
3967 }
3968 break;
3969 }
3970 }
3971};
3972
3973// CSI Ps ; Ps r
3974// Set Scrolling Region [top;bottom] (default = full size of win-
3975// dow) (DECSTBM).
3976// CSI ? Pm r
3977Terminal.prototype.setScrollRegion = function(params) {
3978 if (this.prefix) return;
3979 this.scrollTop = (params[0] || 1) - 1;
3980 this.scrollBottom = (params[1] || this.rows) - 1;
3981 this.x = 0;
3982 this.y = 0;
3983};
3984
3985// CSI s
3986// Save cursor (ANSI.SYS).
3987Terminal.prototype.saveCursor = function(params) {
3988 this.savedX = this.x;
3989 this.savedY = this.y;
3990};
3991
3992// CSI u
3993// Restore cursor (ANSI.SYS).
3994Terminal.prototype.restoreCursor = function(params) {
3995 this.x = this.savedX || 0;
3996 this.y = this.savedY || 0;
3997};
3998
3999/**
4000 * Lesser Used
4001 */
4002
4003// CSI Ps I
4004// Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
4005Terminal.prototype.cursorForwardTab = function(params) {
4006 var param = params[0] || 1;
4007 while (param--) {
4008 this.x = this.nextStop();
4009 }
4010};
4011
4012// CSI Ps S Scroll up Ps lines (default = 1) (SU).
4013Terminal.prototype.scrollUp = function(params) {
4014 var param = params[0] || 1;
4015 while (param--) {
4016 this.lines.splice(this.ybase + this.scrollTop, 1);
4017 this.lines.splice(this.ybase + this.scrollBottom, 0, this.blankLine());
4018 }
4019 // this.maxRange();
4020 this.updateRange(this.scrollTop);
4021 this.updateRange(this.scrollBottom);
4022};
4023
4024// CSI Ps T Scroll down Ps lines (default = 1) (SD).
4025Terminal.prototype.scrollDown = function(params) {
4026 var param = params[0] || 1;
4027 while (param--) {
4028 this.lines.splice(this.ybase + this.scrollBottom, 1);
4029 this.lines.splice(this.ybase + this.scrollTop, 0, this.blankLine());
4030 }
4031 // this.maxRange();
4032 this.updateRange(this.scrollTop);
4033 this.updateRange(this.scrollBottom);
4034};
4035
4036// CSI Ps ; Ps ; Ps ; Ps ; Ps T
4037// Initiate highlight mouse tracking. Parameters are
4038// [func;startx;starty;firstrow;lastrow]. See the section Mouse
4039// Tracking.
4040Terminal.prototype.initMouseTracking = function(params) {
4041 // Relevant: DECSET 1001
4042};
4043
4044// CSI > Ps; Ps T
4045// Reset one or more features of the title modes to the default
4046// value. Normally, "reset" disables the feature. It is possi-
4047// ble to disable the ability to reset features by compiling a
4048// different default for the title modes into xterm.
4049// Ps = 0 -> Do not set window/icon labels using hexadecimal.
4050// Ps = 1 -> Do not query window/icon labels using hexadeci-
4051// mal.
4052// Ps = 2 -> Do not set window/icon labels using UTF-8.
4053// Ps = 3 -> Do not query window/icon labels using UTF-8.
4054// (See discussion of "Title Modes").
4055Terminal.prototype.resetTitleModes = function(params) {
4056 ;
4057};
4058
4059// CSI Ps Z Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
4060Terminal.prototype.cursorBackwardTab = function(params) {
4061 var param = params[0] || 1;
4062 while (param--) {
4063 this.x = this.prevStop();
4064 }
4065};
4066
4067// CSI Ps b Repeat the preceding graphic character Ps times (REP).
4068Terminal.prototype.repeatPrecedingCharacter = function(params) {
4069 var param = params[0] || 1
4070 , line = this.lines[this.ybase + this.y]
4071 , ch = line[this.x - 1] || [this.defAttr, ' '];
4072
4073 while (param--) line[this.x++] = ch;
4074};
4075
4076// CSI Ps g Tab Clear (TBC).
4077// Ps = 0 -> Clear Current Column (default).
4078// Ps = 3 -> Clear All.
4079// Potentially:
4080// Ps = 2 -> Clear Stops on Line.
4081// http://vt100.net/annarbor/aaa-ug/section6.html
4082Terminal.prototype.tabClear = function(params) {
4083 var param = params[0];
4084 if (param <= 0) {
4085 delete this.tabs[this.x];
4086 } else if (param === 3) {
4087 this.tabs = {};
4088 }
4089};
4090
4091// CSI Pm i Media Copy (MC).
4092// Ps = 0 -> Print screen (default).
4093// Ps = 4 -> Turn off printer controller mode.
4094// Ps = 5 -> Turn on printer controller mode.
4095// CSI ? Pm i
4096// Media Copy (MC, DEC-specific).
4097// Ps = 1 -> Print line containing cursor.
4098// Ps = 4 -> Turn off autoprint mode.
4099// Ps = 5 -> Turn on autoprint mode.
4100// Ps = 1 0 -> Print composed display, ignores DECPEX.
4101// Ps = 1 1 -> Print all pages.
4102Terminal.prototype.mediaCopy = function(params) {
4103 ;
4104};
4105
4106// CSI > Ps; Ps m
4107// Set or reset resource-values used by xterm to decide whether
4108// to construct escape sequences holding information about the
4109// modifiers pressed with a given key. The first parameter iden-
4110// tifies the resource to set/reset. The second parameter is the
4111// value to assign to the resource. If the second parameter is
4112// omitted, the resource is reset to its initial value.
4113// Ps = 1 -> modifyCursorKeys.
4114// Ps = 2 -> modifyFunctionKeys.
4115// Ps = 4 -> modifyOtherKeys.
4116// If no parameters are given, all resources are reset to their
4117// initial values.
4118Terminal.prototype.setResources = function(params) {
4119 ;
4120};
4121
4122// CSI > Ps n
4123// Disable modifiers which may be enabled via the CSI > Ps; Ps m
4124// sequence. This corresponds to a resource value of "-1", which
4125// cannot be set with the other sequence. The parameter identi-
4126// fies the resource to be disabled:
4127// Ps = 1 -> modifyCursorKeys.
4128// Ps = 2 -> modifyFunctionKeys.
4129// Ps = 4 -> modifyOtherKeys.
4130// If the parameter is omitted, modifyFunctionKeys is disabled.
4131// When modifyFunctionKeys is disabled, xterm uses the modifier
4132// keys to make an extended sequence of functions rather than
4133// adding a parameter to each function key to denote the modi-
4134// fiers.
4135Terminal.prototype.disableModifiers = function(params) {
4136 ;
4137};
4138
4139// CSI > Ps p
4140// Set resource value pointerMode. This is used by xterm to
4141// decide whether to hide the pointer cursor as the user types.
4142// Valid values for the parameter:
4143// Ps = 0 -> never hide the pointer.
4144// Ps = 1 -> hide if the mouse tracking mode is not enabled.
4145// Ps = 2 -> always hide the pointer. If no parameter is
4146// given, xterm uses the default, which is 1 .
4147Terminal.prototype.setPointerMode = function(params) {
4148 ;
4149};
4150
4151// CSI ! p Soft terminal reset (DECSTR).
4152// http://vt100.net/docs/vt220-rm/table4-10.html
4153Terminal.prototype.softReset = function(params) {
4154 this.cursorHidden = false;
4155 this.insertMode = false;
4156 this.originMode = false;
4157 this.wraparoundMode = false; // autowrap
4158 this.applicationKeypad = false; // ?
4159 this.applicationCursor = false;
4160 this.scrollTop = 0;
4161 this.scrollBottom = this.rows - 1;
4162 this.curAttr = this.defAttr;
4163 this.x = this.y = 0; // ?
4164 this.charset = null;
4165 this.glevel = 0; // ??
4166 this.charsets = [null]; // ??
4167};
4168
4169// CSI Ps$ p
4170// Request ANSI mode (DECRQM). For VT300 and up, reply is
4171// CSI Ps; Pm$ y
4172// where Ps is the mode number as in RM, and Pm is the mode
4173// value:
4174// 0 - not recognized
4175// 1 - set
4176// 2 - reset
4177// 3 - permanently set
4178// 4 - permanently reset
4179Terminal.prototype.requestAnsiMode = function(params) {
4180 ;
4181};
4182
4183// CSI ? Ps$ p
4184// Request DEC private mode (DECRQM). For VT300 and up, reply is
4185// CSI ? Ps; Pm$ p
4186// where Ps is the mode number as in DECSET, Pm is the mode value
4187// as in the ANSI DECRQM.
4188Terminal.prototype.requestPrivateMode = function(params) {
4189 ;
4190};
4191
4192// CSI Ps ; Ps " p
4193// Set conformance level (DECSCL). Valid values for the first
4194// parameter:
4195// Ps = 6 1 -> VT100.
4196// Ps = 6 2 -> VT200.
4197// Ps = 6 3 -> VT300.
4198// Valid values for the second parameter:
4199// Ps = 0 -> 8-bit controls.
4200// Ps = 1 -> 7-bit controls (always set for VT100).
4201// Ps = 2 -> 8-bit controls.
4202Terminal.prototype.setConformanceLevel = function(params) {
4203 ;
4204};
4205
4206// CSI Ps q Load LEDs (DECLL).
4207// Ps = 0 -> Clear all LEDS (default).
4208// Ps = 1 -> Light Num Lock.
4209// Ps = 2 -> Light Caps Lock.
4210// Ps = 3 -> Light Scroll Lock.
4211// Ps = 2 1 -> Extinguish Num Lock.
4212// Ps = 2 2 -> Extinguish Caps Lock.
4213// Ps = 2 3 -> Extinguish Scroll Lock.
4214Terminal.prototype.loadLEDs = function(params) {
4215 ;
4216};
4217
4218// CSI Ps SP q
4219// Set cursor style (DECSCUSR, VT520).
4220// Ps = 0 -> blinking block.
4221// Ps = 1 -> blinking block (default).
4222// Ps = 2 -> steady block.
4223// Ps = 3 -> blinking underline.
4224// Ps = 4 -> steady underline.
4225Terminal.prototype.setCursorStyle = function(params) {
4226 ;
4227};
4228
4229// CSI Ps " q
4230// Select character protection attribute (DECSCA). Valid values
4231// for the parameter:
4232// Ps = 0 -> DECSED and DECSEL can erase (default).
4233// Ps = 1 -> DECSED and DECSEL cannot erase.
4234// Ps = 2 -> DECSED and DECSEL can erase.
4235Terminal.prototype.setCharProtectionAttr = function(params) {
4236 ;
4237};
4238
4239// CSI ? Pm r
4240// Restore DEC Private Mode Values. The value of Ps previously
4241// saved is restored. Ps values are the same as for DECSET.
4242Terminal.prototype.restorePrivateValues = function(params) {
4243 ;
4244};
4245
4246// CSI Pt; Pl; Pb; Pr; Ps$ r
4247// Change Attributes in Rectangular Area (DECCARA), VT400 and up.
4248// Pt; Pl; Pb; Pr denotes the rectangle.
4249// Ps denotes the SGR attributes to change: 0, 1, 4, 5, 7.
4250// NOTE: xterm doesn't enable this code by default.
4251Terminal.prototype.setAttrInRectangle = function(params) {
4252 var t = params[0]
4253 , l = params[1]
4254 , b = params[2]
4255 , r = params[3]
4256 , attr = params[4];
4257
4258 var line
4259 , i;
4260
4261 for (; t < b + 1; t++) {
4262 line = this.lines[this.ybase + t];
4263 for (i = l; i < r; i++) {
4264 line[i] = [attr, line[i][1]];
4265 }
8bc844c0 4266 }
9e6cb6b6
CJ
4267
4268 // this.maxRange();
4269 this.updateRange(params[0]);
4270 this.updateRange(params[2]);
4271};
4272
4273// CSI ? Pm s
4274// Save DEC Private Mode Values. Ps values are the same as for
4275// DECSET.
4276Terminal.prototype.savePrivateValues = function(params) {
4277 ;
4278};
4279
4280// CSI Ps ; Ps ; Ps t
4281// Window manipulation (from dtterm, as well as extensions).
4282// These controls may be disabled using the allowWindowOps
4283// resource. Valid values for the first (and any additional
4284// parameters) are:
4285// Ps = 1 -> De-iconify window.
4286// Ps = 2 -> Iconify window.
4287// Ps = 3 ; x ; y -> Move window to [x, y].
4288// Ps = 4 ; height ; width -> Resize the xterm window to
4289// height and width in pixels.
4290// Ps = 5 -> Raise the xterm window to the front of the stack-
4291// ing order.
4292// Ps = 6 -> Lower the xterm window to the bottom of the
4293// stacking order.
4294// Ps = 7 -> Refresh the xterm window.
4295// Ps = 8 ; height ; width -> Resize the text area to
4296// [height;width] in characters.
4297// Ps = 9 ; 0 -> Restore maximized window.
4298// Ps = 9 ; 1 -> Maximize window (i.e., resize to screen
4299// size).
4300// Ps = 1 0 ; 0 -> Undo full-screen mode.
4301// Ps = 1 0 ; 1 -> Change to full-screen.
4302// Ps = 1 1 -> Report xterm window state. If the xterm window
4303// is open (non-iconified), it returns CSI 1 t . If the xterm
4304// window is iconified, it returns CSI 2 t .
4305// Ps = 1 3 -> Report xterm window position. Result is CSI 3
4306// ; x ; y t
4307// Ps = 1 4 -> Report xterm window in pixels. Result is CSI
4308// 4 ; height ; width t
4309// Ps = 1 8 -> Report the size of the text area in characters.
4310// Result is CSI 8 ; height ; width t
4311// Ps = 1 9 -> Report the size of the screen in characters.
4312// Result is CSI 9 ; height ; width t
4313// Ps = 2 0 -> Report xterm window's icon label. Result is
4314// OSC L label ST
4315// Ps = 2 1 -> Report xterm window's title. Result is OSC l
4316// label ST
4317// Ps = 2 2 ; 0 -> Save xterm icon and window title on
4318// stack.
4319// Ps = 2 2 ; 1 -> Save xterm icon title on stack.
4320// Ps = 2 2 ; 2 -> Save xterm window title on stack.
4321// Ps = 2 3 ; 0 -> Restore xterm icon and window title from
4322// stack.
4323// Ps = 2 3 ; 1 -> Restore xterm icon title from stack.
4324// Ps = 2 3 ; 2 -> Restore xterm window title from stack.
4325// Ps >= 2 4 -> Resize to Ps lines (DECSLPP).
4326Terminal.prototype.manipulateWindow = function(params) {
4327 ;
8bc844c0
CJ
4328};
4329
9e6cb6b6
CJ
4330// CSI Pt; Pl; Pb; Pr; Ps$ t
4331// Reverse Attributes in Rectangular Area (DECRARA), VT400 and
4332// up.
4333// Pt; Pl; Pb; Pr denotes the rectangle.
4334// Ps denotes the attributes to reverse, i.e., 1, 4, 5, 7.
4335// NOTE: xterm doesn't enable this code by default.
4336Terminal.prototype.reverseAttrInRectangle = function(params) {
4337 ;
8bc844c0
CJ
4338};
4339
9e6cb6b6
CJ
4340// CSI > Ps; Ps t
4341// Set one or more features of the title modes. Each parameter
4342// enables a single feature.
4343// Ps = 0 -> Set window/icon labels using hexadecimal.
4344// Ps = 1 -> Query window/icon labels using hexadecimal.
4345// Ps = 2 -> Set window/icon labels using UTF-8.
4346// Ps = 3 -> Query window/icon labels using UTF-8. (See dis-
4347// cussion of "Title Modes")
4348Terminal.prototype.setTitleModeFeature = function(params) {
4349 ;
4350};
8bc844c0 4351
9e6cb6b6
CJ
4352// CSI Ps SP t
4353// Set warning-bell volume (DECSWBV, VT520).
4354// Ps = 0 or 1 -> off.
4355// Ps = 2 , 3 or 4 -> low.
4356// Ps = 5 , 6 , 7 , or 8 -> high.
4357Terminal.prototype.setWarningBellVolume = function(params) {
4358 ;
4359};
8bc844c0 4360
9e6cb6b6
CJ
4361// CSI Ps SP u
4362// Set margin-bell volume (DECSMBV, VT520).
4363// Ps = 1 -> off.
4364// Ps = 2 , 3 or 4 -> low.
4365// Ps = 0 , 5 , 6 , 7 , or 8 -> high.
4366Terminal.prototype.setMarginBellVolume = function(params) {
4367 ;
4368};
15f68335 4369
9e6cb6b6
CJ
4370// CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v
4371// Copy Rectangular Area (DECCRA, VT400 and up).
4372// Pt; Pl; Pb; Pr denotes the rectangle.
4373// Pp denotes the source page.
4374// Pt; Pl denotes the target location.
4375// Pp denotes the target page.
4376// NOTE: xterm doesn't enable this code by default.
4377Terminal.prototype.copyRectangle = function(params) {
4378 ;
4379};
8bc844c0 4380
9e6cb6b6
CJ
4381// CSI Pt ; Pl ; Pb ; Pr ' w
4382// Enable Filter Rectangle (DECEFR), VT420 and up.
4383// Parameters are [top;left;bottom;right].
4384// Defines the coordinates of a filter rectangle and activates
4385// it. Anytime the locator is detected outside of the filter
4386// rectangle, an outside rectangle event is generated and the
4387// rectangle is disabled. Filter rectangles are always treated
4388// as "one-shot" events. Any parameters that are omitted default
4389// to the current locator position. If all parameters are omit-
4390// ted, any locator motion will be reported. DECELR always can-
4391// cels any prevous rectangle definition.
4392Terminal.prototype.enableFilterRectangle = function(params) {
4393 ;
4394};
8bc844c0 4395
9e6cb6b6
CJ
4396// CSI Ps x Request Terminal Parameters (DECREQTPARM).
4397// if Ps is a "0" (default) or "1", and xterm is emulating VT100,
4398// the control sequence elicits a response of the same form whose
4399// parameters describe the terminal:
4400// Ps -> the given Ps incremented by 2.
4401// Pn = 1 <- no parity.
4402// Pn = 1 <- eight bits.
4403// Pn = 1 <- 2 8 transmit 38.4k baud.
4404// Pn = 1 <- 2 8 receive 38.4k baud.
4405// Pn = 1 <- clock multiplier.
4406// Pn = 0 <- STP flags.
4407Terminal.prototype.requestParameters = function(params) {
4408 ;
8bc844c0
CJ
4409};
4410
9e6cb6b6
CJ
4411// CSI Ps x Select Attribute Change Extent (DECSACE).
4412// Ps = 0 -> from start to end position, wrapped.
4413// Ps = 1 -> from start to end position, wrapped.
4414// Ps = 2 -> rectangle (exact).
4415Terminal.prototype.selectChangeExtent = function(params) {
4416 ;
4417};
4418
4419// CSI Pc; Pt; Pl; Pb; Pr$ x
4420// Fill Rectangular Area (DECFRA), VT420 and up.
4421// Pc is the character to use.
4422// Pt; Pl; Pb; Pr denotes the rectangle.
4423// NOTE: xterm doesn't enable this code by default.
4424Terminal.prototype.fillRectangle = function(params) {
4425 var ch = params[0]
4426 , t = params[1]
4427 , l = params[2]
4428 , b = params[3]
4429 , r = params[4];
4430
4431 var line
4432 , i;
4433
4434 for (; t < b + 1; t++) {
4435 line = this.lines[this.ybase + t];
4436 for (i = l; i < r; i++) {
4437 line[i] = [line[i][0], String.fromCharCode(ch)];
8bc844c0
CJ
4438 }
4439 }
9e6cb6b6
CJ
4440
4441 // this.maxRange();
4442 this.updateRange(params[1]);
4443 this.updateRange(params[3]);
8bc844c0
CJ
4444};
4445
9e6cb6b6
CJ
4446// CSI Ps ; Pu ' z
4447// Enable Locator Reporting (DECELR).
4448// Valid values for the first parameter:
4449// Ps = 0 -> Locator disabled (default).
4450// Ps = 1 -> Locator enabled.
4451// Ps = 2 -> Locator enabled for one report, then disabled.
4452// The second parameter specifies the coordinate unit for locator
4453// reports.
4454// Valid values for the second parameter:
4455// Pu = 0 <- or omitted -> default to character cells.
4456// Pu = 1 <- device physical pixels.
4457// Pu = 2 <- character cells.
4458Terminal.prototype.enableLocatorReporting = function(params) {
4459 var val = params[0] > 0;
4460 //this.mouseEvents = val;
4461 //this.decLocator = val;
4462};
8bc844c0 4463
9e6cb6b6
CJ
4464// CSI Pt; Pl; Pb; Pr$ z
4465// Erase Rectangular Area (DECERA), VT400 and up.
4466// Pt; Pl; Pb; Pr denotes the rectangle.
4467// NOTE: xterm doesn't enable this code by default.
4468Terminal.prototype.eraseRectangle = function(params) {
4469 var t = params[0]
4470 , l = params[1]
4471 , b = params[2]
4472 , r = params[3];
8bc844c0 4473
9e6cb6b6
CJ
4474 var line
4475 , i
4476 , ch;
8bc844c0 4477
9e6cb6b6 4478 ch = [this.eraseAttr(), ' ']; // xterm?
8bc844c0 4479
9e6cb6b6
CJ
4480 for (; t < b + 1; t++) {
4481 line = this.lines[this.ybase + t];
4482 for (i = l; i < r; i++) {
4483 line[i] = ch;
4484 }
8bc844c0 4485 }
8bc844c0 4486
9e6cb6b6
CJ
4487 // this.maxRange();
4488 this.updateRange(params[0]);
4489 this.updateRange(params[2]);
8bc844c0
CJ
4490};
4491
9e6cb6b6
CJ
4492// CSI Pm ' {
4493// Select Locator Events (DECSLE).
4494// Valid values for the first (and any additional parameters)
4495// are:
4496// Ps = 0 -> only respond to explicit host requests (DECRQLP).
4497// (This is default). It also cancels any filter
4498// rectangle.
4499// Ps = 1 -> report button down transitions.
4500// Ps = 2 -> do not report button down transitions.
4501// Ps = 3 -> report button up transitions.
4502// Ps = 4 -> do not report button up transitions.
4503Terminal.prototype.setLocatorEvents = function(params) {
4504 ;
8bc844c0
CJ
4505};
4506
9e6cb6b6
CJ
4507// CSI Pt; Pl; Pb; Pr$ {
4508// Selective Erase Rectangular Area (DECSERA), VT400 and up.
4509// Pt; Pl; Pb; Pr denotes the rectangle.
4510Terminal.prototype.selectiveEraseRectangle = function(params) {
4511 ;
8bc844c0
CJ
4512};
4513
9e6cb6b6
CJ
4514// CSI Ps ' |
4515// Request Locator Position (DECRQLP).
4516// Valid values for the parameter are:
4517// Ps = 0 , 1 or omitted -> transmit a single DECLRP locator
4518// report.
8bc844c0 4519
9e6cb6b6
CJ
4520// If Locator Reporting has been enabled by a DECELR, xterm will
4521// respond with a DECLRP Locator Report. This report is also
4522// generated on button up and down events if they have been
4523// enabled with a DECSLE, or when the locator is detected outside
4524// of a filter rectangle, if filter rectangles have been enabled
4525// with a DECEFR.
4526
4527// -> CSI Pe ; Pb ; Pr ; Pc ; Pp & w
4528
4529// Parameters are [event;button;row;column;page].
4530// Valid values for the event:
4531// Pe = 0 -> locator unavailable - no other parameters sent.
4532// Pe = 1 -> request - xterm received a DECRQLP.
4533// Pe = 2 -> left button down.
4534// Pe = 3 -> left button up.
4535// Pe = 4 -> middle button down.
4536// Pe = 5 -> middle button up.
4537// Pe = 6 -> right button down.
4538// Pe = 7 -> right button up.
4539// Pe = 8 -> M4 button down.
4540// Pe = 9 -> M4 button up.
4541// Pe = 1 0 -> locator outside filter rectangle.
4542// ``button'' parameter is a bitmask indicating which buttons are
4543// pressed:
4544// Pb = 0 <- no buttons down.
4545// Pb & 1 <- right button down.
4546// Pb & 2 <- middle button down.
4547// Pb & 4 <- left button down.
4548// Pb & 8 <- M4 button down.
4549// ``row'' and ``column'' parameters are the coordinates of the
4550// locator position in the xterm window, encoded as ASCII deci-
4551// mal.
4552// The ``page'' parameter is not used by xterm, and will be omit-
4553// ted.
4554Terminal.prototype.requestLocatorPosition = function(params) {
4555 ;
4556};
8bc844c0 4557
9e6cb6b6
CJ
4558// CSI P m SP }
4559// Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
4560// NOTE: xterm doesn't enable this code by default.
4561Terminal.prototype.insertColumns = function() {
4562 var param = params[0]
4563 , l = this.ybase + this.rows
4564 , ch = [this.eraseAttr(), ' '] // xterm?
4565 , i;
8bc844c0
CJ
4566
4567 while (param--) {
9e6cb6b6
CJ
4568 for (i = this.ybase; i < l; i++) {
4569 this.lines[i].splice(this.x + 1, 0, ch);
4570 this.lines[i].pop();
4571 }
8bc844c0
CJ
4572 }
4573
9e6cb6b6 4574 this.maxRange();
8bc844c0
CJ
4575};
4576
9e6cb6b6
CJ
4577// CSI P m SP ~
4578// Delete P s Column(s) (default = 1) (DECDC), VT420 and up
4579// NOTE: xterm doesn't enable this code by default.
4580Terminal.prototype.deleteColumns = function() {
4581 var param = params[0]
4582 , l = this.ybase + this.rows
4583 , ch = [this.eraseAttr(), ' '] // xterm?
4584 , i;
8bc844c0
CJ
4585
4586 while (param--) {
9e6cb6b6
CJ
4587 for (i = this.ybase; i < l; i++) {
4588 this.lines[i].splice(this.x, 1);
4589 this.lines[i].push(ch);
4590 }
8bc844c0
CJ
4591 }
4592
9e6cb6b6 4593 this.maxRange();
8bc844c0
CJ
4594};
4595
9e6cb6b6
CJ
4596/**
4597 * Prefix/Select/Visual/Search Modes
4598 */
8bc844c0 4599
9e6cb6b6
CJ
4600Terminal.prototype.enterPrefix = function() {
4601 this.prefixMode = true;
4602};
8bc844c0 4603
9e6cb6b6
CJ
4604Terminal.prototype.leavePrefix = function() {
4605 this.prefixMode = false;
8bc844c0
CJ
4606};
4607
9e6cb6b6
CJ
4608Terminal.prototype.enterSelect = function() {
4609 this._real = {
4610 x: this.x,
4611 y: this.y,
4612 ydisp: this.ydisp,
4613 ybase: this.ybase,
4614 cursorHidden: this.cursorHidden,
4615 lines: this.copyBuffer(this.lines),
4616 write: this.write
4617 };
4618 this.write = function() {};
4619 this.selectMode = true;
4620 this.visualMode = false;
4621 this.cursorHidden = false;
4622 this.refresh(this.y, this.y);
4623};
8bc844c0 4624
9e6cb6b6
CJ
4625Terminal.prototype.leaveSelect = function() {
4626 this.x = this._real.x;
4627 this.y = this._real.y;
4628 this.ydisp = this._real.ydisp;
4629 this.ybase = this._real.ybase;
4630 this.cursorHidden = this._real.cursorHidden;
4631 this.lines = this._real.lines;
4632 this.write = this._real.write;
4633 delete this._real;
4634 this.selectMode = false;
4635 this.visualMode = false;
4636 this.refresh(0, this.rows - 1);
4637};
8bc844c0 4638
9e6cb6b6
CJ
4639Terminal.prototype.enterVisual = function() {
4640 this._real.preVisual = this.copyBuffer(this.lines);
4641 this.selectText(this.x, this.x, this.ydisp + this.y, this.ydisp + this.y);
4642 this.visualMode = true;
4643};
8bc844c0 4644
9e6cb6b6
CJ
4645Terminal.prototype.leaveVisual = function() {
4646 this.lines = this._real.preVisual;
4647 delete this._real.preVisual;
4648 delete this._selected;
4649 this.visualMode = false;
4650 this.refresh(0, this.rows - 1);
8bc844c0
CJ
4651};
4652
9e6cb6b6
CJ
4653Terminal.prototype.enterSearch = function(down) {
4654 this.entry = '';
4655 this.searchMode = true;
4656 this.searchDown = down;
4657 this._real.preSearch = this.copyBuffer(this.lines);
4658 this._real.preSearchX = this.x;
4659 this._real.preSearchY = this.y;
4660 this.entryPrefix = 'Search: ';
4661 var bottom = this.ydisp + this.rows - 1;
4662 for (var i = 0; i < this.entryPrefix.length; i++) {
4663 //this.lines[bottom][i][0] = (this.defAttr & ~0x1ff) | 4;
4664 //this.lines[bottom][i][1] = this.entryPrefix[i];
4665 this.lines[bottom][i] = [
4666 (this.defAttr & ~0x1ff) | 4,
4667 this.entryPrefix[i]
4668 ];
8bc844c0 4669 }
9e6cb6b6
CJ
4670 this.y = this.rows - 1;
4671 this.x = this.entryPrefix.length;
4672 this.refresh(this.rows - 1, this.rows - 1);
8bc844c0
CJ
4673};
4674
9e6cb6b6
CJ
4675Terminal.prototype.leaveSearch = function() {
4676 this.searchMode = false;
4677
4678 if (this._real.preSearch) {
4679 this.lines = this._real.preSearch;
4680 this.x = this._real.preSearchX;
4681 this.y = this._real.preSearchY;
4682 delete this._real.preSearch;
4683 delete this._real.preSearchX;
4684 delete this._real.preSearchY;
8bc844c0 4685 }
9e6cb6b6
CJ
4686
4687 this.refresh(this.rows - 1, this.rows - 1);
8bc844c0
CJ
4688};
4689
9e6cb6b6
CJ
4690Terminal.prototype.copyBuffer = function(lines) {
4691 var lines = lines || this.lines
4692 , out = [];
8bc844c0 4693
9e6cb6b6
CJ
4694 for (var y = 0; y < lines.length; y++) {
4695 out[y] = [];
4696 for (var x = 0; x < lines[y].length; x++) {
4697 out[y][x] = [lines[y][x][0], lines[y][x][1]];
8bc844c0
CJ
4698 }
4699 }
9e6cb6b6
CJ
4700
4701 return out;
8bc844c0
CJ
4702};
4703
9e6cb6b6
CJ
4704Terminal.prototype.getCopyTextarea = function(text) {
4705 var textarea = this._copyTextarea
4706 , document = this.document;
4707
4708 if (!textarea) {
4709 textarea = document.createElement('textarea');
4710 textarea.style.position = 'absolute';
4711 textarea.style.left = '-32000px';
4712 textarea.style.top = '-32000px';
5d3f8786
CJ
4713 textarea.style.width = '0px';
4714 textarea.style.height = '0px';
9e6cb6b6
CJ
4715 textarea.style.opacity = '0';
4716 textarea.style.backgroundColor = 'transparent';
4717 textarea.style.borderStyle = 'none';
4718 textarea.style.outlineStyle = 'none';
4719
4720 document.getElementsByTagName('body')[0].appendChild(textarea);
4721
4722 this._copyTextarea = textarea;
8bc844c0 4723 }
9e6cb6b6
CJ
4724
4725 return textarea;
8bc844c0
CJ
4726};
4727
9e6cb6b6
CJ
4728// NOTE: Only works for primary selection on X11.
4729// Non-X11 users should use Ctrl-C instead.
4730Terminal.prototype.copyText = function(text) {
4731 var self = this
4732 , textarea = this.getCopyTextarea();
4733
4734 this.emit('copy', text);
4735
4736 textarea.focus();
4737 textarea.textContent = text;
4738 textarea.value = text;
4739 textarea.setSelectionRange(0, text.length);
4740
4741 setTimeout(function() {
4742 self.element.focus();
4743 self.focus();
4744 }, 1);
8bc844c0
CJ
4745};
4746
9e6cb6b6
CJ
4747Terminal.prototype.selectText = function(x1, x2, y1, y2) {
4748 var ox1
4749 , ox2
4750 , oy1
4751 , oy2
4752 , tmp
4753 , x
4754 , y
4755 , xl
4756 , attr;
8bc844c0 4757
9e6cb6b6
CJ
4758 if (this._selected) {
4759 ox1 = this._selected.x1;
4760 ox2 = this._selected.x2;
4761 oy1 = this._selected.y1;
4762 oy2 = this._selected.y2;
8bc844c0 4763
9e6cb6b6
CJ
4764 if (oy2 < oy1) {
4765 tmp = ox2;
4766 ox2 = ox1;
4767 ox1 = tmp;
4768 tmp = oy2;
4769 oy2 = oy1;
4770 oy1 = tmp;
4771 }
8bc844c0 4772
9e6cb6b6
CJ
4773 if (ox2 < ox1 && oy1 === oy2) {
4774 tmp = ox2;
4775 ox2 = ox1;
4776 ox1 = tmp;
4777 }
8bc844c0 4778
9e6cb6b6
CJ
4779 for (y = oy1; y <= oy2; y++) {
4780 x = 0;
5d3f8786 4781 xl = this.cols - 1;
9e6cb6b6
CJ
4782 if (y === oy1) {
4783 x = ox1;
4784 }
4785 if (y === oy2) {
4786 xl = ox2;
4787 }
5d3f8786 4788 for (; x <= xl; x++) {
9e6cb6b6
CJ
4789 if (this.lines[y][x].old != null) {
4790 //this.lines[y][x][0] = this.lines[y][x].old;
4791 //delete this.lines[y][x].old;
4792 attr = this.lines[y][x].old;
4793 delete this.lines[y][x].old;
4794 this.lines[y][x] = [attr, this.lines[y][x][1]];
4795 }
4796 }
8bc844c0
CJ
4797 }
4798
9e6cb6b6
CJ
4799 y1 = this._selected.y1;
4800 x1 = this._selected.x1;
8bc844c0
CJ
4801 }
4802
9e6cb6b6
CJ
4803 y1 = Math.max(y1, 0);
4804 y1 = Math.min(y1, this.ydisp + this.rows - 1);
4805
4806 y2 = Math.max(y2, 0);
4807 y2 = Math.min(y2, this.ydisp + this.rows - 1);
4808
4809 this._selected = { x1: x1, x2: x2, y1: y1, y2: y2 };
4810
4811 if (y2 < y1) {
4812 tmp = x2;
4813 x2 = x1;
4814 x1 = tmp;
4815 tmp = y2;
4816 y2 = y1;
4817 y1 = tmp;
4818 }
4819
4820 if (x2 < x1 && y1 === y2) {
4821 tmp = x2;
4822 x2 = x1;
4823 x1 = tmp;
4824 }
4825
4826 for (y = y1; y <= y2; y++) {
4827 x = 0;
bcecbcd9 4828 xl = this.cols - 1;
9e6cb6b6
CJ
4829 if (y === y1) {
4830 x = x1;
4831 }
4832 if (y === y2) {
4833 xl = x2;
4834 }
bcecbcd9 4835 for (; x <= xl; x++) {
9e6cb6b6
CJ
4836 //this.lines[y][x].old = this.lines[y][x][0];
4837 //this.lines[y][x][0] &= ~0x1ff;
4838 //this.lines[y][x][0] |= (0x1ff << 9) | 4;
4839 attr = this.lines[y][x][0];
4840 this.lines[y][x] = [
4841 (attr & ~0x1ff) | ((0x1ff << 9) | 4),
4842 this.lines[y][x][1]
4843 ];
4844 this.lines[y][x].old = attr;
8bc844c0
CJ
4845 }
4846 }
9e6cb6b6
CJ
4847
4848 y1 = y1 - this.ydisp;
4849 y2 = y2 - this.ydisp;
4850
4851 y1 = Math.max(y1, 0);
4852 y1 = Math.min(y1, this.rows - 1);
4853
4854 y2 = Math.max(y2, 0);
4855 y2 = Math.min(y2, this.rows - 1);
4856
4857 //this.refresh(y1, y2);
4858 this.refresh(0, this.rows - 1);
8bc844c0
CJ
4859};
4860
9e6cb6b6
CJ
4861Terminal.prototype.grabText = function(x1, x2, y1, y2) {
4862 var out = ''
4863 , buf = ''
4864 , ch
4865 , x
4866 , y
4867 , xl
4868 , tmp;
8bc844c0 4869
9e6cb6b6
CJ
4870 if (y2 < y1) {
4871 tmp = x2;
4872 x2 = x1;
4873 x1 = tmp;
4874 tmp = y2;
4875 y2 = y1;
4876 y1 = tmp;
4877 }
8bc844c0 4878
9e6cb6b6
CJ
4879 if (x2 < x1 && y1 === y2) {
4880 tmp = x2;
4881 x2 = x1;
4882 x1 = tmp;
8bc844c0
CJ
4883 }
4884
9e6cb6b6
CJ
4885 for (y = y1; y <= y2; y++) {
4886 x = 0;
bcecbcd9 4887 xl = this.cols - 1;
9e6cb6b6
CJ
4888 if (y === y1) {
4889 x = x1;
8bc844c0 4890 }
9e6cb6b6
CJ
4891 if (y === y2) {
4892 xl = x2;
4893 }
bcecbcd9 4894 for (; x <= xl; x++) {
9e6cb6b6
CJ
4895 ch = this.lines[y][x][1];
4896 if (ch === ' ') {
4897 buf += ch;
4898 continue;
4899 }
4900 if (buf) {
4901 out += buf;
4902 buf = '';
4903 }
4904 out += ch;
4905 if (isWide(ch)) x++;
4906 }
4907 buf = '';
4908 out += '\n';
4909 }
4910
4911 // If we're not at the end of the
4912 // line, don't add a newline.
bcecbcd9 4913 for (x = x2, y = y2; x < this.cols; x++) {
9e6cb6b6
CJ
4914 if (this.lines[y][x][1] !== ' ') {
4915 out = out.slice(0, -1);
4916 break;
8bc844c0
CJ
4917 }
4918 }
8bc844c0 4919
9e6cb6b6 4920 return out;
8bc844c0
CJ
4921};
4922
9e6cb6b6
CJ
4923Terminal.prototype.keyPrefix = function(ev, key) {
4924 if (key === 'k' || key === '&') {
4925 this.destroy();
4926 } else if (key === 'p' || key === ']') {
4927 this.emit('request paste');
4928 } else if (key === 'c') {
4929 this.emit('request create');
4930 } else if (key >= '0' && key <= '9') {
74848936
CJ
4931 key = +key - 1;
4932 if (!~key) key = 9;
4933 this.emit('request term', key);
9e6cb6b6 4934 } else if (key === 'n') {
74848936 4935 this.emit('request term next');
9e6cb6b6 4936 } else if (key === 'P') {
74848936 4937 this.emit('request term previous');
9e6cb6b6 4938 } else if (key === ':') {
74848936 4939 this.emit('request command mode');
9e6cb6b6
CJ
4940 } else if (key === '[') {
4941 this.enterSelect();
4942 }
8bc844c0
CJ
4943};
4944
9e6cb6b6
CJ
4945Terminal.prototype.keySelect = function(ev, key) {
4946 this.showCursor();
8bc844c0 4947
9e6cb6b6
CJ
4948 if (this.searchMode || key === 'n' || key === 'N') {
4949 return this.keySearch(ev, key);
4950 }
8bc844c0 4951
9e6cb6b6
CJ
4952 if (key === '\x04') { // ctrl-d
4953 var y = this.ydisp + this.y;
4954 if (this.ydisp === this.ybase) {
4955 // Mimic vim behavior
4956 this.y = Math.min(this.y + (this.rows - 1) / 2 | 0, this.rows - 1);
4957 this.refresh(0, this.rows - 1);
4958 } else {
4959 this.scrollDisp((this.rows - 1) / 2 | 0);
4960 }
4961 if (this.visualMode) {
5d3f8786 4962 this.selectText(this.x, this.x, y, this.ydisp + this.y);
9e6cb6b6
CJ
4963 }
4964 return;
8bc844c0 4965 }
8bc844c0 4966
9e6cb6b6
CJ
4967 if (key === '\x15') { // ctrl-u
4968 var y = this.ydisp + this.y;
4969 if (this.ydisp === 0) {
4970 // Mimic vim behavior
4971 this.y = Math.max(this.y - (this.rows - 1) / 2 | 0, 0);
4972 this.refresh(0, this.rows - 1);
4973 } else {
4974 this.scrollDisp(-(this.rows - 1) / 2 | 0);
4975 }
4976 if (this.visualMode) {
4977 this.selectText(this.x, this.x, y, this.ydisp + this.y);
4978 }
4979 return;
8bc844c0 4980 }
8bc844c0 4981
9e6cb6b6
CJ
4982 if (key === '\x06') { // ctrl-f
4983 var y = this.ydisp + this.y;
4984 this.scrollDisp(this.rows - 1);
4985 if (this.visualMode) {
5d3f8786 4986 this.selectText(this.x, this.x, y, this.ydisp + this.y);
9e6cb6b6
CJ
4987 }
4988 return;
8bc844c0 4989 }
8bc844c0 4990
9e6cb6b6
CJ
4991 if (key === '\x02') { // ctrl-b
4992 var y = this.ydisp + this.y;
4993 this.scrollDisp(-(this.rows - 1));
4994 if (this.visualMode) {
4995 this.selectText(this.x, this.x, y, this.ydisp + this.y);
4996 }
4997 return;
4998 }
8bc844c0 4999
9e6cb6b6
CJ
5000 if (key === 'k') {
5001 var y = this.ydisp + this.y;
5002 this.y--;
5003 if (this.y < 0) {
5004 this.y = 0;
5005 this.scrollDisp(-1);
5006 }
5007 if (this.visualMode) {
5d3f8786 5008 this.selectText(this.x, this.x, y, this.ydisp + this.y);
9e6cb6b6
CJ
5009 } else {
5010 this.refresh(this.y, this.y + 1);
5011 }
5012 return;
5013 }
8bc844c0 5014
9e6cb6b6
CJ
5015 if (key === 'j') {
5016 var y = this.ydisp + this.y;
5017 this.y++;
5018 if (this.y >= this.rows) {
5019 this.y = this.rows - 1;
5020 this.scrollDisp(1);
5021 }
5022 if (this.visualMode) {
5023 this.selectText(this.x, this.x, y, this.ydisp + this.y);
5024 } else {
5025 this.refresh(this.y - 1, this.y);
5026 }
5027 return;
8bc844c0 5028 }
8bc844c0 5029
9e6cb6b6
CJ
5030 if (key === 'h') {
5031 var x = this.x;
5032 this.x--;
5033 if (this.x < 0) {
5034 this.x = 0;
5035 }
5036 if (this.visualMode) {
5037 this.selectText(this.x, x, this.ydisp + this.y, this.ydisp + this.y);
5038 } else {
5039 this.refresh(this.y, this.y);
5040 }
5041 return;
5042 }
8bc844c0 5043
9e6cb6b6
CJ
5044 if (key === 'l') {
5045 var x = this.x;
5046 this.x++;
5047 if (this.x >= this.cols) {
5048 this.x = this.cols - 1;
5049 }
5050 if (this.visualMode) {
5051 this.selectText(x, this.x, this.ydisp + this.y, this.ydisp + this.y);
5052 } else {
5053 this.refresh(this.y, this.y);
5054 }
5055 return;
5056 }
8bc844c0 5057
74848936 5058 if (key === 'v' || key === ' ') {
9e6cb6b6
CJ
5059 if (!this.visualMode) {
5060 this.enterVisual();
5061 } else {
5062 this.leaveVisual();
5063 }
5064 return;
8bc844c0 5065 }
8bc844c0 5066
9e6cb6b6
CJ
5067 if (key === 'y') {
5068 if (this.visualMode) {
5069 var text = this.grabText(
5070 this._selected.x1, this._selected.x2,
5071 this._selected.y1, this._selected.y2);
5072 this.copyText(text);
5073 this.leaveVisual();
5074 // this.leaveSelect();
5075 }
5076 return;
5077 }
5078
5079 if (key === 'q') {
5080 if (this.visualMode) {
5081 this.leaveVisual();
5082 } else {
5083 this.leaveSelect();
5084 }
5085 return;
5086 }
5087
5088 if (key === 'w' || key === 'W') {
5089 var ox = this.x;
5090 var oy = this.y;
5091 var oyd = this.ydisp;
5092
5093 var x = this.x;
5094 var y = this.y;
5095 var yb = this.ydisp;
5096 var saw_space = false;
5097
5098 for (;;) {
5099 var line = this.lines[yb + y];
5100 while (x < this.cols) {
5101 if (line[x][1] <= ' ') {
5102 saw_space = true;
5103 } else if (saw_space) {
5104 break;
5105 }
5106 x++;
5107 }
5108 if (x >= this.cols) x = this.cols - 1;
5109 if (x === this.cols - 1 && line[x][1] <= ' ') {
5110 x = 0;
5111 if (++y >= this.rows) {
5112 y--;
5113 if (++yb > this.ybase) {
5114 yb = this.ybase;
5115 x = this.x;
5116 break;
5117 }
5118 }
5119 continue;
5120 }
5121 break;
5122 }
8bc844c0 5123
9e6cb6b6
CJ
5124 this.x = x, this.y = y;
5125 this.scrollDisp(-this.ydisp + yb);
8bc844c0 5126
9e6cb6b6
CJ
5127 if (this.visualMode) {
5128 this.selectText(ox, this.x, oy + oyd, this.ydisp + this.y);
5129 }
5130 return;
5131 }
8bc844c0 5132
9e6cb6b6
CJ
5133 if (key === 'b' || key === 'B') {
5134 var ox = this.x;
5135 var oy = this.y;
5136 var oyd = this.ydisp;
8bc844c0 5137
9e6cb6b6
CJ
5138 var x = this.x;
5139 var y = this.y;
5140 var yb = this.ydisp;
8bc844c0 5141
9e6cb6b6
CJ
5142 for (;;) {
5143 var line = this.lines[yb + y];
5144 var saw_space = x > 0 && line[x][1] > ' ' && line[x - 1][1] > ' ';
5145 while (x >= 0) {
5146 if (line[x][1] <= ' ') {
5147 if (saw_space && (x + 1 < this.cols && line[x + 1][1] > ' ')) {
5148 x++;
5149 break;
5150 } else {
5151 saw_space = true;
5152 }
5153 }
5154 x--;
5155 }
5156 if (x < 0) x = 0;
5157 if (x === 0 && (line[x][1] <= ' ' || !saw_space)) {
5158 x = this.cols - 1;
5159 if (--y < 0) {
5160 y++;
5161 if (--yb < 0) {
5162 yb++;
5163 x = 0;
5164 break;
5165 }
5166 }
5167 continue;
5168 }
5169 break;
5170 }
8bc844c0 5171
9e6cb6b6
CJ
5172 this.x = x, this.y = y;
5173 this.scrollDisp(-this.ydisp + yb);
8bc844c0 5174
9e6cb6b6
CJ
5175 if (this.visualMode) {
5176 this.selectText(this.x, ox, this.ydisp + this.y, oy + oyd);
5177 }
5178 return;
5179 }
8bc844c0 5180
9e6cb6b6
CJ
5181 if (key === 'e' || key === 'E') {
5182 var x = this.x + 1;
5183 var y = this.y;
5184 var yb = this.ydisp;
5185 if (x >= this.cols) x--;
8bc844c0 5186
9e6cb6b6
CJ
5187 for (;;) {
5188 var line = this.lines[yb + y];
5189 while (x < this.cols) {
5190 if (line[x][1] <= ' ') {
5191 x++;
5192 } else {
5193 break;
5194 }
5195 }
5196 while (x < this.cols) {
5197 if (line[x][1] <= ' ') {
5198 if (x - 1 >= 0 && line[x - 1][1] > ' ') {
5199 x--;
5200 break;
5201 }
5202 }
5203 x++;
5204 }
5205 if (x >= this.cols) x = this.cols - 1;
5206 if (x === this.cols - 1 && line[x][1] <= ' ') {
5207 x = 0;
5208 if (++y >= this.rows) {
5209 y--;
5210 if (++yb > this.ybase) {
5211 yb = this.ybase;
5212 break;
5213 }
5214 }
5215 continue;
5216 }
5217 break;
5218 }
8bc844c0 5219
9e6cb6b6
CJ
5220 this.x = x, this.y = y;
5221 this.scrollDisp(-this.ydisp + yb);
8bc844c0 5222
9e6cb6b6
CJ
5223 if (this.visualMode) {
5224 this.selectText(ox, this.x, oy + oyd, this.ydisp + this.y);
5225 }
5226 return;
5227 }
8bc844c0 5228
9e6cb6b6
CJ
5229 if (key === '^' || key === '0') {
5230 var ox = this.x;
8bc844c0 5231
9e6cb6b6
CJ
5232 if (key === '0') {
5233 this.x = 0;
5234 } else if (key === '^') {
5235 var line = this.lines[this.ydisp + this.y];
5236 var x = 0;
5237 while (x < this.cols) {
5238 if (line[x][1] > ' ') {
5239 break;
5240 }
5241 x++;
5242 }
5243 if (x >= this.cols) x = this.cols - 1;
5244 this.x = x;
5245 }
8bc844c0 5246
9e6cb6b6
CJ
5247 if (this.visualMode) {
5248 this.selectText(this.x, ox, this.ydisp + this.y, this.ydisp + this.y);
5249 } else {
5250 this.refresh(this.y, this.y);
8bc844c0 5251 }
9e6cb6b6 5252 return;
8bc844c0
CJ
5253 }
5254
9e6cb6b6
CJ
5255 if (key === '$') {
5256 var ox = this.x;
5257 var line = this.lines[this.ydisp + this.y];
5258 var x = this.cols - 1;
5259 while (x >= 0) {
5260 if (line[x][1] > ' ') {
bcecbcd9 5261 if (this.visualMode && x < this.cols - 1) x++;
9e6cb6b6
CJ
5262 break;
5263 }
5264 x--;
5265 }
5266 if (x < 0) x = 0;
5267 this.x = x;
5268 if (this.visualMode) {
5269 this.selectText(ox, this.x, this.ydisp + this.y, this.ydisp + this.y);
5270 } else {
5271 this.refresh(this.y, this.y);
5272 }
5273 return;
5274 }
8bc844c0 5275
9e6cb6b6
CJ
5276 if (key === 'g' || key === 'G') {
5277 var ox = this.x;
5278 var oy = this.y;
5279 var oyd = this.ydisp;
5280 if (key === 'g') {
5281 this.x = 0, this.y = 0;
5282 this.scrollDisp(-this.ydisp);
9e6cb6b6
CJ
5283 } else if (key === 'G') {
5284 this.x = 0, this.y = this.rows - 1;
5285 this.scrollDisp(this.ybase);
5d3f8786
CJ
5286 }
5287 if (this.visualMode) {
5288 this.selectText(ox, this.x, oy + oyd, this.ydisp + this.y);
9e6cb6b6
CJ
5289 }
5290 return;
5291 }
8bc844c0 5292
9e6cb6b6
CJ
5293 if (key === 'H' || key === 'M' || key === 'L') {
5294 var ox = this.x;
5295 var oy = this.y;
5296 if (key === 'H') {
5297 this.x = 0, this.y = 0;
5298 } else if (key === 'M') {
5299 this.x = 0, this.y = this.rows / 2 | 0;
5300 } else if (key === 'L') {
5301 this.x = 0, this.y = this.rows - 1;
5302 }
5303 if (this.visualMode) {
5304 this.selectText(ox, this.x, this.ydisp + oy, this.ydisp + this.y);
5305 } else {
5306 this.refresh(oy, oy);
5307 this.refresh(this.y, this.y);
5308 }
5309 return;
5310 }
8bc844c0 5311
9e6cb6b6
CJ
5312 if (key === '{' || key === '}') {
5313 var ox = this.x;
5314 var oy = this.y;
5315 var oyd = this.ydisp;
8bc844c0 5316
9e6cb6b6
CJ
5317 var line;
5318 var saw_full = false;
5319 var found = false;
5320 var first_is_space = -1;
5321 var y = this.y + (key === '{' ? -1 : 1);
5322 var yb = this.ydisp;
5323 var i;
8bc844c0 5324
9e6cb6b6
CJ
5325 if (key === '{') {
5326 if (y < 0) {
5327 y++;
5328 if (yb > 0) yb--;
5329 }
5330 } else if (key === '}') {
5331 if (y >= this.rows) {
5332 y--;
5333 if (yb < this.ybase) yb++;
5334 }
5335 }
8bc844c0 5336
9e6cb6b6
CJ
5337 for (;;) {
5338 line = this.lines[yb + y];
8bc844c0 5339
9e6cb6b6
CJ
5340 for (i = 0; i < this.cols; i++) {
5341 if (line[i][1] > ' ') {
5342 if (first_is_space === -1) {
5343 first_is_space = 0;
5344 }
5345 saw_full = true;
5346 break;
5347 } else if (i === this.cols - 1) {
5348 if (first_is_space === -1) {
5349 first_is_space = 1;
5350 } else if (first_is_space === 0) {
5351 found = true;
5352 } else if (first_is_space === 1) {
5353 if (saw_full) found = true;
5354 }
5355 break;
5356 }
5357 }
8bc844c0 5358
9e6cb6b6 5359 if (found) break;
8bc844c0 5360
9e6cb6b6
CJ
5361 if (key === '{') {
5362 y--;
5363 if (y < 0) {
5364 y++;
5365 if (yb > 0) yb--;
5366 else break;
5367 }
5368 } else if (key === '}') {
5369 y++;
5370 if (y >= this.rows) {
5371 y--;
5372 if (yb < this.ybase) yb++;
5373 else break;
5374 }
5375 }
5376 }
8bc844c0 5377
9e6cb6b6
CJ
5378 if (!found) {
5379 if (key === '{') {
5380 y = 0;
5381 yb = 0;
5382 } else if (key === '}') {
5383 y = this.rows - 1;
5384 yb = this.ybase;
5385 }
5386 }
8bc844c0 5387
9e6cb6b6
CJ
5388 this.x = 0, this.y = y;
5389 this.scrollDisp(-this.ydisp + yb);
8bc844c0 5390
5d3f8786
CJ
5391 if (this.visualMode) {
5392 this.selectText(ox, this.x, oy + oyd, this.ydisp + this.y);
9e6cb6b6
CJ
5393 }
5394 return;
5395 }
8bc844c0 5396
9e6cb6b6
CJ
5397 if (key === '/' || key === '?') {
5398 if (!this.visualMode) {
5399 this.enterSearch(key === '/');
8bc844c0 5400 }
9e6cb6b6 5401 return;
8bc844c0
CJ
5402 }
5403
9e6cb6b6 5404 return false;
8bc844c0
CJ
5405};
5406
9e6cb6b6
CJ
5407Terminal.prototype.keySearch = function(ev, key) {
5408 if (key === '\x1b') {
5409 this.leaveSearch();
5410 return;
8bc844c0
CJ
5411 }
5412
9e6cb6b6
CJ
5413 if (key === '\r' || (!this.searchMode && (key === 'n' || key === 'N'))) {
5414 this.leaveSearch();
8bc844c0 5415
9e6cb6b6 5416 var entry = this.entry;
8bc844c0 5417
9e6cb6b6
CJ
5418 if (!entry) {
5419 this.refresh(0, this.rows - 1);
5420 return;
5421 }
8bc844c0 5422
9e6cb6b6
CJ
5423 var ox = this.x;
5424 var oy = this.y;
5425 var oyd = this.ydisp;
8bc844c0 5426
9e6cb6b6
CJ
5427 var line;
5428 var found = false;
5429 var wrapped = false;
5430 var x = this.x + 1;
5431 var y = this.ydisp + this.y;
5432 var yb, i;
5433 var up = key === 'N'
5434 ? this.searchDown
5435 : !this.searchDown;
8bc844c0 5436
9e6cb6b6
CJ
5437 for (;;) {
5438 line = this.lines[y];
8bc844c0 5439
9e6cb6b6
CJ
5440 while (x < this.cols) {
5441 for (i = 0; i < entry.length; i++) {
5442 if (x + i >= this.cols) break;
5443 if (line[x + i][1] !== entry[i]) {
5444 break;
5445 } else if (line[x + i][1] === entry[i] && i === entry.length - 1) {
5446 found = true;
5447 break;
5448 }
5449 }
5450 if (found) break;
5451 x += i + 1;
5452 }
5453 if (found) break;
8bc844c0 5454
9e6cb6b6 5455 x = 0;
8bc844c0 5456
9e6cb6b6
CJ
5457 if (!up) {
5458 y++;
5459 if (y > this.ybase + this.rows - 1) {
5460 if (wrapped) break;
74848936 5461 // this.setMessage('Search wrapped. Continuing at TOP.');
9e6cb6b6
CJ
5462 wrapped = true;
5463 y = 0;
5464 }
5465 } else {
5466 y--;
5467 if (y < 0) {
5468 if (wrapped) break;
74848936 5469 // this.setMessage('Search wrapped. Continuing at BOTTOM.');
9e6cb6b6
CJ
5470 wrapped = true;
5471 y = this.ybase + this.rows - 1;
5472 }
5473 }
8bc844c0 5474 }
8bc844c0 5475
9e6cb6b6
CJ
5476 if (found) {
5477 if (y - this.ybase < 0) {
5478 yb = y;
5479 y = 0;
5480 if (yb > this.ybase) {
5481 y = yb - this.ybase;
5482 yb = this.ybase;
5483 }
5484 } else {
5485 yb = this.ybase;
5486 y -= this.ybase;
5487 }
8bc844c0 5488
9e6cb6b6
CJ
5489 this.x = x, this.y = y;
5490 this.scrollDisp(-this.ydisp + yb);
8bc844c0 5491
9e6cb6b6
CJ
5492 if (this.visualMode) {
5493 this.selectText(ox, this.x, oy + oyd, this.ydisp + this.y);
5494 }
5495 return;
8bc844c0 5496 }
9e6cb6b6 5497
74848936 5498 // this.setMessage("No matches found.");
9e6cb6b6 5499 this.refresh(0, this.rows - 1);
74848936 5500
9e6cb6b6 5501 return;
8bc844c0
CJ
5502 }
5503
9e6cb6b6
CJ
5504 if (key === '\b' || key === '\x7f') {
5505 if (this.entry.length === 0) return;
5506 var bottom = this.ydisp + this.rows - 1;
5507 this.entry = this.entry.slice(0, -1);
5508 var i = this.entryPrefix.length + this.entry.length;
5509 //this.lines[bottom][i][1] = ' ';
5510 this.lines[bottom][i] = [
5511 this.lines[bottom][i][0],
5512 ' '
5513 ];
5514 this.x--;
5515 this.refresh(this.rows - 1, this.rows - 1);
5516 this.refresh(this.y, this.y);
5517 return;
5518 }
5519
5520 if (key.length === 1 && key >= ' ' && key <= '~') {
5521 var bottom = this.ydisp + this.rows - 1;
5522 this.entry += key;
5523 var i = this.entryPrefix.length + this.entry.length - 1;
5524 //this.lines[bottom][i][0] = (this.defAttr & ~0x1ff) | 4;
5525 //this.lines[bottom][i][1] = key;
5526 this.lines[bottom][i] = [
5527 (this.defAttr & ~0x1ff) | 4,
5528 key
5529 ];
5530 this.x++;
5531 this.refresh(this.rows - 1, this.rows - 1);
5532 this.refresh(this.y, this.y);
5533 return;
5534 }
5535
5536 return false;
8bc844c0
CJ
5537};
5538
5539/**
5540 * Character Sets
5541 */
5542
5543Terminal.charsets = {};
5544
5545// DEC Special Character and Line Drawing Set.
5546// http://vt100.net/docs/vt102-ug/table5-13.html
5547// A lot of curses apps use this if they see TERM=xterm.
5548// testing: echo -e '\e(0a\e(B'
5549// The xterm output sometimes seems to conflict with the
5550// reference above. xterm seems in line with the reference
5551// when running vttest however.
5552// The table below now uses xterm's output from vttest.
5553Terminal.charsets.SCLD = { // (0
5554 '`': '\u25c6', // '◆'
5555 'a': '\u2592', // '▒'
5556 'b': '\u0009', // '\t'
5557 'c': '\u000c', // '\f'
5558 'd': '\u000d', // '\r'
5559 'e': '\u000a', // '\n'
5560 'f': '\u00b0', // '°'
5561 'g': '\u00b1', // '±'
5562 'h': '\u2424', // '\u2424' (NL)
5563 'i': '\u000b', // '\v'
5564 'j': '\u2518', // '┘'
5565 'k': '\u2510', // '┐'
5566 'l': '\u250c', // '┌'
5567 'm': '\u2514', // '└'
5568 'n': '\u253c', // '┼'
5569 'o': '\u23ba', // '⎺'
5570 'p': '\u23bb', // '⎻'
5571 'q': '\u2500', // '─'
5572 'r': '\u23bc', // '⎼'
5573 's': '\u23bd', // '⎽'
5574 't': '\u251c', // '├'
5575 'u': '\u2524', // '┤'
5576 'v': '\u2534', // '┴'
5577 'w': '\u252c', // '┬'
5578 'x': '\u2502', // '│'
5579 'y': '\u2264', // '≤'
5580 'z': '\u2265', // '≥'
5581 '{': '\u03c0', // 'π'
5582 '|': '\u2260', // '≠'
5583 '}': '\u00a3', // '£'
5584 '~': '\u00b7' // '·'
5585};
5586
5587Terminal.charsets.UK = null; // (A
5588Terminal.charsets.US = null; // (B (USASCII)
5589Terminal.charsets.Dutch = null; // (4
5590Terminal.charsets.Finnish = null; // (C or (5
5591Terminal.charsets.French = null; // (R
5592Terminal.charsets.FrenchCanadian = null; // (Q
5593Terminal.charsets.German = null; // (K
5594Terminal.charsets.Italian = null; // (Y
5595Terminal.charsets.NorwegianDanish = null; // (E or (6
5596Terminal.charsets.Spanish = null; // (Z
5597Terminal.charsets.Swedish = null; // (H or (7
5598Terminal.charsets.Swiss = null; // (=
5599Terminal.charsets.ISOLatin = null; // /A
5600
5601/**
5602 * Helpers
5603 */
5604
5605function on(el, type, handler, capture) {
5606 el.addEventListener(type, handler, capture || false);
5607}
5608
5609function off(el, type, handler, capture) {
5610 el.removeEventListener(type, handler, capture || false);
5611}
5612
5613function cancel(ev) {
5614 if (ev.preventDefault) ev.preventDefault();
5615 ev.returnValue = false;
5616 if (ev.stopPropagation) ev.stopPropagation();
5617 ev.cancelBubble = true;
5618 return false;
5619}
5620
5621function inherits(child, parent) {
5622 function f() {
5623 this.constructor = child;
5624 }
5625 f.prototype = parent.prototype;
5626 child.prototype = new f;
5627}
5628
8bc844c0
CJ
5629// if bold is broken, we can't
5630// use it in the terminal.
91273161 5631function isBoldBroken(document) {
cd956bca 5632 var body = document.getElementsByTagName('body')[0];
8bc844c0
CJ
5633 var el = document.createElement('span');
5634 el.innerHTML = 'hello world';
cd956bca 5635 body.appendChild(el);
8bc844c0
CJ
5636 var w1 = el.scrollWidth;
5637 el.style.fontWeight = 'bold';
5638 var w2 = el.scrollWidth;
cd956bca 5639 body.removeChild(el);
8bc844c0
CJ
5640 return w1 !== w2;
5641}
5642
5643var String = this.String;
5644var setTimeout = this.setTimeout;
5645var setInterval = this.setInterval;
5646
6cc8b3cd
CJ
5647function indexOf(obj, el) {
5648 var i = obj.length;
5649 while (i--) {
5650 if (obj[i] === el) return i;
5651 }
5652 return -1;
5653}
5654
a7f50531
CJ
5655function isWide(ch) {
5656 if (ch <= '\uff00') return false;
5657 return (ch >= '\uff01' && ch <= '\uffbe')
5658 || (ch >= '\uffc2' && ch <= '\uffc7')
5659 || (ch >= '\uffca' && ch <= '\uffcf')
5660 || (ch >= '\uffd2' && ch <= '\uffd7')
5661 || (ch >= '\uffda' && ch <= '\uffdc')
5662 || (ch >= '\uffe0' && ch <= '\uffe6')
5663 || (ch >= '\uffe8' && ch <= '\uffee');
5664}
14248234 5665
a68c8336
CJ
5666function matchColor(r1, g1, b1) {
5667 var hash = (r1 << 16) | (g1 << 8) | b1;
5668
5669 if (matchColor._cache[hash] != null) {
5670 return matchColor._cache[hash];
5671 }
5672
5673 var ldiff = Infinity
5674 , li = -1
5675 , i = 0
5676 , c
5677 , r2
5678 , g2
5679 , b2
5680 , diff;
5681
5682 for (; i < Terminal.vcolors.length; i++) {
5683 c = Terminal.vcolors[i];
5684 r2 = c[0];
5685 g2 = c[1];
5686 b2 = c[2];
5687
5688 diff = matchColor.distance(r1, g1, b1, r2, g2, b2);
5689
5690 if (diff === 0) {
5691 li = i;
5692 break;
5693 }
5694
5695 if (diff < ldiff) {
5696 ldiff = diff;
5697 li = i;
5698 }
5699 }
5700
5701 return matchColor._cache[hash] = li;
5702}
5703
5704matchColor._cache = {};
5705
5706// http://stackoverflow.com/questions/1633828
5707matchColor.distance = function(r1, g1, b1, r2, g2, b2) {
5708 return Math.pow(30 * (r1 - r2), 2)
5709 + Math.pow(59 * (g1 - g2), 2)
5710 + Math.pow(11 * (b1 - b2), 2);
5711};
5712
86dad1b0
CJ
5713function each(obj, iter, con) {
5714 if (obj.forEach) return obj.forEach(iter, con);
5715 for (var i = 0; i < obj.length; i++) {
5716 iter.call(con, obj[i], i, obj);
5717 }
5718}
5719
5720function keys(obj) {
5721 if (Object.keys) return Object.keys(obj);
5722 var key, keys = [];
5723 for (key in obj) {
5724 if (Object.prototype.hasOwnProperty.call(obj, key)) {
5725 keys.push(key);
5726 }
5727 }
5728 return keys;
5729}
5730
8bc844c0
CJ
5731/**
5732 * Expose
5733 */
5734
5735Terminal.EventEmitter = EventEmitter;
8bc844c0
CJ
5736Terminal.inherits = inherits;
5737Terminal.on = on;
5738Terminal.off = off;
5739Terminal.cancel = cancel;
5740
5741if (typeof module !== 'undefined') {
5742 module.exports = Terminal;
5743} else {
5744 this.Terminal = Terminal;
5745}
5746
5747}).call(function() {
5748 return this || (typeof window !== 'undefined' ? window : global);
5749}());