]> git.proxmox.com Git - mirror_xterm.js.git/blame - lib/term.js
optimize widechar check.
[mirror_xterm.js.git] / lib / 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);
110 // if (obj[i].apply(this, args) === false) return false;
111 }
112};
113
114EventEmitter.prototype.listeners = function(type) {
115 return this._events[type] = this._events[type] || [];
116};
117
118/**
119 * States
120 */
121
122var normal = 0
123 , escaped = 1
124 , csi = 2
125 , osc = 3
126 , charset = 4
127 , dcs = 5
128 , ignore = 6;
129
130/**
131 * Terminal
132 */
133
91273161
CJ
134function Terminal(options) {
135 if (!(this instanceof Terminal)) {
136 return new Terminal(arguments[0], arguments[1], arguments[2]);
137 }
138
8bc844c0
CJ
139 EventEmitter.call(this);
140
2f212c6e 141 if (typeof options === 'number') {
91273161
CJ
142 options = {
143 cols: arguments[0],
144 rows: arguments[1],
145 handler: arguments[2]
146 };
8bc844c0 147 }
91273161 148
8bc844c0
CJ
149 this._options = options || {};
150
2f212c6e
CJ
151 // this.context = options.context || window;
152 // this.document = options.document || document;
153 this.parent = options.body || options.parent
154 || (document ? document.body : null);
8bc844c0 155
91273161
CJ
156 this.cols = options.cols || Terminal.geometry[0];
157 this.rows = options.rows || Terminal.geometry[1];
158
159 if (options.handler) {
160 this.on('data', options.handler);
8bc844c0
CJ
161 }
162
163 this.ybase = 0;
164 this.ydisp = 0;
165 this.x = 0;
166 this.y = 0;
167 this.cursorState = 0;
168 this.cursorHidden = false;
169 this.convertEol = false;
170 this.state = 0;
171 this.queue = '';
172 this.scrollTop = 0;
173 this.scrollBottom = this.rows - 1;
174
175 // modes
176 this.applicationKeypad = false;
177 this.applicationCursor = false;
178 this.originMode = false;
179 this.insertMode = false;
180 this.wraparoundMode = false;
181 this.normal = null;
182
183 // charset
184 this.charset = null;
185 this.gcharset = null;
186 this.glevel = 0;
187 this.charsets = [null];
188
189 // mouse properties
190 this.decLocator;
191 this.x10Mouse;
192 this.vt200Mouse;
193 this.vt300Mouse;
194 this.normalMouse;
195 this.mouseEvents;
196 this.sendFocus;
197 this.utfMouse;
198 this.sgrMouse;
199 this.urxvtMouse;
200
201 // misc
202 this.element;
203 this.children;
204 this.refreshStart;
205 this.refreshEnd;
206 this.savedX;
207 this.savedY;
208 this.savedCols;
209
210 // stream
211 this.readable = true;
212 this.writable = true;
213
214 this.defAttr = (257 << 9) | 256;
215 this.curAttr = this.defAttr;
216
217 this.params = [];
218 this.currentParam = 0;
219 this.prefix = '';
220 this.postfix = '';
221
222 this.lines = [];
223 var i = this.rows;
224 while (i--) {
225 this.lines.push(this.blankLine());
226 }
227
228 this.tabs;
229 this.setupStops();
230}
231
232inherits(Terminal, EventEmitter);
233
234// back_color_erase feature for xterm.
235Terminal.prototype.eraseAttr = function() {
236 // if (this.is('screen')) return this.defAttr;
237 return (this.defAttr & ~0x1ff) | (this.curAttr & 0x1ff);
238};
239
240/**
241 * Colors
242 */
243
244// Colors 0-15
245Terminal.colors = [
246 // dark:
247 '#2e3436',
248 '#cc0000',
249 '#4e9a06',
250 '#c4a000',
251 '#3465a4',
252 '#75507b',
253 '#06989a',
254 '#d3d7cf',
255 // bright:
256 '#555753',
257 '#ef2929',
258 '#8ae234',
259 '#fce94f',
260 '#729fcf',
261 '#ad7fa8',
262 '#34e2e2',
263 '#eeeeec'
264];
265
6cc8b3cd
CJ
266Terminal.xtermColors = [
267 '#000000', // black
268 '#cd0000', // red3
269 '#00cd00', // green3
270 '#cdcd00', // yellow3
271 '#0000ee', // blue2
272 '#cd00cd', // magenta3
273 '#00cdcd', // cyan3
274 '#e5e5e5', // gray90
275 '#7f7f7f', // gray50
276 '#ff0000', // red
277 '#00ff00', // green
278 '#ffff00', // yellow
279 '#5c5cff', // rgb:5c/5c/ff
280 '#ff00ff', // magenta
281 '#00ffff', // cyan
282 '#ffffff' // white
283];
284
8bc844c0
CJ
285// Colors 16-255
286// Much thanks to TooTallNate for writing this.
287Terminal.colors = (function() {
288 var colors = Terminal.colors
289 , r = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
290 , i;
291
292 // 16-231
293 i = 0;
294 for (; i < 216; i++) {
295 out(r[(i / 36) % 6 | 0], r[(i / 6) % 6 | 0], r[i % 6]);
296 }
297
298 // 232-255 (grey)
299 i = 0;
300 for (; i < 24; i++) {
301 r = 8 + i * 10;
302 out(r, r, r);
303 }
304
305 function out(r, g, b) {
306 colors.push('#' + hex(r) + hex(g) + hex(b));
307 }
308
309 function hex(c) {
310 c = c.toString(16);
311 return c.length < 2 ? '0' + c : c;
312 }
313
314 return colors;
315})();
316
a68c8336
CJ
317Terminal.vcolors = (function() {
318 var out = []
319 , colors = Terminal.colors
320 , i = 0
321 , color;
322
323 for (; i < colors.length; i++) {
324 color = parseInt(colors[i].substring(1), 16);
325 out.push([
326 (color >> 16) & 0xff,
327 (color >> 8) & 0xff,
328 color & 0xff
329 ]);
330 }
331
332 return out;
333})();
334
8bc844c0
CJ
335// Default BG/FG
336Terminal.defaultColors = {
337 bg: '#000000',
338 fg: '#f0f0f0'
339};
340
341Terminal.colors[256] = Terminal.defaultColors.bg;
342Terminal.colors[257] = Terminal.defaultColors.fg;
343
344/**
345 * Options
346 */
347
348Terminal.termName = 'xterm';
349Terminal.geometry = [80, 24];
350Terminal.cursorBlink = true;
351Terminal.visualBell = false;
352Terminal.popOnBell = false;
353Terminal.scrollback = 1000;
354Terminal.screenKeys = false;
355Terminal.programFeatures = false;
356Terminal.escapeKey = null;
357Terminal.debug = false;
358
359/**
360 * Focused Terminal
361 */
362
363Terminal.focus = null;
364
365Terminal.prototype.focus = function() {
366 if (Terminal.focus === this) return;
6cc8b3cd 367
8bc844c0 368 if (Terminal.focus) {
6cc8b3cd 369 Terminal.focus.blur();
8bc844c0 370 }
6cc8b3cd 371
8bc844c0
CJ
372 if (this.sendFocus) this.send('\x1b[I');
373 this.showCursor();
6cc8b3cd
CJ
374
375 // try {
376 // this.element.focus();
377 // } catch (e) {
378 // ;
379 // }
380
381 // this.emit('focus');
382
383 Terminal.focus = this;
384};
385
386Terminal.prototype.blur = function() {
387 if (Terminal.focus !== this) return;
388
389 this.cursorState = 0;
390 this.refresh(this.y, this.y);
391 if (this.sendFocus) this.send('\x1b[O');
392
393 // try {
394 // this.element.blur();
395 // } catch (e) {
396 // ;
397 // }
398
399 // this.emit('blur');
400
401 Terminal.focus = null;
8bc844c0
CJ
402};
403
404/**
405 * Global Events for key handling
406 */
407
91273161 408Terminal.bindKeys = function(document) {
6cc8b3cd
CJ
409 Terminal._boundDocs = Terminal._boundDocs || [];
410
411 if (~indexOf(Terminal._boundDocs, document)) {
412 return;
413 }
414
415 Terminal._boundDocs.push(document);
8bc844c0
CJ
416
417 // We could put an "if (Terminal.focus)" check
418 // here, but it shouldn't be necessary.
419 on(document, 'keydown', function(ev) {
6cc8b3cd
CJ
420 if (!Terminal.focus) return;
421 var target = ev.target || ev.srcElement;
422 // Should just be body, but we can
423 // check everything for good measure.
424 if (target === Terminal.focus.element
425 || target === Terminal.focus.context
426 || target === Terminal.focus.document
427 || target === Terminal.focus.document.body
428 || target === Terminal.focus.parent) {
429 return Terminal.focus.keyDown(ev);
430 }
8bc844c0
CJ
431 }, true);
432
433 on(document, 'keypress', function(ev) {
6cc8b3cd
CJ
434 if (!Terminal.focus) return;
435 var target = ev.target || ev.srcElement;
436 // Should just be body, but we can
437 // check everything for good measure.
438 if (target === Terminal.focus.element
439 || target === Terminal.focus.context
440 || target === Terminal.focus.document
441 || target === Terminal.focus.document.body
442 || target === Terminal.focus.parent) {
443 return Terminal.focus.keyPress(ev);
444 }
8bc844c0 445 }, true);
6cc8b3cd
CJ
446
447 // If we click somewhere other than a
448 // terminal, unfocus the terminal.
449 on(document, 'mousedown', function(ev) {
450 if (!Terminal.focus) return;
451
452 var el = ev.target || ev.srcElement;
f46cb519 453 if (!el) return;
6cc8b3cd
CJ
454
455 do {
456 if (el === Terminal.focus.element) return;
457 } while (el = el.parentNode);
458
459 Terminal.focus.blur();
460 });
8bc844c0
CJ
461};
462
463/**
464 * Open Terminal
465 */
466
91273161 467Terminal.prototype.open = function(parent) {
8bc844c0
CJ
468 var self = this
469 , i = 0
470 , div;
471
2f212c6e
CJ
472 this.parent = parent || this.parent;
473
474 if (!this.parent) {
475 throw new Error('Terminal requires a parent element.');
476 }
477
478 this.context = this.parent.ownerDocument.defaultView;
479 this.document = this.parent.ownerDocument;
91273161
CJ
480
481 this.element = this.document.createElement('div');
8bc844c0 482 this.element.className = 'terminal';
6cc8b3cd
CJ
483 this.element.style.outline = 'none';
484 this.element.setAttribute('tabindex', 0);
485
8bc844c0
CJ
486 this.children = [];
487
488 for (; i < this.rows; i++) {
91273161 489 div = this.document.createElement('div');
8bc844c0
CJ
490 this.element.appendChild(div);
491 this.children.push(div);
492 }
493
91273161 494 this.parent.appendChild(this.element);
8bc844c0
CJ
495
496 this.refresh(0, this.rows - 1);
497
91273161
CJ
498 Terminal.bindKeys(this.document);
499
8bc844c0
CJ
500 this.focus();
501
502 this.startBlink();
503
6cc8b3cd
CJ
504 on(this.element, 'focus', function() {
505 self.focus();
506 });
507
508 // on(this.element, 'blur', function() {
509 // self.blur();
510 // });
511
8bc844c0
CJ
512 on(this.element, 'mousedown', function() {
513 self.focus();
514 });
515
516 // This probably shouldn't work,
517 // ... but it does. Firefox's paste
518 // event seems to only work for textareas?
519 on(this.element, 'mousedown', function(ev) {
520 var button = ev.button != null
521 ? +ev.button
522 : ev.which != null
523 ? ev.which - 1
524 : null;
525
526 // Does IE9 do this?
527 if (~navigator.userAgent.indexOf('MSIE')) {
528 button = button === 1 ? 0 : button === 4 ? 1 : button;
529 }
530
531 if (button !== 2) return;
532
533 self.element.contentEditable = 'true';
534 setTimeout(function() {
535 self.element.contentEditable = 'inherit'; // 'false';
536 }, 1);
537 }, true);
538
539 on(this.element, 'paste', function(ev) {
540 if (ev.clipboardData) {
541 self.send(ev.clipboardData.getData('text/plain'));
91273161
CJ
542 } else if (self.context.clipboardData) {
543 self.send(self.context.clipboardData.getData('Text'));
8bc844c0
CJ
544 }
545 // Not necessary. Do it anyway for good measure.
546 self.element.contentEditable = 'inherit';
547 return cancel(ev);
548 });
549
550 this.bindMouse();
551
552 // XXX - hack, move this somewhere else.
553 if (Terminal.brokenBold == null) {
91273161 554 Terminal.brokenBold = isBoldBroken(this.document);
8bc844c0
CJ
555 }
556
557 // sync default bg/fg colors
558 this.element.style.backgroundColor = Terminal.defaultColors.bg;
559 this.element.style.color = Terminal.defaultColors.fg;
560
f46cb519 561 // this.emit('open');
8bc844c0
CJ
562};
563
564// XTerm mouse events
565// http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
566// To better understand these
567// the xterm code is very helpful:
568// Relevant files:
569// button.c, charproc.c, misc.c
570// Relevant functions in xterm/button.c:
571// BtnCode, EmitButtonCode, EditorButton, SendMousePosition
572Terminal.prototype.bindMouse = function() {
573 var el = this.element
574 , self = this
575 , pressed = 32;
576
91273161 577 var wheelEvent = 'onmousewheel' in this.context
8bc844c0
CJ
578 ? 'mousewheel'
579 : 'DOMMouseScroll';
580
581 // mouseup, mousedown, mousewheel
582 // left click: ^[[M 3<^[[M#3<
583 // mousewheel up: ^[[M`3>
584 function sendButton(ev) {
585 var button
586 , pos;
587
588 // get the xterm-style button
589 button = getButton(ev);
590
591 // get mouse coordinates
592 pos = getCoords(ev);
593 if (!pos) return;
594
595 sendEvent(button, pos);
596
597 switch (ev.type) {
598 case 'mousedown':
599 pressed = button;
600 break;
601 case 'mouseup':
602 // keep it at the left
603 // button, just in case.
604 pressed = 32;
605 break;
606 case wheelEvent:
607 // nothing. don't
608 // interfere with
609 // `pressed`.
610 break;
611 }
612 }
613
614 // motion example of a left click:
615 // ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
616 function sendMove(ev) {
617 var button = pressed
618 , pos;
619
620 pos = getCoords(ev);
621 if (!pos) return;
622
623 // buttons marked as motions
624 // are incremented by 32
625 button += 32;
626
627 sendEvent(button, pos);
628 }
629
630 // encode button and
631 // position to characters
632 function encode(data, ch) {
633 if (!self.utfMouse) {
634 if (ch === 255) return data.push(0);
635 if (ch > 127) ch = 127;
636 data.push(ch);
637 } else {
638 if (ch === 2047) return data.push(0);
639 if (ch < 127) {
640 data.push(ch);
641 } else {
642 if (ch > 2047) ch = 2047;
643 data.push(0xC0 | (ch >> 6));
644 data.push(0x80 | (ch & 0x3F));
645 }
646 }
647 }
648
649 // send a mouse event:
650 // regular/utf8: ^[[M Cb Cx Cy
651 // urxvt: ^[[ Cb ; Cx ; Cy M
652 // sgr: ^[[ Cb ; Cx ; Cy M/m
653 // vt300: ^[[ 24(1/3/5)~ [ Cx , Cy ] \r
654 // locator: CSI P e ; P b ; P r ; P c ; P p & w
655 function sendEvent(button, pos) {
656 // self.emit('mouse', {
657 // x: pos.x - 32,
658 // y: pos.x - 32,
659 // button: button
660 // });
661
662 if (self.vt300Mouse) {
663 // NOTE: Unstable.
664 // http://www.vt100.net/docs/vt3xx-gp/chapter15.html
665 button &= 3;
666 pos.x -= 32;
667 pos.y -= 32;
668 var data = '\x1b[24';
669 if (button === 0) data += '1';
670 else if (button === 1) data += '3';
671 else if (button === 2) data += '5';
672 else if (button === 3) return;
673 else data += '0';
674 data += '~[' + pos.x + ',' + pos.y + ']\r';
675 self.send(data);
676 return;
677 }
678
679 if (self.decLocator) {
680 // NOTE: Unstable.
681 button &= 3;
682 pos.x -= 32;
683 pos.y -= 32;
684 if (button === 0) button = 2;
685 else if (button === 1) button = 4;
686 else if (button === 2) button = 6;
687 else if (button === 3) button = 3;
688 self.send('\x1b['
689 + button
690 + ';'
691 + (button === 3 ? 4 : 0)
692 + ';'
693 + pos.y
694 + ';'
695 + pos.x
696 + ';'
697 + (pos.page || 0)
698 + '&w');
699 return;
700 }
701
702 if (self.urxvtMouse) {
703 pos.x -= 32;
704 pos.y -= 32;
705 pos.x++;
706 pos.y++;
707 self.send('\x1b[' + button + ';' + pos.x + ';' + pos.y + 'M');
708 return;
709 }
710
711 if (self.sgrMouse) {
712 pos.x -= 32;
713 pos.y -= 32;
714 self.send('\x1b[<'
715 + ((button & 3) === 3 ? button & ~3 : button)
716 + ';'
717 + pos.x
718 + ';'
719 + pos.y
720 + ((button & 3) === 3 ? 'm' : 'M'));
721 return;
722 }
723
724 var data = [];
725
726 encode(data, button);
727 encode(data, pos.x);
728 encode(data, pos.y);
729
730 self.send('\x1b[M' + String.fromCharCode.apply(String, data));
731 }
732
733 function getButton(ev) {
734 var button
735 , shift
736 , meta
737 , ctrl
738 , mod;
739
740 // two low bits:
741 // 0 = left
742 // 1 = middle
743 // 2 = right
744 // 3 = release
745 // wheel up/down:
746 // 1, and 2 - with 64 added
747 switch (ev.type) {
748 case 'mousedown':
749 button = ev.button != null
750 ? +ev.button
751 : ev.which != null
752 ? ev.which - 1
753 : null;
754
755 if (~navigator.userAgent.indexOf('MSIE')) {
756 button = button === 1 ? 0 : button === 4 ? 1 : button;
757 }
758 break;
759 case 'mouseup':
760 button = 3;
761 break;
762 case 'DOMMouseScroll':
763 button = ev.detail < 0
764 ? 64
765 : 65;
766 break;
767 case 'mousewheel':
768 button = ev.wheelDeltaY > 0
769 ? 64
770 : 65;
771 break;
772 }
773
774 // next three bits are the modifiers:
775 // 4 = shift, 8 = meta, 16 = control
776 shift = ev.shiftKey ? 4 : 0;
777 meta = ev.metaKey ? 8 : 0;
778 ctrl = ev.ctrlKey ? 16 : 0;
779 mod = shift | meta | ctrl;
780
781 // no mods
782 if (self.vt200Mouse) {
783 // ctrl only
784 mod &= ctrl;
785 } else if (!self.normalMouse) {
786 mod = 0;
787 }
788
789 // increment to SP
790 button = (32 + (mod << 2)) + button;
791
792 return button;
793 }
794
795 // mouse coordinates measured in cols/rows
796 function getCoords(ev) {
797 var x, y, w, h, el;
798
799 // ignore browsers without pageX for now
800 if (ev.pageX == null) return;
801
802 x = ev.pageX;
803 y = ev.pageY;
804 el = self.element;
805
806 // should probably check offsetParent
807 // but this is more portable
49d3a20f 808 while (el && el !== self.document.documentElement) {
8bc844c0
CJ
809 x -= el.offsetLeft;
810 y -= el.offsetTop;
49d3a20f
CJ
811 el = 'offsetParent' in el
812 ? el.offsetParent
813 : el.parentNode;
8bc844c0
CJ
814 }
815
816 // convert to cols/rows
817 w = self.element.clientWidth;
818 h = self.element.clientHeight;
49d3a20f
CJ
819 x = Math.round((x / w) * self.cols);
820 y = Math.round((y / h) * self.rows);
8bc844c0
CJ
821
822 // be sure to avoid sending
823 // bad positions to the program
824 if (x < 0) x = 0;
628af053 825 if (x > self.cols) x = self.cols;
8bc844c0 826 if (y < 0) y = 0;
628af053 827 if (y > self.rows) y = self.rows;
8bc844c0
CJ
828
829 // xterm sends raw bytes and
830 // starts at 32 (SP) for each.
831 x += 32;
832 y += 32;
833
834 return {
835 x: x,
836 y: y,
49d3a20f
CJ
837 type: ev.type === wheelEvent
838 ? 'mousewheel'
839 : ev.type
8bc844c0
CJ
840 };
841 }
842
843 on(el, 'mousedown', function(ev) {
844 if (!self.mouseEvents) return;
845
846 // send the button
847 sendButton(ev);
848
849 // ensure focus
850 self.focus();
851
852 // fix for odd bug
49d3a20f 853 //if (self.vt200Mouse && !self.normalMouse) {
8bc844c0
CJ
854 if (self.vt200Mouse) {
855 sendButton({ __proto__: ev, type: 'mouseup' });
856 return cancel(ev);
857 }
858
859 // bind events
91273161 860 if (self.normalMouse) on(self.document, 'mousemove', sendMove);
8bc844c0
CJ
861
862 // x10 compatibility mode can't send button releases
863 if (!self.x10Mouse) {
91273161 864 on(self.document, 'mouseup', function up(ev) {
8bc844c0 865 sendButton(ev);
91273161
CJ
866 if (self.normalMouse) off(self.document, 'mousemove', sendMove);
867 off(self.document, 'mouseup', up);
8bc844c0
CJ
868 return cancel(ev);
869 });
870 }
871
872 return cancel(ev);
873 });
874
49d3a20f
CJ
875 //if (self.normalMouse) {
876 // on(self.document, 'mousemove', sendMove);
877 //}
878
8bc844c0
CJ
879 on(el, wheelEvent, function(ev) {
880 if (!self.mouseEvents) return;
881 if (self.x10Mouse
882 || self.vt300Mouse
883 || self.decLocator) return;
884 sendButton(ev);
885 return cancel(ev);
886 });
887
888 // allow mousewheel scrolling in
889 // the shell for example
890 on(el, wheelEvent, function(ev) {
891 if (self.mouseEvents) return;
892 if (self.applicationKeypad) return;
893 if (ev.type === 'DOMMouseScroll') {
894 self.scrollDisp(ev.detail < 0 ? -5 : 5);
895 } else {
896 self.scrollDisp(ev.wheelDeltaY > 0 ? -5 : 5);
897 }
898 return cancel(ev);
899 });
900};
901
902/**
903 * Destroy Terminal
904 */
905
906Terminal.prototype.destroy = function() {
907 this.readable = false;
908 this.writable = false;
909 this._events = {};
910 this.handler = function() {};
911 this.write = function() {};
628af053
CJ
912 if (this.element.parentNode) {
913 this.element.parentNode.removeChild(this.element);
914 }
8bc844c0
CJ
915 //this.emit('close');
916};
917
918/**
919 * Rendering Engine
920 */
921
922// In the screen buffer, each character
923// is stored as a an array with a character
924// and a 32-bit integer.
925// First value: a utf-16 character.
926// Second value:
927// Next 9 bits: background color (0-511).
928// Next 9 bits: foreground color (0-511).
929// Next 14 bits: a mask for misc. flags:
930// 1=bold, 2=underline, 4=inverse
931
932Terminal.prototype.refresh = function(start, end) {
933 var x
934 , y
935 , i
936 , line
937 , out
938 , ch
939 , width
940 , data
941 , attr
942 , fgColor
943 , bgColor
944 , flags
945 , row
946 , parent;
947
948 if (end - start >= this.rows / 2) {
949 parent = this.element.parentNode;
950 if (parent) parent.removeChild(this.element);
951 }
952
953 width = this.cols;
954 y = start;
955
628af053
CJ
956 if (end >= this.lines.length) {
957 this.log('`end` is too large. Most likely a bad CSR.');
958 end = this.lines.length - 1;
959 }
8bc844c0
CJ
960
961 for (; y <= end; y++) {
962 row = y + this.ydisp;
963
964 line = this.lines[row];
965 out = '';
966
967 if (y === this.y
968 && this.cursorState
969 && this.ydisp === this.ybase
970 && !this.cursorHidden) {
971 x = this.x;
972 } else {
973 x = -1;
974 }
975
976 attr = this.defAttr;
977 i = 0;
978
979 for (; i < width; i++) {
980 data = line[i][0];
981 ch = line[i][1];
982
983 if (i === x) data = -1;
984
985 if (data !== attr) {
986 if (attr !== this.defAttr) {
987 out += '</span>';
988 }
989 if (data !== this.defAttr) {
990 if (data === -1) {
628af053 991 out += '<span class="reverse-video terminal-cursor">';
8bc844c0
CJ
992 } else {
993 out += '<span style="';
994
995 bgColor = data & 0x1ff;
996 fgColor = (data >> 9) & 0x1ff;
997 flags = data >> 18;
998
999 if (flags & 1) {
1000 if (!Terminal.brokenBold) {
1001 out += 'font-weight:bold;';
1002 }
628af053 1003 // See: XTerm*boldColors
8bc844c0
CJ
1004 if (fgColor < 8) fgColor += 8;
1005 }
1006
1007 if (flags & 2) {
1008 out += 'text-decoration:underline;';
1009 }
1010
1011 if (bgColor !== 256) {
1012 out += 'background-color:'
1013 + Terminal.colors[bgColor]
1014 + ';';
1015 }
1016
1017 if (fgColor !== 257) {
1018 out += 'color:'
1019 + Terminal.colors[fgColor]
1020 + ';';
1021 }
1022
1023 out += '">';
1024 }
1025 }
1026 }
1027
1028 switch (ch) {
1029 case '&':
1030 out += '&amp;';
1031 break;
1032 case '<':
1033 out += '&lt;';
1034 break;
1035 case '>':
1036 out += '&gt;';
1037 break;
1038 default:
1039 if (ch <= ' ') {
1040 out += '&nbsp;';
1041 } else {
848a8381 1042 // if (ch > '\uff00' && wideChars.test(ch)) i++;
8bc844c0
CJ
1043 out += ch;
1044 }
1045 break;
1046 }
1047
1048 attr = data;
1049 }
1050
1051 if (attr !== this.defAttr) {
1052 out += '</span>';
1053 }
1054
1055 this.children[y].innerHTML = out;
1056 }
1057
1058 if (parent) parent.appendChild(this.element);
1059};
1060
1061Terminal.prototype.cursorBlink = function() {
1062 if (Terminal.focus !== this) return;
1063 this.cursorState ^= 1;
1064 this.refresh(this.y, this.y);
1065};
1066
1067Terminal.prototype.showCursor = function() {
1068 if (!this.cursorState) {
1069 this.cursorState = 1;
1070 this.refresh(this.y, this.y);
1071 } else {
1072 // Temporarily disabled:
1073 // this.refreshBlink();
1074 }
1075};
1076
1077Terminal.prototype.startBlink = function() {
1078 if (!Terminal.cursorBlink) return;
1079 var self = this;
1080 this._blinker = function() {
1081 self.cursorBlink();
1082 };
1083 this._blink = setInterval(this._blinker, 500);
1084};
1085
1086Terminal.prototype.refreshBlink = function() {
1087 if (!Terminal.cursorBlink) return;
1088 clearInterval(this._blink);
1089 this._blink = setInterval(this._blinker, 500);
1090};
1091
1092Terminal.prototype.scroll = function() {
1093 var row;
1094
1095 if (++this.ybase === Terminal.scrollback) {
1096 this.ybase = this.ybase / 2 | 0;
1097 this.lines = this.lines.slice(-(this.ybase + this.rows) + 1);
1098 }
1099
1100 this.ydisp = this.ybase;
1101
1102 // last line
1103 row = this.ybase + this.rows - 1;
1104
1105 // subtract the bottom scroll region
1106 row -= this.rows - 1 - this.scrollBottom;
1107
1108 if (row === this.lines.length) {
1109 // potential optimization:
1110 // pushing is faster than splicing
1111 // when they amount to the same
1112 // behavior.
1113 this.lines.push(this.blankLine());
1114 } else {
1115 // add our new line
1116 this.lines.splice(row, 0, this.blankLine());
1117 }
1118
1119 if (this.scrollTop !== 0) {
1120 if (this.ybase !== 0) {
1121 this.ybase--;
1122 this.ydisp = this.ybase;
1123 }
1124 this.lines.splice(this.ybase + this.scrollTop, 1);
1125 }
1126
1127 // this.maxRange();
1128 this.updateRange(this.scrollTop);
1129 this.updateRange(this.scrollBottom);
1130};
1131
1132Terminal.prototype.scrollDisp = function(disp) {
1133 this.ydisp += disp;
1134
1135 if (this.ydisp > this.ybase) {
1136 this.ydisp = this.ybase;
1137 } else if (this.ydisp < 0) {
1138 this.ydisp = 0;
1139 }
1140
1141 this.refresh(0, this.rows - 1);
1142};
1143
1144Terminal.prototype.write = function(data) {
1145 var l = data.length
1146 , i = 0
1147 , cs
1148 , ch;
1149
d5b233b3 1150 // If we want to remove double-width chars entirely.
efa0e3c1 1151 // data = data.replace(wideChars, '?');
d5b233b3 1152
8bc844c0
CJ
1153 this.refreshStart = this.y;
1154 this.refreshEnd = this.y;
1155
1156 if (this.ybase !== this.ydisp) {
1157 this.ydisp = this.ybase;
1158 this.maxRange();
1159 }
1160
1161 // this.log(JSON.stringify(data.replace(/\x1b/g, '^[')));
1162
1163 for (; i < l; i++) {
1164 ch = data[i];
1165 switch (this.state) {
1166 case normal:
1167 switch (ch) {
1168 // '\0'
1169 // case '\0':
1170 // case '\200':
1171 // break;
1172
1173 // '\a'
1174 case '\x07':
1175 this.bell();
1176 break;
1177
1178 // '\n', '\v', '\f'
1179 case '\n':
1180 case '\x0b':
1181 case '\x0c':
1182 if (this.convertEol) {
1183 this.x = 0;
1184 }
1185 // TODO: Implement eat_newline_glitch.
86922c7c 1186 // if (this.realX >= this.cols) break;
8bc844c0
CJ
1187 // this.realX = 0;
1188 this.y++;
1189 if (this.y > this.scrollBottom) {
1190 this.y--;
1191 this.scroll();
1192 }
1193 break;
1194
1195 // '\r'
1196 case '\r':
1197 this.x = 0;
1198 break;
1199
1200 // '\b'
1201 case '\x08':
1202 if (this.x > 0) {
1203 this.x--;
1204 }
1205 break;
1206
1207 // '\t'
1208 case '\t':
1209 this.x = this.nextStop();
1210 break;
1211
1212 // shift out
1213 case '\x0e':
1214 this.setgLevel(1);
1215 break;
1216
1217 // shift in
1218 case '\x0f':
1219 this.setgLevel(0);
1220 break;
1221
1222 // '\e'
1223 case '\x1b':
1224 this.state = escaped;
1225 break;
1226
1227 default:
1228 // ' '
1229 if (ch >= ' ') {
1230 if (this.charset && this.charset[ch]) {
1231 ch = this.charset[ch];
1232 }
1233 if (this.x >= this.cols) {
1234 this.x = 0;
1235 this.y++;
1236 if (this.y > this.scrollBottom) {
1237 this.y--;
1238 this.scroll();
1239 }
1240 }
1241 this.lines[this.y + this.ybase][this.x] = [this.curAttr, ch];
1242 this.x++;
1243 this.updateRange(this.y);
efa0e3c1 1244
848a8381 1245 // if (ch > '\uff00' && wideChars.test(ch)) {
efa0e3c1
CJ
1246 // if (this.cols < 2) {
1247 // this.lines[this.y + this.ybase][this.x - 1][1] = ' ';
1248 // break;
1249 // }
1250 // this.x++;
1251 // if (this.x >= this.cols) {
1252 // this.lines[this.y + this.ybase][this.x - 2][1] = ' ';
1253 // // Do something like: this.write(ch);
1254 // }
1255 // }
8bc844c0
CJ
1256 }
1257 break;
1258 }
1259 break;
1260 case escaped:
1261 switch (ch) {
1262 // ESC [ Control Sequence Introducer ( CSI is 0x9b).
1263 case '[':
1264 this.params = [];
1265 this.currentParam = 0;
1266 this.state = csi;
1267 break;
1268
1269 // ESC ] Operating System Command ( OSC is 0x9d).
1270 case ']':
1271 this.params = [];
1272 this.currentParam = 0;
1273 this.state = osc;
1274 break;
1275
1276 // ESC P Device Control String ( DCS is 0x90).
1277 case 'P':
1278 this.params = [];
1279 this.currentParam = 0;
1280 this.state = dcs;
1281 break;
1282
1283 // ESC _ Application Program Command ( APC is 0x9f).
1284 case '_':
1285 this.state = ignore;
1286 break;
1287
1288 // ESC ^ Privacy Message ( PM is 0x9e).
1289 case '^':
1290 this.state = ignore;
1291 break;
1292
1293 // ESC c Full Reset (RIS).
1294 case 'c':
1295 this.reset();
1296 break;
1297
1298 // ESC E Next Line ( NEL is 0x85).
1299 // ESC D Index ( IND is 0x84).
1300 case 'E':
1301 this.x = 0;
1302 ;
1303 case 'D':
1304 this.index();
1305 break;
1306
1307 // ESC M Reverse Index ( RI is 0x8d).
1308 case 'M':
1309 this.reverseIndex();
1310 break;
1311
1312 // ESC % Select default/utf-8 character set.
1313 // @ = default, G = utf-8
1314 case '%':
1315 //this.charset = null;
1316 this.setgLevel(0);
1317 this.setgCharset(0, Terminal.charsets.US);
1318 this.state = normal;
1319 i++;
1320 break;
1321
1322 // ESC (,),*,+,-,. Designate G0-G2 Character Set.
1323 case '(': // <-- this seems to get all the attention
1324 case ')':
1325 case '*':
1326 case '+':
1327 case '-':
1328 case '.':
1329 switch (ch) {
1330 case '(':
1331 this.gcharset = 0;
1332 break;
1333 case ')':
1334 this.gcharset = 1;
1335 break;
1336 case '*':
1337 this.gcharset = 2;
1338 break;
1339 case '+':
1340 this.gcharset = 3;
1341 break;
1342 case '-':
1343 this.gcharset = 1;
1344 break;
1345 case '.':
1346 this.gcharset = 2;
1347 break;
1348 }
1349 this.state = charset;
1350 break;
1351
1352 // Designate G3 Character Set (VT300).
1353 // A = ISO Latin-1 Supplemental.
1354 // Not implemented.
1355 case '/':
1356 this.gcharset = 3;
1357 this.state = charset;
1358 i--;
1359 break;
1360
1361 // ESC N
1362 // Single Shift Select of G2 Character Set
1363 // ( SS2 is 0x8e). This affects next character only.
1364 case 'N':
1365 break;
1366 // ESC O
1367 // Single Shift Select of G3 Character Set
1368 // ( SS3 is 0x8f). This affects next character only.
1369 case 'O':
1370 break;
1371 // ESC n
1372 // Invoke the G2 Character Set as GL (LS2).
1373 case 'n':
1374 this.setgLevel(2);
1375 break;
1376 // ESC o
1377 // Invoke the G3 Character Set as GL (LS3).
1378 case 'o':
1379 this.setgLevel(3);
1380 break;
1381 // ESC |
1382 // Invoke the G3 Character Set as GR (LS3R).
1383 case '|':
1384 this.setgLevel(3);
1385 break;
1386 // ESC }
1387 // Invoke the G2 Character Set as GR (LS2R).
1388 case '}':
1389 this.setgLevel(2);
1390 break;
1391 // ESC ~
1392 // Invoke the G1 Character Set as GR (LS1R).
1393 case '~':
1394 this.setgLevel(1);
1395 break;
1396
1397 // ESC 7 Save Cursor (DECSC).
1398 case '7':
1399 this.saveCursor();
1400 this.state = normal;
1401 break;
1402
1403 // ESC 8 Restore Cursor (DECRC).
1404 case '8':
1405 this.restoreCursor();
1406 this.state = normal;
1407 break;
1408
1409 // ESC # 3 DEC line height/width
1410 case '#':
1411 this.state = normal;
1412 i++;
1413 break;
1414
1415 // ESC H Tab Set (HTS is 0x88).
1416 case 'H':
1417 this.tabSet();
1418 break;
1419
1420 // ESC = Application Keypad (DECPAM).
1421 case '=':
1422 this.log('Serial port requested application keypad.');
1423 this.applicationKeypad = true;
1424 this.state = normal;
1425 break;
1426
1427 // ESC > Normal Keypad (DECPNM).
1428 case '>':
1429 this.log('Switching back to normal keypad.');
1430 this.applicationKeypad = false;
1431 this.state = normal;
1432 break;
1433
1434 default:
1435 this.state = normal;
1436 this.error('Unknown ESC control: %s.', ch);
1437 break;
1438 }
1439 break;
1440
1441 case charset:
1442 switch (ch) {
1443 case '0': // DEC Special Character and Line Drawing Set.
1444 cs = Terminal.charsets.SCLD;
1445 break;
1446 case 'A': // UK
1447 cs = Terminal.charsets.UK;
1448 break;
1449 case 'B': // United States (USASCII).
1450 cs = Terminal.charsets.US;
1451 break;
1452 case '4': // Dutch
1453 cs = Terminal.charsets.Dutch;
1454 break;
1455 case 'C': // Finnish
1456 case '5':
1457 cs = Terminal.charsets.Finnish;
1458 break;
1459 case 'R': // French
1460 cs = Terminal.charsets.French;
1461 break;
1462 case 'Q': // FrenchCanadian
1463 cs = Terminal.charsets.FrenchCanadian;
1464 break;
1465 case 'K': // German
1466 cs = Terminal.charsets.German;
1467 break;
1468 case 'Y': // Italian
1469 cs = Terminal.charsets.Italian;
1470 break;
1471 case 'E': // NorwegianDanish
1472 case '6':
1473 cs = Terminal.charsets.NorwegianDanish;
1474 break;
1475 case 'Z': // Spanish
1476 cs = Terminal.charsets.Spanish;
1477 break;
1478 case 'H': // Swedish
1479 case '7':
1480 cs = Terminal.charsets.Swedish;
1481 break;
1482 case '=': // Swiss
1483 cs = Terminal.charsets.Swiss;
1484 break;
1485 case '/': // ISOLatin (actually /A)
1486 cs = Terminal.charsets.ISOLatin;
1487 i++;
1488 break;
1489 default: // Default
1490 cs = Terminal.charsets.US;
1491 break;
1492 }
1493 this.setgCharset(this.gcharset, cs);
1494 this.gcharset = null;
1495 this.state = normal;
1496 break;
1497
1498 case osc:
1499 // OSC Ps ; Pt ST
1500 // OSC Ps ; Pt BEL
1501 // Set Text Parameters.
1502 if (ch === '\x1b' || ch === '\x07') {
1503 if (ch === '\x1b') i++;
1504
1505 this.params.push(this.currentParam);
1506
1507 switch (this.params[0]) {
1508 case 0:
1509 case 1:
1510 case 2:
1511 if (this.params[1]) {
1512 this.title = this.params[1];
1513 this.handleTitle(this.title);
1514 }
1515 break;
1516 case 3:
1517 // set X property
1518 break;
1519 case 4:
1520 case 5:
1521 // change dynamic colors
1522 break;
1523 case 10:
1524 case 11:
1525 case 12:
1526 case 13:
1527 case 14:
1528 case 15:
1529 case 16:
1530 case 17:
1531 case 18:
1532 case 19:
1533 // change dynamic ui colors
1534 break;
1535 case 46:
1536 // change log file
1537 break;
1538 case 50:
1539 // dynamic font
1540 break;
1541 case 51:
1542 // emacs shell
1543 break;
1544 case 52:
1545 // manipulate selection data
1546 break;
1547 case 104:
1548 case 105:
1549 case 110:
1550 case 111:
1551 case 112:
1552 case 113:
1553 case 114:
1554 case 115:
1555 case 116:
1556 case 117:
1557 case 118:
1558 // reset colors
1559 break;
1560 }
1561
1562 this.params = [];
1563 this.currentParam = 0;
1564 this.state = normal;
1565 } else {
1566 if (!this.params.length) {
1567 if (ch >= '0' && ch <= '9') {
1568 this.currentParam =
1569 this.currentParam * 10 + ch.charCodeAt(0) - 48;
1570 } else if (ch === ';') {
1571 this.params.push(this.currentParam);
1572 this.currentParam = '';
1573 }
1574 } else {
1575 this.currentParam += ch;
1576 }
1577 }
1578 break;
1579
1580 case csi:
1581 // '?', '>', '!'
1582 if (ch === '?' || ch === '>' || ch === '!') {
1583 this.prefix = ch;
1584 break;
1585 }
1586
1587 // 0 - 9
1588 if (ch >= '0' && ch <= '9') {
1589 this.currentParam = this.currentParam * 10 + ch.charCodeAt(0) - 48;
1590 break;
1591 }
1592
1593 // '$', '"', ' ', '\''
1594 if (ch === '$' || ch === '"' || ch === ' ' || ch === '\'') {
1595 this.postfix = ch;
1596 break;
1597 }
1598
1599 this.params.push(this.currentParam);
1600 this.currentParam = 0;
1601
1602 // ';'
1603 if (ch === ';') break;
1604
1605 this.state = normal;
1606
1607 switch (ch) {
1608 // CSI Ps A
1609 // Cursor Up Ps Times (default = 1) (CUU).
1610 case 'A':
1611 this.cursorUp(this.params);
1612 break;
1613
1614 // CSI Ps B
1615 // Cursor Down Ps Times (default = 1) (CUD).
1616 case 'B':
1617 this.cursorDown(this.params);
1618 break;
1619
1620 // CSI Ps C
1621 // Cursor Forward Ps Times (default = 1) (CUF).
1622 case 'C':
1623 this.cursorForward(this.params);
1624 break;
1625
1626 // CSI Ps D
1627 // Cursor Backward Ps Times (default = 1) (CUB).
1628 case 'D':
1629 this.cursorBackward(this.params);
1630 break;
1631
1632 // CSI Ps ; Ps H
1633 // Cursor Position [row;column] (default = [1,1]) (CUP).
1634 case 'H':
1635 this.cursorPos(this.params);
1636 break;
1637
1638 // CSI Ps J Erase in Display (ED).
1639 case 'J':
1640 this.eraseInDisplay(this.params);
1641 break;
1642
1643 // CSI Ps K Erase in Line (EL).
1644 case 'K':
1645 this.eraseInLine(this.params);
1646 break;
1647
1648 // CSI Pm m Character Attributes (SGR).
1649 case 'm':
1650 this.charAttributes(this.params);
1651 break;
1652
1653 // CSI Ps n Device Status Report (DSR).
1654 case 'n':
1655 this.deviceStatus(this.params);
1656 break;
1657
1658 /**
1659 * Additions
1660 */
1661
1662 // CSI Ps @
1663 // Insert Ps (Blank) Character(s) (default = 1) (ICH).
1664 case '@':
1665 this.insertChars(this.params);
1666 break;
1667
1668 // CSI Ps E
1669 // Cursor Next Line Ps Times (default = 1) (CNL).
1670 case 'E':
1671 this.cursorNextLine(this.params);
1672 break;
1673
1674 // CSI Ps F
1675 // Cursor Preceding Line Ps Times (default = 1) (CNL).
1676 case 'F':
1677 this.cursorPrecedingLine(this.params);
1678 break;
1679
1680 // CSI Ps G
1681 // Cursor Character Absolute [column] (default = [row,1]) (CHA).
1682 case 'G':
1683 this.cursorCharAbsolute(this.params);
1684 break;
1685
1686 // CSI Ps L
1687 // Insert Ps Line(s) (default = 1) (IL).
1688 case 'L':
1689 this.insertLines(this.params);
1690 break;
1691
1692 // CSI Ps M
1693 // Delete Ps Line(s) (default = 1) (DL).
1694 case 'M':
1695 this.deleteLines(this.params);
1696 break;
1697
1698 // CSI Ps P
1699 // Delete Ps Character(s) (default = 1) (DCH).
1700 case 'P':
1701 this.deleteChars(this.params);
1702 break;
1703
1704 // CSI Ps X
1705 // Erase Ps Character(s) (default = 1) (ECH).
1706 case 'X':
1707 this.eraseChars(this.params);
1708 break;
1709
1710 // CSI Pm ` Character Position Absolute
1711 // [column] (default = [row,1]) (HPA).
1712 case '`':
1713 this.charPosAbsolute(this.params);
1714 break;
1715
1716 // 141 61 a * HPR -
1717 // Horizontal Position Relative
1718 case 'a':
1719 this.HPositionRelative(this.params);
1720 break;
1721
1722 // CSI P s c
1723 // Send Device Attributes (Primary DA).
1724 // CSI > P s c
1725 // Send Device Attributes (Secondary DA)
1726 case 'c':
1727 this.sendDeviceAttributes(this.params);
1728 break;
1729
1730 // CSI Pm d
1731 // Line Position Absolute [row] (default = [1,column]) (VPA).
1732 case 'd':
1733 this.linePosAbsolute(this.params);
1734 break;
1735
1736 // 145 65 e * VPR - Vertical Position Relative
1737 case 'e':
1738 this.VPositionRelative(this.params);
1739 break;
1740
1741 // CSI Ps ; Ps f
1742 // Horizontal and Vertical Position [row;column] (default =
1743 // [1,1]) (HVP).
1744 case 'f':
1745 this.HVPosition(this.params);
1746 break;
1747
1748 // CSI Pm h Set Mode (SM).
1749 // CSI ? Pm h - mouse escape codes, cursor escape codes
1750 case 'h':
1751 this.setMode(this.params);
1752 break;
1753
1754 // CSI Pm l Reset Mode (RM).
1755 // CSI ? Pm l
1756 case 'l':
1757 this.resetMode(this.params);
1758 break;
1759
1760 // CSI Ps ; Ps r
1761 // Set Scrolling Region [top;bottom] (default = full size of win-
1762 // dow) (DECSTBM).
1763 // CSI ? Pm r
1764 case 'r':
1765 this.setScrollRegion(this.params);
1766 break;
1767
1768 // CSI s
1769 // Save cursor (ANSI.SYS).
1770 case 's':
1771 this.saveCursor(this.params);
1772 break;
1773
1774 // CSI u
1775 // Restore cursor (ANSI.SYS).
1776 case 'u':
1777 this.restoreCursor(this.params);
1778 break;
1779
1780 /**
1781 * Lesser Used
1782 */
1783
1784 // CSI Ps I
1785 // Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
1786 case 'I':
1787 this.cursorForwardTab(this.params);
1788 break;
1789
1790 // CSI Ps S Scroll up Ps lines (default = 1) (SU).
1791 case 'S':
1792 this.scrollUp(this.params);
1793 break;
1794
1795 // CSI Ps T Scroll down Ps lines (default = 1) (SD).
1796 // CSI Ps ; Ps ; Ps ; Ps ; Ps T
1797 // CSI > Ps; Ps T
1798 case 'T':
1799 // if (this.prefix === '>') {
1800 // this.resetTitleModes(this.params);
1801 // break;
1802 // }
1803 // if (this.params.length > 2) {
1804 // this.initMouseTracking(this.params);
1805 // break;
1806 // }
1807 if (this.params.length < 2 && !this.prefix) {
1808 this.scrollDown(this.params);
1809 }
1810 break;
1811
1812 // CSI Ps Z
1813 // Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
1814 case 'Z':
1815 this.cursorBackwardTab(this.params);
1816 break;
1817
1818 // CSI Ps b Repeat the preceding graphic character Ps times (REP).
1819 case 'b':
1820 this.repeatPrecedingCharacter(this.params);
1821 break;
1822
1823 // CSI Ps g Tab Clear (TBC).
1824 case 'g':
1825 this.tabClear(this.params);
1826 break;
1827
1828 // CSI Pm i Media Copy (MC).
1829 // CSI ? Pm i
1830 // case 'i':
1831 // this.mediaCopy(this.params);
1832 // break;
1833
1834 // CSI Pm m Character Attributes (SGR).
1835 // CSI > Ps; Ps m
1836 // case 'm': // duplicate
1837 // if (this.prefix === '>') {
1838 // this.setResources(this.params);
1839 // } else {
1840 // this.charAttributes(this.params);
1841 // }
1842 // break;
1843
1844 // CSI Ps n Device Status Report (DSR).
1845 // CSI > Ps n
1846 // case 'n': // duplicate
1847 // if (this.prefix === '>') {
1848 // this.disableModifiers(this.params);
1849 // } else {
1850 // this.deviceStatus(this.params);
1851 // }
1852 // break;
1853
1854 // CSI > Ps p Set pointer mode.
1855 // CSI ! p Soft terminal reset (DECSTR).
1856 // CSI Ps$ p
1857 // Request ANSI mode (DECRQM).
1858 // CSI ? Ps$ p
1859 // Request DEC private mode (DECRQM).
1860 // CSI Ps ; Ps " p
1861 case 'p':
1862 switch (this.prefix) {
1863 // case '>':
1864 // this.setPointerMode(this.params);
1865 // break;
1866 case '!':
1867 this.softReset(this.params);
1868 break;
1869 // case '?':
1870 // if (this.postfix === '$') {
1871 // this.requestPrivateMode(this.params);
1872 // }
1873 // break;
1874 // default:
1875 // if (this.postfix === '"') {
1876 // this.setConformanceLevel(this.params);
1877 // } else if (this.postfix === '$') {
1878 // this.requestAnsiMode(this.params);
1879 // }
1880 // break;
1881 }
1882 break;
1883
1884 // CSI Ps q Load LEDs (DECLL).
1885 // CSI Ps SP q
1886 // CSI Ps " q
1887 // case 'q':
1888 // if (this.postfix === ' ') {
1889 // this.setCursorStyle(this.params);
1890 // break;
1891 // }
1892 // if (this.postfix === '"') {
1893 // this.setCharProtectionAttr(this.params);
1894 // break;
1895 // }
1896 // this.loadLEDs(this.params);
1897 // break;
1898
1899 // CSI Ps ; Ps r
1900 // Set Scrolling Region [top;bottom] (default = full size of win-
1901 // dow) (DECSTBM).
1902 // CSI ? Pm r
1903 // CSI Pt; Pl; Pb; Pr; Ps$ r
1904 // case 'r': // duplicate
1905 // if (this.prefix === '?') {
1906 // this.restorePrivateValues(this.params);
1907 // } else if (this.postfix === '$') {
1908 // this.setAttrInRectangle(this.params);
1909 // } else {
1910 // this.setScrollRegion(this.params);
1911 // }
1912 // break;
1913
1914 // CSI s Save cursor (ANSI.SYS).
1915 // CSI ? Pm s
1916 // case 's': // duplicate
1917 // if (this.prefix === '?') {
1918 // this.savePrivateValues(this.params);
1919 // } else {
1920 // this.saveCursor(this.params);
1921 // }
1922 // break;
1923
1924 // CSI Ps ; Ps ; Ps t
1925 // CSI Pt; Pl; Pb; Pr; Ps$ t
1926 // CSI > Ps; Ps t
1927 // CSI Ps SP t
1928 // case 't':
1929 // if (this.postfix === '$') {
1930 // this.reverseAttrInRectangle(this.params);
1931 // } else if (this.postfix === ' ') {
1932 // this.setWarningBellVolume(this.params);
1933 // } else {
1934 // if (this.prefix === '>') {
1935 // this.setTitleModeFeature(this.params);
1936 // } else {
1937 // this.manipulateWindow(this.params);
1938 // }
1939 // }
1940 // break;
1941
1942 // CSI u Restore cursor (ANSI.SYS).
1943 // CSI Ps SP u
1944 // case 'u': // duplicate
1945 // if (this.postfix === ' ') {
1946 // this.setMarginBellVolume(this.params);
1947 // } else {
1948 // this.restoreCursor(this.params);
1949 // }
1950 // break;
1951
1952 // CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v
1953 // case 'v':
1954 // if (this.postfix === '$') {
1955 // this.copyRectagle(this.params);
1956 // }
1957 // break;
1958
1959 // CSI Pt ; Pl ; Pb ; Pr ' w
1960 // case 'w':
1961 // if (this.postfix === '\'') {
1962 // this.enableFilterRectangle(this.params);
1963 // }
1964 // break;
1965
1966 // CSI Ps x Request Terminal Parameters (DECREQTPARM).
1967 // CSI Ps x Select Attribute Change Extent (DECSACE).
1968 // CSI Pc; Pt; Pl; Pb; Pr$ x
1969 // case 'x':
1970 // if (this.postfix === '$') {
1971 // this.fillRectangle(this.params);
1972 // } else {
1973 // this.requestParameters(this.params);
1974 // //this.__(this.params);
1975 // }
1976 // break;
1977
1978 // CSI Ps ; Pu ' z
1979 // CSI Pt; Pl; Pb; Pr$ z
1980 // case 'z':
1981 // if (this.postfix === '\'') {
1982 // this.enableLocatorReporting(this.params);
1983 // } else if (this.postfix === '$') {
1984 // this.eraseRectangle(this.params);
1985 // }
1986 // break;
1987
1988 // CSI Pm ' {
1989 // CSI Pt; Pl; Pb; Pr$ {
1990 // case '{':
1991 // if (this.postfix === '\'') {
1992 // this.setLocatorEvents(this.params);
1993 // } else if (this.postfix === '$') {
1994 // this.selectiveEraseRectangle(this.params);
1995 // }
1996 // break;
1997
1998 // CSI Ps ' |
1999 // case '|':
2000 // if (this.postfix === '\'') {
2001 // this.requestLocatorPosition(this.params);
2002 // }
2003 // break;
2004
2005 // CSI P m SP }
2006 // Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
2007 // case '}':
2008 // if (this.postfix === ' ') {
2009 // this.insertColumns(this.params);
2010 // }
2011 // break;
2012
2013 // CSI P m SP ~
2014 // Delete P s Column(s) (default = 1) (DECDC), VT420 and up
2015 // case '~':
2016 // if (this.postfix === ' ') {
2017 // this.deleteColumns(this.params);
2018 // }
2019 // break;
2020
2021 default:
2022 this.error('Unknown CSI code: %s.', ch);
2023 break;
2024 }
2025
2026 this.prefix = '';
2027 this.postfix = '';
2028 break;
2029
2030 case dcs:
2031 if (ch === '\x1b' || ch === '\x07') {
2032 if (ch === '\x1b') i++;
2033
2034 switch (this.prefix) {
2035 // User-Defined Keys (DECUDK).
2036 case '':
2037 break;
2038
2039 // Request Status String (DECRQSS).
2040 // test: echo -e '\eP$q"p\e\\'
2041 case '$q':
2042 var pt = this.currentParam
2043 , valid = false;
2044
2045 switch (pt) {
2046 // DECSCA
2047 case '"q':
2048 pt = '0"q';
2049 break;
2050
2051 // DECSCL
2052 case '"p':
2053 pt = '61"p';
2054 break;
2055
2056 // DECSTBM
2057 case 'r':
2058 pt = ''
2059 + (this.scrollTop + 1)
2060 + ';'
2061 + (this.scrollBottom + 1)
2062 + 'r';
2063 break;
2064
2065 // SGR
2066 case 'm':
2067 pt = '0m';
2068 break;
2069
2070 default:
2071 this.error('Unknown DCS Pt: %s.', pt);
2072 pt = '';
2073 break;
2074 }
2075
2076 this.send('\x1bP' + +valid + '$r' + pt + '\x1b\\');
2077 break;
2078
2079 // Set Termcap/Terminfo Data (xterm, experimental).
2080 case '+p':
2081 break;
2082
2083 // Request Termcap/Terminfo String (xterm, experimental)
2084 // Regular xterm does not even respond to this sequence.
2085 // This can cause a small glitch in vim.
2086 // test: echo -ne '\eP+q6b64\e\\'
2087 case '+q':
2088 var pt = this.currentParam
2089 , valid = false;
2090
2091 this.send('\x1bP' + +valid + '+r' + pt + '\x1b\\');
2092 break;
2093
2094 default:
2095 this.error('Unknown DCS prefix: %s.', this.prefix);
2096 break;
2097 }
2098
2099 this.currentParam = 0;
2100 this.prefix = '';
2101 this.state = normal;
2102 } else if (!this.currentParam) {
2103 if (!this.prefix && ch !== '$' && ch !== '+') {
2104 this.currentParam = ch;
2105 } else if (this.prefix.length === 2) {
2106 this.currentParam = ch;
2107 } else {
2108 this.prefix += ch;
2109 }
2110 } else {
2111 this.currentParam += ch;
2112 }
2113 break;
2114
2115 case ignore:
2116 // For PM and APC.
2117 if (ch === '\x1b' || ch === '\x07') {
2118 if (ch === '\x1b') i++;
2119 this.state = normal;
2120 }
2121 break;
2122 }
2123 }
2124
2125 this.updateRange(this.y);
2126 this.refresh(this.refreshStart, this.refreshEnd);
2127};
2128
2129Terminal.prototype.writeln = function(data) {
2130 this.write(data + '\r\n');
2131};
2132
2133// Key Resources:
2134// https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
2135Terminal.prototype.keyDown = function(ev) {
2136 var key;
2137
2138 switch (ev.keyCode) {
2139 // backspace
2140 case 8:
2141 if (ev.shiftKey) {
2142 key = '\x08'; // ^H
2143 break;
2144 }
2145 key = '\x7f'; // ^?
2146 break;
2147 // tab
2148 case 9:
2149 if (ev.shiftKey) {
2150 key = '\x1b[Z';
2151 break;
2152 }
2153 key = '\t';
2154 break;
2155 // return/enter
2156 case 13:
2157 key = '\r';
2158 break;
2159 // escape
2160 case 27:
2161 key = '\x1b';
2162 break;
2163 // left-arrow
2164 case 37:
2165 if (this.applicationCursor) {
2166 key = '\x1bOD'; // SS3 as ^[O for 7-bit
2167 //key = '\x8fD'; // SS3 as 0x8f for 8-bit
2168 break;
2169 }
2170 key = '\x1b[D';
2171 break;
2172 // right-arrow
2173 case 39:
2174 if (this.applicationCursor) {
2175 key = '\x1bOC';
2176 break;
2177 }
2178 key = '\x1b[C';
2179 break;
2180 // up-arrow
2181 case 38:
2182 if (this.applicationCursor) {
2183 key = '\x1bOA';
2184 break;
2185 }
2186 if (ev.ctrlKey) {
2187 this.scrollDisp(-1);
2188 return cancel(ev);
2189 } else {
2190 key = '\x1b[A';
2191 }
2192 break;
2193 // down-arrow
2194 case 40:
2195 if (this.applicationCursor) {
2196 key = '\x1bOB';
2197 break;
2198 }
2199 if (ev.ctrlKey) {
2200 this.scrollDisp(1);
2201 return cancel(ev);
2202 } else {
2203 key = '\x1b[B';
2204 }
2205 break;
2206 // delete
2207 case 46:
2208 key = '\x1b[3~';
2209 break;
2210 // insert
2211 case 45:
2212 key = '\x1b[2~';
2213 break;
2214 // home
2215 case 36:
2216 if (this.applicationKeypad) {
2217 key = '\x1bOH';
2218 break;
2219 }
2220 key = '\x1bOH';
2221 break;
2222 // end
2223 case 35:
2224 if (this.applicationKeypad) {
2225 key = '\x1bOF';
2226 break;
2227 }
2228 key = '\x1bOF';
2229 break;
2230 // page up
2231 case 33:
2232 if (ev.shiftKey) {
2233 this.scrollDisp(-(this.rows - 1));
2234 return cancel(ev);
2235 } else {
2236 key = '\x1b[5~';
2237 }
2238 break;
2239 // page down
2240 case 34:
2241 if (ev.shiftKey) {
2242 this.scrollDisp(this.rows - 1);
2243 return cancel(ev);
2244 } else {
2245 key = '\x1b[6~';
2246 }
2247 break;
2248 // F1
2249 case 112:
2250 key = '\x1bOP';
2251 break;
2252 // F2
2253 case 113:
2254 key = '\x1bOQ';
2255 break;
2256 // F3
2257 case 114:
2258 key = '\x1bOR';
2259 break;
2260 // F4
2261 case 115:
2262 key = '\x1bOS';
2263 break;
2264 // F5
2265 case 116:
2266 key = '\x1b[15~';
2267 break;
2268 // F6
2269 case 117:
2270 key = '\x1b[17~';
2271 break;
2272 // F7
2273 case 118:
2274 key = '\x1b[18~';
2275 break;
2276 // F8
2277 case 119:
2278 key = '\x1b[19~';
2279 break;
2280 // F9
2281 case 120:
2282 key = '\x1b[20~';
2283 break;
2284 // F10
2285 case 121:
2286 key = '\x1b[21~';
2287 break;
2288 // F11
2289 case 122:
2290 key = '\x1b[23~';
2291 break;
2292 // F12
2293 case 123:
2294 key = '\x1b[24~';
2295 break;
2296 default:
2297 // a-z and space
2298 if (ev.ctrlKey) {
2299 if (ev.keyCode >= 65 && ev.keyCode <= 90) {
2300 key = String.fromCharCode(ev.keyCode - 64);
2301 } else if (ev.keyCode === 32) {
2302 // NUL
2303 key = String.fromCharCode(0);
2304 } else if (ev.keyCode >= 51 && ev.keyCode <= 55) {
2305 // escape, file sep, group sep, record sep, unit sep
2306 key = String.fromCharCode(ev.keyCode - 51 + 27);
2307 } else if (ev.keyCode === 56) {
2308 // delete
2309 key = String.fromCharCode(127);
2310 } else if (ev.keyCode === 219) {
2311 // ^[ - escape
2312 key = String.fromCharCode(27);
2313 } else if (ev.keyCode === 221) {
2314 // ^] - group sep
2315 key = String.fromCharCode(29);
2316 }
2317 } else if ((!isMac && ev.altKey) || (isMac && ev.metaKey)) {
2318 if (ev.keyCode >= 65 && ev.keyCode <= 90) {
2319 key = '\x1b' + String.fromCharCode(ev.keyCode + 32);
2320 } else if (ev.keyCode === 192) {
2321 key = '\x1b`';
2322 } else if (ev.keyCode >= 48 && ev.keyCode <= 57) {
2323 key = '\x1b' + (ev.keyCode - 48);
2324 }
2325 }
2326 break;
2327 }
2328
2329 this.emit('keydown', ev);
2330 // if (this.emit('keydown', key, ev) === false) { this.showCursor(); cancel(ev); return; }
2331
2332 if (key) {
2333 this.emit('key', key, ev);
2334 // if (this.emit('key', key, ev) === false) { this.showCursor(); cancel(ev); return; }
2335
2336 this.showCursor();
2337 this.handler(key);
2338
2339 return cancel(ev);
2340 }
2341
2342 return true;
2343};
2344
2345Terminal.prototype.setgLevel = function(g) {
2346 this.glevel = g;
2347 this.charset = this.charsets[g];
2348};
2349
2350Terminal.prototype.setgCharset = function(g, charset) {
2351 this.charsets[g] = charset;
2352 if (this.glevel === g) {
2353 this.charset = charset;
2354 }
2355};
2356
2357Terminal.prototype.keyPress = function(ev) {
2358 var key;
2359
2360 cancel(ev);
2361
2362 if (ev.charCode) {
2363 key = ev.charCode;
2364 } else if (ev.which == null) {
2365 key = ev.keyCode;
2366 } else if (ev.which !== 0 && ev.charCode !== 0) {
2367 key = ev.which;
2368 } else {
2369 return false;
2370 }
2371
2372 if (!key || ev.ctrlKey || ev.altKey || ev.metaKey) return false;
2373
2374 key = String.fromCharCode(key);
2375
2376 this.emit('keypress', key, ev);
2377 // if (this.emit('keypress', key, ev) === false) { this.showCursor(); return; }
2378 this.emit('key', key, ev);
2379 // if (this.emit('key', key, ev) === false) { this.showCursor(); return; }
2380
2381 this.showCursor();
2382 this.handler(key);
2383
2384 return false;
2385};
2386
2387Terminal.prototype.send = function(data) {
2388 var self = this;
2389
2390 if (!this.queue) {
2391 setTimeout(function() {
2392 self.handler(self.queue);
2393 self.queue = '';
2394 }, 1);
2395 }
2396
2397 this.queue += data;
2398};
2399
2400Terminal.prototype.bell = function() {
2401 if (!Terminal.visualBell) return;
2402 var self = this;
2403 this.element.style.borderColor = 'white';
2404 setTimeout(function() {
2405 self.element.style.borderColor = '';
2406 }, 10);
2407 if (Terminal.popOnBell) this.focus();
2408};
2409
2410Terminal.prototype.log = function() {
2411 if (!Terminal.debug) return;
91273161 2412 if (!this.context.console || !this.context.console.log) return;
8bc844c0 2413 var args = Array.prototype.slice.call(arguments);
91273161 2414 this.context.console.log.apply(this.context.console, args);
8bc844c0
CJ
2415};
2416
2417Terminal.prototype.error = function() {
2418 if (!Terminal.debug) return;
91273161 2419 if (!this.context.console || !this.context.console.error) return;
8bc844c0 2420 var args = Array.prototype.slice.call(arguments);
91273161 2421 this.context.console.error.apply(this.context.console, args);
8bc844c0
CJ
2422};
2423
2424Terminal.prototype.resize = function(x, y) {
2425 var line
2426 , el
2427 , i
2428 , j
2429 , ch;
2430
2431 if (x < 1) x = 1;
2432 if (y < 1) y = 1;
2433
2434 // resize cols
2435 j = this.cols;
2436 if (j < x) {
2437 ch = [this.defAttr, ' ']; // does xterm use the default attr?
2438 i = this.lines.length;
2439 while (i--) {
2440 while (this.lines[i].length < x) {
2441 this.lines[i].push(ch);
2442 }
2443 }
2444 } else if (j > x) {
2445 i = this.lines.length;
2446 while (i--) {
2447 while (this.lines[i].length > x) {
2448 this.lines[i].pop();
2449 }
2450 }
2451 }
2452 this.setupStops(j);
2453 this.cols = x;
2454
2455 // resize rows
2456 j = this.rows;
2457 if (j < y) {
2458 el = this.element;
2459 while (j++ < y) {
2460 if (this.lines.length < y + this.ybase) {
2461 this.lines.push(this.blankLine());
2462 }
2463 if (this.children.length < y) {
91273161 2464 line = this.document.createElement('div');
8bc844c0
CJ
2465 el.appendChild(line);
2466 this.children.push(line);
2467 }
2468 }
2469 } else if (j > y) {
2470 while (j-- > y) {
2471 if (this.lines.length > y + this.ybase) {
2472 this.lines.pop();
2473 }
2474 if (this.children.length > y) {
2475 el = this.children.pop();
2476 if (!el) continue;
2477 el.parentNode.removeChild(el);
2478 }
2479 }
2480 }
2481 this.rows = y;
2482
2483 // make sure the cursor stays on screen
2484 if (this.y >= y) this.y = y - 1;
2485 if (this.x >= x) this.x = x - 1;
2486
2487 this.scrollTop = 0;
2488 this.scrollBottom = y - 1;
2489
2490 this.refresh(0, this.rows - 1);
2491
2492 // it's a real nightmare trying
2493 // to resize the original
2494 // screen buffer. just set it
2495 // to null for now.
2496 this.normal = null;
2497};
2498
2499Terminal.prototype.updateRange = function(y) {
2500 if (y < this.refreshStart) this.refreshStart = y;
2501 if (y > this.refreshEnd) this.refreshEnd = y;
2502 // if (y > this.refreshEnd) {
2503 // this.refreshEnd = y;
2504 // if (y > this.rows - 1) {
2505 // this.refreshEnd = this.rows - 1;
2506 // }
2507 // }
2508};
2509
2510Terminal.prototype.maxRange = function() {
2511 this.refreshStart = 0;
2512 this.refreshEnd = this.rows - 1;
2513};
2514
2515Terminal.prototype.setupStops = function(i) {
2516 if (i != null) {
2517 if (!this.tabs[i]) {
2518 i = this.prevStop(i);
2519 }
2520 } else {
2521 this.tabs = {};
2522 i = 0;
2523 }
2524
2525 for (; i < this.cols; i += 8) {
2526 this.tabs[i] = true;
2527 }
2528};
2529
2530Terminal.prototype.prevStop = function(x) {
2531 if (x == null) x = this.x;
2532 while (!this.tabs[--x] && x > 0);
2533 return x >= this.cols
2534 ? this.cols - 1
2535 : x < 0 ? 0 : x;
2536};
2537
2538Terminal.prototype.nextStop = function(x) {
2539 if (x == null) x = this.x;
2540 while (!this.tabs[++x] && x < this.cols);
2541 return x >= this.cols
2542 ? this.cols - 1
2543 : x < 0 ? 0 : x;
2544};
2545
2546Terminal.prototype.eraseRight = function(x, y) {
2547 var line = this.lines[this.ybase + y]
2548 , ch = [this.eraseAttr(), ' ']; // xterm
2549
2550
2551 for (; x < this.cols; x++) {
2552 line[x] = ch;
2553 }
2554
2555 this.updateRange(y);
2556};
2557
2558Terminal.prototype.eraseLeft = function(x, y) {
2559 var line = this.lines[this.ybase + y]
2560 , ch = [this.eraseAttr(), ' ']; // xterm
2561
2562 x++;
2563 while (x--) line[x] = ch;
2564
2565 this.updateRange(y);
2566};
2567
2568Terminal.prototype.eraseLine = function(y) {
2569 this.eraseRight(0, y);
2570};
2571
2572Terminal.prototype.blankLine = function(cur) {
2573 var attr = cur
2574 ? this.eraseAttr()
2575 : this.defAttr;
2576
2577 var ch = [attr, ' ']
2578 , line = []
2579 , i = 0;
2580
2581 for (; i < this.cols; i++) {
2582 line[i] = ch;
2583 }
2584
2585 return line;
2586};
2587
2588Terminal.prototype.ch = function(cur) {
2589 return cur
2590 ? [this.eraseAttr(), ' ']
2591 : [this.defAttr, ' '];
2592};
2593
2594Terminal.prototype.is = function(term) {
2595 var name = this.termName || Terminal.termName;
2596 return (name + '').indexOf(term) === 0;
2597};
2598
2599Terminal.prototype.handler = function(data) {
2600 this.emit('data', data);
2601};
2602
2603Terminal.prototype.handleTitle = function(title) {
2604 this.emit('title', title);
2605};
2606
2607/**
2608 * ESC
2609 */
2610
2611// ESC D Index (IND is 0x84).
2612Terminal.prototype.index = function() {
2613 this.y++;
2614 if (this.y > this.scrollBottom) {
2615 this.y--;
2616 this.scroll();
2617 }
2618 this.state = normal;
2619};
2620
2621// ESC M Reverse Index (RI is 0x8d).
2622Terminal.prototype.reverseIndex = function() {
2623 var j;
2624 this.y--;
2625 if (this.y < this.scrollTop) {
2626 this.y++;
2627 // possibly move the code below to term.reverseScroll();
2628 // test: echo -ne '\e[1;1H\e[44m\eM\e[0m'
2629 // blankLine(true) is xterm/linux behavior
2630 this.lines.splice(this.y + this.ybase, 0, this.blankLine(true));
2631 j = this.rows - 1 - this.scrollBottom;
2632 this.lines.splice(this.rows - 1 + this.ybase - j + 1, 1);
2633 // this.maxRange();
2634 this.updateRange(this.scrollTop);
2635 this.updateRange(this.scrollBottom);
2636 }
2637 this.state = normal;
2638};
2639
2640// ESC c Full Reset (RIS).
2641Terminal.prototype.reset = function() {
2642 Terminal.call(this, this.cols, this.rows);
2643 this.refresh(0, this.rows - 1);
2644};
2645
2646// ESC H Tab Set (HTS is 0x88).
2647Terminal.prototype.tabSet = function() {
2648 this.tabs[this.x] = true;
2649 this.state = normal;
2650};
2651
2652/**
2653 * CSI
2654 */
2655
2656// CSI Ps A
2657// Cursor Up Ps Times (default = 1) (CUU).
2658Terminal.prototype.cursorUp = function(params) {
2659 var param = params[0];
2660 if (param < 1) param = 1;
2661 this.y -= param;
2662 if (this.y < 0) this.y = 0;
2663};
2664
2665// CSI Ps B
2666// Cursor Down Ps Times (default = 1) (CUD).
2667Terminal.prototype.cursorDown = function(params) {
2668 var param = params[0];
2669 if (param < 1) param = 1;
2670 this.y += param;
2671 if (this.y >= this.rows) {
2672 this.y = this.rows - 1;
2673 }
2674};
2675
2676// CSI Ps C
2677// Cursor Forward Ps Times (default = 1) (CUF).
2678Terminal.prototype.cursorForward = function(params) {
2679 var param = params[0];
2680 if (param < 1) param = 1;
2681 this.x += param;
2682 if (this.x >= this.cols) {
2683 this.x = this.cols - 1;
2684 }
2685};
2686
2687// CSI Ps D
2688// Cursor Backward Ps Times (default = 1) (CUB).
2689Terminal.prototype.cursorBackward = function(params) {
2690 var param = params[0];
2691 if (param < 1) param = 1;
2692 this.x -= param;
2693 if (this.x < 0) this.x = 0;
2694};
2695
2696// CSI Ps ; Ps H
2697// Cursor Position [row;column] (default = [1,1]) (CUP).
2698Terminal.prototype.cursorPos = function(params) {
2699 var row, col;
2700
2701 row = params[0] - 1;
2702
2703 if (params.length >= 2) {
2704 col = params[1] - 1;
2705 } else {
2706 col = 0;
2707 }
2708
2709 if (row < 0) {
2710 row = 0;
2711 } else if (row >= this.rows) {
2712 row = this.rows - 1;
2713 }
2714
2715 if (col < 0) {
2716 col = 0;
2717 } else if (col >= this.cols) {
2718 col = this.cols - 1;
2719 }
2720
2721 this.x = col;
2722 this.y = row;
2723};
2724
2725// CSI Ps J Erase in Display (ED).
2726// Ps = 0 -> Erase Below (default).
2727// Ps = 1 -> Erase Above.
2728// Ps = 2 -> Erase All.
2729// Ps = 3 -> Erase Saved Lines (xterm).
2730// CSI ? Ps J
2731// Erase in Display (DECSED).
2732// Ps = 0 -> Selective Erase Below (default).
2733// Ps = 1 -> Selective Erase Above.
2734// Ps = 2 -> Selective Erase All.
2735Terminal.prototype.eraseInDisplay = function(params) {
2736 var j;
2737 switch (params[0]) {
2738 case 0:
2739 this.eraseRight(this.x, this.y);
2740 j = this.y + 1;
2741 for (; j < this.rows; j++) {
2742 this.eraseLine(j);
2743 }
2744 break;
2745 case 1:
2746 this.eraseLeft(this.x, this.y);
2747 j = this.y;
2748 while (j--) {
2749 this.eraseLine(j);
2750 }
2751 break;
2752 case 2:
2753 j = this.rows;
2754 while (j--) this.eraseLine(j);
2755 break;
2756 case 3:
2757 ; // no saved lines
2758 break;
2759 }
2760};
2761
2762// CSI Ps K Erase in Line (EL).
2763// Ps = 0 -> Erase to Right (default).
2764// Ps = 1 -> Erase to Left.
2765// Ps = 2 -> Erase All.
2766// CSI ? Ps K
2767// Erase in Line (DECSEL).
2768// Ps = 0 -> Selective Erase to Right (default).
2769// Ps = 1 -> Selective Erase to Left.
2770// Ps = 2 -> Selective Erase All.
2771Terminal.prototype.eraseInLine = function(params) {
2772 switch (params[0]) {
2773 case 0:
2774 this.eraseRight(this.x, this.y);
2775 break;
2776 case 1:
2777 this.eraseLeft(this.x, this.y);
2778 break;
2779 case 2:
2780 this.eraseLine(this.y);
2781 break;
2782 }
2783};
2784
2785// CSI Pm m Character Attributes (SGR).
2786// Ps = 0 -> Normal (default).
2787// Ps = 1 -> Bold.
2788// Ps = 4 -> Underlined.
2789// Ps = 5 -> Blink (appears as Bold).
2790// Ps = 7 -> Inverse.
2791// Ps = 8 -> Invisible, i.e., hidden (VT300).
2792// Ps = 2 2 -> Normal (neither bold nor faint).
2793// Ps = 2 4 -> Not underlined.
2794// Ps = 2 5 -> Steady (not blinking).
2795// Ps = 2 7 -> Positive (not inverse).
2796// Ps = 2 8 -> Visible, i.e., not hidden (VT300).
2797// Ps = 3 0 -> Set foreground color to Black.
2798// Ps = 3 1 -> Set foreground color to Red.
2799// Ps = 3 2 -> Set foreground color to Green.
2800// Ps = 3 3 -> Set foreground color to Yellow.
2801// Ps = 3 4 -> Set foreground color to Blue.
2802// Ps = 3 5 -> Set foreground color to Magenta.
2803// Ps = 3 6 -> Set foreground color to Cyan.
2804// Ps = 3 7 -> Set foreground color to White.
2805// Ps = 3 9 -> Set foreground color to default (original).
2806// Ps = 4 0 -> Set background color to Black.
2807// Ps = 4 1 -> Set background color to Red.
2808// Ps = 4 2 -> Set background color to Green.
2809// Ps = 4 3 -> Set background color to Yellow.
2810// Ps = 4 4 -> Set background color to Blue.
2811// Ps = 4 5 -> Set background color to Magenta.
2812// Ps = 4 6 -> Set background color to Cyan.
2813// Ps = 4 7 -> Set background color to White.
2814// Ps = 4 9 -> Set background color to default (original).
2815
2816// If 16-color support is compiled, the following apply. Assume
2817// that xterm's resources are set so that the ISO color codes are
2818// the first 8 of a set of 16. Then the aixterm colors are the
2819// bright versions of the ISO colors:
2820// Ps = 9 0 -> Set foreground color to Black.
2821// Ps = 9 1 -> Set foreground color to Red.
2822// Ps = 9 2 -> Set foreground color to Green.
2823// Ps = 9 3 -> Set foreground color to Yellow.
2824// Ps = 9 4 -> Set foreground color to Blue.
2825// Ps = 9 5 -> Set foreground color to Magenta.
2826// Ps = 9 6 -> Set foreground color to Cyan.
2827// Ps = 9 7 -> Set foreground color to White.
2828// Ps = 1 0 0 -> Set background color to Black.
2829// Ps = 1 0 1 -> Set background color to Red.
2830// Ps = 1 0 2 -> Set background color to Green.
2831// Ps = 1 0 3 -> Set background color to Yellow.
2832// Ps = 1 0 4 -> Set background color to Blue.
2833// Ps = 1 0 5 -> Set background color to Magenta.
2834// Ps = 1 0 6 -> Set background color to Cyan.
2835// Ps = 1 0 7 -> Set background color to White.
2836
2837// If xterm is compiled with the 16-color support disabled, it
2838// supports the following, from rxvt:
2839// Ps = 1 0 0 -> Set foreground and background color to
2840// default.
2841
2842// If 88- or 256-color support is compiled, the following apply.
2843// Ps = 3 8 ; 5 ; Ps -> Set foreground color to the second
2844// Ps.
2845// Ps = 4 8 ; 5 ; Ps -> Set background color to the second
2846// Ps.
2847Terminal.prototype.charAttributes = function(params) {
2848 var l = params.length
2849 , i = 0
2850 , flags = this.curAttr >> 18
2851 , fg = (this.curAttr >> 9) & 0x1ff
2852 , bg = this.curAttr & 0x1ff
2853 , p;
2854
2855 for (; i < l; i++) {
2856 p = params[i];
2857 if (p >= 30 && p <= 37) {
2858 // fg color 8
2859 fg = p - 30;
2860 } else if (p >= 40 && p <= 47) {
2861 // bg color 8
2862 bg = p - 40;
2863 } else if (p >= 90 && p <= 97) {
2864 // fg color 16
2865 p += 8;
2866 fg = p - 90;
2867 } else if (p >= 100 && p <= 107) {
2868 // bg color 16
2869 p += 8;
2870 bg = p - 100;
2871 } else if (p === 0) {
2872 // default
2873 flags = this.defAttr >> 18;
2874 fg = (this.defAttr >> 9) & 0x1ff;
2875 bg = this.defAttr & 0x1ff;
2876 } else if (p === 1) {
2877 // bold text
2878 flags |= 1;
2879 } else if (p === 4) {
2880 // underlined text
2881 flags |= 2;
2882 } else if (p === 7 || p === 27) {
2883 // inverse and positive
2884 // test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m'
2885 if (p === 7) {
2886 if (flags & 4) continue;
2887 flags |= 4;
2888 } else if (p === 27) {
2889 if (~flags & 4) continue;
2890 flags &= ~4;
2891 }
2892 // JAVASCRIPT, Y U NO XOR SWAP?
2893 p = bg, bg = fg, fg = p;
2894 } else if (p === 22) {
2895 // not bold
2896 flags &= ~1;
2897 } else if (p === 24) {
2898 // not underlined
2899 flags &= ~2;
2900 } else if (p === 39) {
2901 // reset fg
2902 fg = (this.defAttr >> 9) & 0x1ff;
2903 } else if (p === 49) {
2904 // reset bg
2905 bg = this.defAttr & 0x1ff;
2906 } else if (p === 38) {
2907 // fg color 256
a68c8336
CJ
2908 if (params[i + 1] === 2) {
2909 i += 2;
2910 fg = matchColor(
2911 params[i] & 0xff,
2912 params[i + 1] & 0xff,
2913 params[i + 2] & 0xff);
2914 if (fg === -1) fg = 0x1ff;
2915 i += 2;
2916 } else if (params[i + 1] === 5) {
2917 i += 2;
2918 p = params[i] & 0xff;
2919 fg = p;
2920 }
8bc844c0
CJ
2921 } else if (p === 48) {
2922 // bg color 256
a68c8336
CJ
2923 if (params[i + 1] === 2) {
2924 i += 2;
2925 bg = matchColor(
2926 params[i] & 0xff,
2927 params[i + 1] & 0xff,
2928 params[i + 2] & 0xff);
2929 if (bg === -1) bg = 0x1ff;
2930 i += 2;
2931 } else if (params[i + 1] === 5) {
2932 i += 2;
2933 p = params[i] & 0xff;
2934 bg = p;
2935 }
8bc844c0
CJ
2936 }
2937 }
2938
2939 this.curAttr = (flags << 18) | (fg << 9) | bg;
2940};
2941
2942// CSI Ps n Device Status Report (DSR).
2943// Ps = 5 -> Status Report. Result (``OK'') is
2944// CSI 0 n
2945// Ps = 6 -> Report Cursor Position (CPR) [row;column].
2946// Result is
2947// CSI r ; c R
2948// CSI ? Ps n
2949// Device Status Report (DSR, DEC-specific).
2950// Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI
2951// ? r ; c R (assumes page is zero).
2952// Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready).
2953// or CSI ? 1 1 n (not ready).
2954// Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked)
2955// or CSI ? 2 1 n (locked).
2956// Ps = 2 6 -> Report Keyboard status as
2957// CSI ? 2 7 ; 1 ; 0 ; 0 n (North American).
2958// The last two parameters apply to VT400 & up, and denote key-
2959// board ready and LK01 respectively.
2960// Ps = 5 3 -> Report Locator status as
2961// CSI ? 5 3 n Locator available, if compiled-in, or
2962// CSI ? 5 0 n No Locator, if not.
2963Terminal.prototype.deviceStatus = function(params) {
2964 if (!this.prefix) {
2965 switch (params[0]) {
2966 case 5:
2967 // status report
2968 this.send('\x1b[0n');
2969 break;
2970 case 6:
2971 // cursor position
2972 this.send('\x1b['
2973 + (this.y + 1)
2974 + ';'
2975 + (this.x + 1)
2976 + 'R');
2977 break;
2978 }
2979 } else if (this.prefix === '?') {
2980 // modern xterm doesnt seem to
2981 // respond to any of these except ?6, 6, and 5
2982 switch (params[0]) {
2983 case 6:
2984 // cursor position
2985 this.send('\x1b[?'
2986 + (this.y + 1)
2987 + ';'
2988 + (this.x + 1)
2989 + 'R');
2990 break;
2991 case 15:
2992 // no printer
2993 // this.send('\x1b[?11n');
2994 break;
2995 case 25:
2996 // dont support user defined keys
2997 // this.send('\x1b[?21n');
2998 break;
2999 case 26:
3000 // north american keyboard
3001 // this.send('\x1b[?27;1;0;0n');
3002 break;
3003 case 53:
3004 // no dec locator/mouse
3005 // this.send('\x1b[?50n');
3006 break;
3007 }
3008 }
3009};
3010
3011/**
3012 * Additions
3013 */
3014
3015// CSI Ps @
3016// Insert Ps (Blank) Character(s) (default = 1) (ICH).
3017Terminal.prototype.insertChars = function(params) {
3018 var param, row, j, ch;
3019
3020 param = params[0];
3021 if (param < 1) param = 1;
3022
3023 row = this.y + this.ybase;
3024 j = this.x;
3025 ch = [this.eraseAttr(), ' ']; // xterm
3026
3027 while (param-- && j < this.cols) {
3028 this.lines[row].splice(j++, 0, ch);
3029 this.lines[row].pop();
3030 }
3031};
3032
3033// CSI Ps E
3034// Cursor Next Line Ps Times (default = 1) (CNL).
3035// same as CSI Ps B ?
3036Terminal.prototype.cursorNextLine = function(params) {
3037 var param = params[0];
3038 if (param < 1) param = 1;
3039 this.y += param;
3040 if (this.y >= this.rows) {
3041 this.y = this.rows - 1;
3042 }
3043 this.x = 0;
3044};
3045
3046// CSI Ps F
3047// Cursor Preceding Line Ps Times (default = 1) (CNL).
3048// reuse CSI Ps A ?
3049Terminal.prototype.cursorPrecedingLine = function(params) {
3050 var param = params[0];
3051 if (param < 1) param = 1;
3052 this.y -= param;
3053 if (this.y < 0) this.y = 0;
3054 this.x = 0;
3055};
3056
3057// CSI Ps G
3058// Cursor Character Absolute [column] (default = [row,1]) (CHA).
3059Terminal.prototype.cursorCharAbsolute = function(params) {
3060 var param = params[0];
3061 if (param < 1) param = 1;
3062 this.x = param - 1;
3063};
3064
3065// CSI Ps L
3066// Insert Ps Line(s) (default = 1) (IL).
3067Terminal.prototype.insertLines = function(params) {
3068 var param, row, j;
3069
3070 param = params[0];
3071 if (param < 1) param = 1;
3072 row = this.y + this.ybase;
3073
3074 j = this.rows - 1 - this.scrollBottom;
3075 j = this.rows - 1 + this.ybase - j + 1;
3076
3077 while (param--) {
3078 // test: echo -e '\e[44m\e[1L\e[0m'
3079 // blankLine(true) - xterm/linux behavior
3080 this.lines.splice(row, 0, this.blankLine(true));
3081 this.lines.splice(j, 1);
3082 }
3083
3084 // this.maxRange();
3085 this.updateRange(this.y);
3086 this.updateRange(this.scrollBottom);
3087};
3088
3089// CSI Ps M
3090// Delete Ps Line(s) (default = 1) (DL).
3091Terminal.prototype.deleteLines = function(params) {
3092 var param, row, j;
3093
3094 param = params[0];
3095 if (param < 1) param = 1;
3096 row = this.y + this.ybase;
3097
3098 j = this.rows - 1 - this.scrollBottom;
3099 j = this.rows - 1 + this.ybase - j;
3100
3101 while (param--) {
3102 // test: echo -e '\e[44m\e[1M\e[0m'
3103 // blankLine(true) - xterm/linux behavior
3104 this.lines.splice(j + 1, 0, this.blankLine(true));
3105 this.lines.splice(row, 1);
3106 }
3107
3108 // this.maxRange();
3109 this.updateRange(this.y);
3110 this.updateRange(this.scrollBottom);
3111};
3112
3113// CSI Ps P
3114// Delete Ps Character(s) (default = 1) (DCH).
3115Terminal.prototype.deleteChars = function(params) {
3116 var param, row, ch;
3117
3118 param = params[0];
3119 if (param < 1) param = 1;
3120
3121 row = this.y + this.ybase;
3122 ch = [this.eraseAttr(), ' ']; // xterm
3123
3124 while (param--) {
3125 this.lines[row].splice(this.x, 1);
3126 this.lines[row].push(ch);
3127 }
3128};
3129
3130// CSI Ps X
3131// Erase Ps Character(s) (default = 1) (ECH).
3132Terminal.prototype.eraseChars = function(params) {
3133 var param, row, j, ch;
3134
3135 param = params[0];
3136 if (param < 1) param = 1;
3137
3138 row = this.y + this.ybase;
3139 j = this.x;
3140 ch = [this.eraseAttr(), ' ']; // xterm
3141
3142 while (param-- && j < this.cols) {
3143 this.lines[row][j++] = ch;
3144 }
3145};
3146
3147// CSI Pm ` Character Position Absolute
3148// [column] (default = [row,1]) (HPA).
3149Terminal.prototype.charPosAbsolute = function(params) {
3150 var param = params[0];
3151 if (param < 1) param = 1;
3152 this.x = param - 1;
3153 if (this.x >= this.cols) {
3154 this.x = this.cols - 1;
3155 }
3156};
3157
3158// 141 61 a * HPR -
3159// Horizontal Position Relative
3160// reuse CSI Ps C ?
3161Terminal.prototype.HPositionRelative = function(params) {
3162 var param = params[0];
3163 if (param < 1) param = 1;
3164 this.x += param;
3165 if (this.x >= this.cols) {
3166 this.x = this.cols - 1;
3167 }
3168};
3169
3170// CSI Ps c Send Device Attributes (Primary DA).
3171// Ps = 0 or omitted -> request attributes from terminal. The
3172// response depends on the decTerminalID resource setting.
3173// -> CSI ? 1 ; 2 c (``VT100 with Advanced Video Option'')
3174// -> CSI ? 1 ; 0 c (``VT101 with No Options'')
3175// -> CSI ? 6 c (``VT102'')
3176// -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c (``VT220'')
3177// The VT100-style response parameters do not mean anything by
3178// themselves. VT220 parameters do, telling the host what fea-
3179// tures the terminal supports:
3180// Ps = 1 -> 132-columns.
3181// Ps = 2 -> Printer.
3182// Ps = 6 -> Selective erase.
3183// Ps = 8 -> User-defined keys.
3184// Ps = 9 -> National replacement character sets.
3185// Ps = 1 5 -> Technical characters.
3186// Ps = 2 2 -> ANSI color, e.g., VT525.
3187// Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode).
3188// CSI > Ps c
3189// Send Device Attributes (Secondary DA).
3190// Ps = 0 or omitted -> request the terminal's identification
3191// code. The response depends on the decTerminalID resource set-
3192// ting. It should apply only to VT220 and up, but xterm extends
3193// this to VT100.
3194// -> CSI > Pp ; Pv ; Pc c
3195// where Pp denotes the terminal type
3196// Pp = 0 -> ``VT100''.
3197// Pp = 1 -> ``VT220''.
3198// and Pv is the firmware version (for xterm, this was originally
3199// the XFree86 patch number, starting with 95). In a DEC termi-
3200// nal, Pc indicates the ROM cartridge registration number and is
3201// always zero.
3202// More information:
3203// xterm/charproc.c - line 2012, for more information.
3204// vim responds with ^[[?0c or ^[[?1c after the terminal's response (?)
3205Terminal.prototype.sendDeviceAttributes = function(params) {
3206 if (params[0] > 0) return;
3207
3208 if (!this.prefix) {
3209 if (this.is('xterm')
3210 || this.is('rxvt-unicode')
3211 || this.is('screen')) {
3212 this.send('\x1b[?1;2c');
3213 } else if (this.is('linux')) {
3214 this.send('\x1b[?6c');
3215 }
3216 } else if (this.prefix === '>') {
3217 // xterm and urxvt
3218 // seem to spit this
3219 // out around ~370 times (?).
3220 if (this.is('xterm')) {
3221 this.send('\x1b[>0;276;0c');
3222 } else if (this.is('rxvt-unicode')) {
3223 this.send('\x1b[>85;95;0c');
3224 } else if (this.is('linux')) {
3225 // not supported by linux console.
3226 // linux console echoes parameters.
3227 this.send(params[0] + 'c');
3228 } else if (this.is('screen')) {
3229 this.send('\x1b[>83;40003;0c');
3230 }
3231 }
3232};
3233
3234// CSI Pm d
3235// Line Position Absolute [row] (default = [1,column]) (VPA).
3236Terminal.prototype.linePosAbsolute = function(params) {
3237 var param = params[0];
3238 if (param < 1) param = 1;
3239 this.y = param - 1;
3240 if (this.y >= this.rows) {
3241 this.y = this.rows - 1;
3242 }
3243};
3244
3245// 145 65 e * VPR - Vertical Position Relative
3246// reuse CSI Ps B ?
3247Terminal.prototype.VPositionRelative = function(params) {
3248 var param = params[0];
3249 if (param < 1) param = 1;
3250 this.y += param;
3251 if (this.y >= this.rows) {
3252 this.y = this.rows - 1;
3253 }
3254};
3255
3256// CSI Ps ; Ps f
3257// Horizontal and Vertical Position [row;column] (default =
3258// [1,1]) (HVP).
3259Terminal.prototype.HVPosition = function(params) {
3260 if (params[0] < 1) params[0] = 1;
3261 if (params[1] < 1) params[1] = 1;
3262
3263 this.y = params[0] - 1;
3264 if (this.y >= this.rows) {
3265 this.y = this.rows - 1;
3266 }
3267
3268 this.x = params[1] - 1;
3269 if (this.x >= this.cols) {
3270 this.x = this.cols - 1;
3271 }
3272};
3273
3274// CSI Pm h Set Mode (SM).
3275// Ps = 2 -> Keyboard Action Mode (AM).
3276// Ps = 4 -> Insert Mode (IRM).
3277// Ps = 1 2 -> Send/receive (SRM).
3278// Ps = 2 0 -> Automatic Newline (LNM).
3279// CSI ? Pm h
3280// DEC Private Mode Set (DECSET).
3281// Ps = 1 -> Application Cursor Keys (DECCKM).
3282// Ps = 2 -> Designate USASCII for character sets G0-G3
3283// (DECANM), and set VT100 mode.
3284// Ps = 3 -> 132 Column Mode (DECCOLM).
3285// Ps = 4 -> Smooth (Slow) Scroll (DECSCLM).
3286// Ps = 5 -> Reverse Video (DECSCNM).
3287// Ps = 6 -> Origin Mode (DECOM).
3288// Ps = 7 -> Wraparound Mode (DECAWM).
3289// Ps = 8 -> Auto-repeat Keys (DECARM).
3290// Ps = 9 -> Send Mouse X & Y on button press. See the sec-
3291// tion Mouse Tracking.
3292// Ps = 1 0 -> Show toolbar (rxvt).
3293// Ps = 1 2 -> Start Blinking Cursor (att610).
3294// Ps = 1 8 -> Print form feed (DECPFF).
3295// Ps = 1 9 -> Set print extent to full screen (DECPEX).
3296// Ps = 2 5 -> Show Cursor (DECTCEM).
3297// Ps = 3 0 -> Show scrollbar (rxvt).
3298// Ps = 3 5 -> Enable font-shifting functions (rxvt).
3299// Ps = 3 8 -> Enter Tektronix Mode (DECTEK).
3300// Ps = 4 0 -> Allow 80 -> 132 Mode.
3301// Ps = 4 1 -> more(1) fix (see curses resource).
3302// Ps = 4 2 -> Enable Nation Replacement Character sets (DECN-
3303// RCM).
3304// Ps = 4 4 -> Turn On Margin Bell.
3305// Ps = 4 5 -> Reverse-wraparound Mode.
3306// Ps = 4 6 -> Start Logging. This is normally disabled by a
3307// compile-time option.
3308// Ps = 4 7 -> Use Alternate Screen Buffer. (This may be dis-
3309// abled by the titeInhibit resource).
3310// Ps = 6 6 -> Application keypad (DECNKM).
3311// Ps = 6 7 -> Backarrow key sends backspace (DECBKM).
3312// Ps = 1 0 0 0 -> Send Mouse X & Y on button press and
3313// release. See the section Mouse Tracking.
3314// Ps = 1 0 0 1 -> Use Hilite Mouse Tracking.
3315// Ps = 1 0 0 2 -> Use Cell Motion Mouse Tracking.
3316// Ps = 1 0 0 3 -> Use All Motion Mouse Tracking.
3317// Ps = 1 0 0 4 -> Send FocusIn/FocusOut events.
3318// Ps = 1 0 0 5 -> Enable Extended Mouse Mode.
3319// Ps = 1 0 1 0 -> Scroll to bottom on tty output (rxvt).
3320// Ps = 1 0 1 1 -> Scroll to bottom on key press (rxvt).
3321// Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit.
3322// (enables the eightBitInput resource).
3323// Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num-
3324// Lock keys. (This enables the numLock resource).
3325// Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This
3326// enables the metaSendsEscape resource).
3327// Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete
3328// key.
3329// Ps = 1 0 3 9 -> Send ESC when Alt modifies a key. (This
3330// enables the altSendsEscape resource).
3331// Ps = 1 0 4 0 -> Keep selection even if not highlighted.
3332// (This enables the keepSelection resource).
3333// Ps = 1 0 4 1 -> Use the CLIPBOARD selection. (This enables
3334// the selectToClipboard resource).
3335// Ps = 1 0 4 2 -> Enable Urgency window manager hint when
3336// Control-G is received. (This enables the bellIsUrgent
3337// resource).
3338// Ps = 1 0 4 3 -> Enable raising of the window when Control-G
3339// is received. (enables the popOnBell resource).
3340// Ps = 1 0 4 7 -> Use Alternate Screen Buffer. (This may be
3341// disabled by the titeInhibit resource).
3342// Ps = 1 0 4 8 -> Save cursor as in DECSC. (This may be dis-
3343// abled by the titeInhibit resource).
3344// Ps = 1 0 4 9 -> Save cursor as in DECSC and use Alternate
3345// Screen Buffer, clearing it first. (This may be disabled by
3346// the titeInhibit resource). This combines the effects of the 1
3347// 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based
3348// applications rather than the 4 7 mode.
3349// Ps = 1 0 5 0 -> Set terminfo/termcap function-key mode.
3350// Ps = 1 0 5 1 -> Set Sun function-key mode.
3351// Ps = 1 0 5 2 -> Set HP function-key mode.
3352// Ps = 1 0 5 3 -> Set SCO function-key mode.
3353// Ps = 1 0 6 0 -> Set legacy keyboard emulation (X11R6).
3354// Ps = 1 0 6 1 -> Set VT220 keyboard emulation.
3355// Ps = 2 0 0 4 -> Set bracketed paste mode.
3356// Modes:
3357// http://vt100.net/docs/vt220-rm/chapter4.html
3358Terminal.prototype.setMode = function(params) {
3359 if (typeof params === 'object') {
3360 var l = params.length
3361 , i = 0;
3362
3363 for (; i < l; i++) {
3364 this.setMode(params[i]);
3365 }
3366
3367 return;
3368 }
3369
3370 if (!this.prefix) {
3371 switch (params) {
3372 case 4:
3373 this.insertMode = true;
3374 break;
3375 case 20:
3376 //this.convertEol = true;
3377 break;
3378 }
3379 } else if (this.prefix === '?') {
3380 switch (params) {
3381 case 1:
3382 this.applicationCursor = true;
3383 break;
3384 case 2:
3385 this.setgCharset(0, Terminal.charsets.US);
3386 this.setgCharset(1, Terminal.charsets.US);
3387 this.setgCharset(2, Terminal.charsets.US);
3388 this.setgCharset(3, Terminal.charsets.US);
3389 // set VT100 mode here
3390 break;
3391 case 3: // 132 col mode
3392 this.savedCols = this.cols;
3393 this.resize(132, this.rows);
3394 break;
3395 case 6:
3396 this.originMode = true;
3397 break;
3398 case 7:
3399 this.wraparoundMode = true;
3400 break;
3401 case 12:
3402 // this.cursorBlink = true;
3403 break;
3404 case 66:
3405 this.log('Serial port requested application keypad.');
3406 this.applicationKeypad = true;
3407 break;
3408 case 9: // X10 Mouse
3409 // no release, no motion, no wheel, no modifiers.
3410 case 1000: // vt200 mouse
3411 // no motion.
3412 // no modifiers, except control on the wheel.
3413 case 1002: // button event mouse
3414 case 1003: // any event mouse
3415 // any event - sends motion events,
3416 // even if there is no button held down.
3417 this.x10Mouse = params === 9;
3418 this.vt200Mouse = params === 1000;
3419 this.normalMouse = params > 1000;
3420 this.mouseEvents = true;
3421 this.element.style.cursor = 'default';
3422 this.log('Binding to mouse events.');
3423 break;
3424 case 1004: // send focusin/focusout events
3425 // focusin: ^[[I
3426 // focusout: ^[[O
3427 this.sendFocus = true;
3428 break;
3429 case 1005: // utf8 ext mode mouse
3430 this.utfMouse = true;
3431 // for wide terminals
3432 // simply encodes large values as utf8 characters
3433 break;
3434 case 1006: // sgr ext mode mouse
3435 this.sgrMouse = true;
3436 // for wide terminals
3437 // does not add 32 to fields
3438 // press: ^[[<b;x;yM
3439 // release: ^[[<b;x;ym
3440 break;
3441 case 1015: // urxvt ext mode mouse
3442 this.urxvtMouse = true;
3443 // for wide terminals
3444 // numbers for fields
3445 // press: ^[[b;x;yM
3446 // motion: ^[[b;x;yT
3447 break;
3448 case 25: // show cursor
3449 this.cursorHidden = false;
3450 break;
3451 case 1049: // alt screen buffer cursor
3452 //this.saveCursor();
3453 ; // FALL-THROUGH
3454 case 47: // alt screen buffer
3455 case 1047: // alt screen buffer
3456 if (!this.normal) {
3457 var normal = {
3458 lines: this.lines,
3459 ybase: this.ybase,
3460 ydisp: this.ydisp,
3461 x: this.x,
3462 y: this.y,
3463 scrollTop: this.scrollTop,
3464 scrollBottom: this.scrollBottom,
3465 tabs: this.tabs
3466 // XXX save charset(s) here?
3467 // charset: this.charset,
3468 // glevel: this.glevel,
3469 // charsets: this.charsets
3470 };
3471 this.reset();
3472 this.normal = normal;
3473 this.showCursor();
3474 }
3475 break;
3476 }
3477 }
3478};
3479
3480// CSI Pm l Reset Mode (RM).
3481// Ps = 2 -> Keyboard Action Mode (AM).
3482// Ps = 4 -> Replace Mode (IRM).
3483// Ps = 1 2 -> Send/receive (SRM).
3484// Ps = 2 0 -> Normal Linefeed (LNM).
3485// CSI ? Pm l
3486// DEC Private Mode Reset (DECRST).
3487// Ps = 1 -> Normal Cursor Keys (DECCKM).
3488// Ps = 2 -> Designate VT52 mode (DECANM).
3489// Ps = 3 -> 80 Column Mode (DECCOLM).
3490// Ps = 4 -> Jump (Fast) Scroll (DECSCLM).
3491// Ps = 5 -> Normal Video (DECSCNM).
3492// Ps = 6 -> Normal Cursor Mode (DECOM).
3493// Ps = 7 -> No Wraparound Mode (DECAWM).
3494// Ps = 8 -> No Auto-repeat Keys (DECARM).
3495// Ps = 9 -> Don't send Mouse X & Y on button press.
3496// Ps = 1 0 -> Hide toolbar (rxvt).
3497// Ps = 1 2 -> Stop Blinking Cursor (att610).
3498// Ps = 1 8 -> Don't print form feed (DECPFF).
3499// Ps = 1 9 -> Limit print to scrolling region (DECPEX).
3500// Ps = 2 5 -> Hide Cursor (DECTCEM).
3501// Ps = 3 0 -> Don't show scrollbar (rxvt).
3502// Ps = 3 5 -> Disable font-shifting functions (rxvt).
3503// Ps = 4 0 -> Disallow 80 -> 132 Mode.
3504// Ps = 4 1 -> No more(1) fix (see curses resource).
3505// Ps = 4 2 -> Disable Nation Replacement Character sets (DEC-
3506// NRCM).
3507// Ps = 4 4 -> Turn Off Margin Bell.
3508// Ps = 4 5 -> No Reverse-wraparound Mode.
3509// Ps = 4 6 -> Stop Logging. (This is normally disabled by a
3510// compile-time option).
3511// Ps = 4 7 -> Use Normal Screen Buffer.
3512// Ps = 6 6 -> Numeric keypad (DECNKM).
3513// Ps = 6 7 -> Backarrow key sends delete (DECBKM).
3514// Ps = 1 0 0 0 -> Don't send Mouse X & Y on button press and
3515// release. See the section Mouse Tracking.
3516// Ps = 1 0 0 1 -> Don't use Hilite Mouse Tracking.
3517// Ps = 1 0 0 2 -> Don't use Cell Motion Mouse Tracking.
3518// Ps = 1 0 0 3 -> Don't use All Motion Mouse Tracking.
3519// Ps = 1 0 0 4 -> Don't send FocusIn/FocusOut events.
3520// Ps = 1 0 0 5 -> Disable Extended Mouse Mode.
3521// Ps = 1 0 1 0 -> Don't scroll to bottom on tty output
3522// (rxvt).
3523// Ps = 1 0 1 1 -> Don't scroll to bottom on key press (rxvt).
3524// Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables
3525// the eightBitInput resource).
3526// Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num-
3527// Lock keys. (This disables the numLock resource).
3528// Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key.
3529// (This disables the metaSendsEscape resource).
3530// Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad
3531// Delete key.
3532// Ps = 1 0 3 9 -> Don't send ESC when Alt modifies a key.
3533// (This disables the altSendsEscape resource).
3534// Ps = 1 0 4 0 -> Do not keep selection when not highlighted.
3535// (This disables the keepSelection resource).
3536// Ps = 1 0 4 1 -> Use the PRIMARY selection. (This disables
3537// the selectToClipboard resource).
3538// Ps = 1 0 4 2 -> Disable Urgency window manager hint when
3539// Control-G is received. (This disables the bellIsUrgent
3540// resource).
3541// Ps = 1 0 4 3 -> Disable raising of the window when Control-
3542// G is received. (This disables the popOnBell resource).
3543// Ps = 1 0 4 7 -> Use Normal Screen Buffer, clearing screen
3544// first if in the Alternate Screen. (This may be disabled by
3545// the titeInhibit resource).
3546// Ps = 1 0 4 8 -> Restore cursor as in DECRC. (This may be
3547// disabled by the titeInhibit resource).
3548// Ps = 1 0 4 9 -> Use Normal Screen Buffer and restore cursor
3549// as in DECRC. (This may be disabled by the titeInhibit
3550// resource). This combines the effects of the 1 0 4 7 and 1 0
3551// 4 8 modes. Use this with terminfo-based applications rather
3552// than the 4 7 mode.
3553// Ps = 1 0 5 0 -> Reset terminfo/termcap function-key mode.
3554// Ps = 1 0 5 1 -> Reset Sun function-key mode.
3555// Ps = 1 0 5 2 -> Reset HP function-key mode.
3556// Ps = 1 0 5 3 -> Reset SCO function-key mode.
3557// Ps = 1 0 6 0 -> Reset legacy keyboard emulation (X11R6).
3558// Ps = 1 0 6 1 -> Reset keyboard emulation to Sun/PC style.
3559// Ps = 2 0 0 4 -> Reset bracketed paste mode.
3560Terminal.prototype.resetMode = function(params) {
3561 if (typeof params === 'object') {
3562 var l = params.length
3563 , i = 0;
3564
3565 for (; i < l; i++) {
3566 this.resetMode(params[i]);
3567 }
3568
3569 return;
3570 }
3571
3572 if (!this.prefix) {
3573 switch (params) {
3574 case 4:
3575 this.insertMode = false;
3576 break;
3577 case 20:
3578 //this.convertEol = false;
3579 break;
3580 }
3581 } else if (this.prefix === '?') {
3582 switch (params) {
3583 case 1:
3584 this.applicationCursor = false;
3585 break;
3586 case 3:
3587 if (this.cols === 132 && this.savedCols) {
3588 this.resize(this.savedCols, this.rows);
3589 }
3590 delete this.savedCols;
3591 break;
3592 case 6:
3593 this.originMode = false;
3594 break;
3595 case 7:
3596 this.wraparoundMode = false;
3597 break;
3598 case 12:
3599 // this.cursorBlink = false;
3600 break;
3601 case 66:
3602 this.log('Switching back to normal keypad.');
3603 this.applicationKeypad = false;
3604 break;
3605 case 9: // X10 Mouse
3606 case 1000: // vt200 mouse
3607 case 1002: // button event mouse
3608 case 1003: // any event mouse
3609 this.x10Mouse = false;
3610 this.vt200Mouse = false;
3611 this.normalMouse = false;
3612 this.mouseEvents = false;
3613 this.element.style.cursor = '';
3614 break;
3615 case 1004: // send focusin/focusout events
3616 this.sendFocus = false;
3617 break;
3618 case 1005: // utf8 ext mode mouse
3619 this.utfMouse = false;
3620 break;
3621 case 1006: // sgr ext mode mouse
3622 this.sgrMouse = false;
3623 break;
3624 case 1015: // urxvt ext mode mouse
3625 this.urxvtMouse = false;
3626 break;
3627 case 25: // hide cursor
3628 this.cursorHidden = true;
3629 break;
3630 case 1049: // alt screen buffer cursor
3631 ; // FALL-THROUGH
3632 case 47: // normal screen buffer
3633 case 1047: // normal screen buffer - clearing it first
3634 if (this.normal) {
3635 this.lines = this.normal.lines;
3636 this.ybase = this.normal.ybase;
3637 this.ydisp = this.normal.ydisp;
3638 this.x = this.normal.x;
3639 this.y = this.normal.y;
3640 this.scrollTop = this.normal.scrollTop;
3641 this.scrollBottom = this.normal.scrollBottom;
3642 this.tabs = this.normal.tabs;
3643 this.normal = null;
3644 // if (params === 1049) {
3645 // this.x = this.savedX;
3646 // this.y = this.savedY;
3647 // }
3648 this.refresh(0, this.rows - 1);
3649 this.showCursor();
3650 }
3651 break;
3652 }
3653 }
3654};
3655
3656// CSI Ps ; Ps r
3657// Set Scrolling Region [top;bottom] (default = full size of win-
3658// dow) (DECSTBM).
3659// CSI ? Pm r
3660Terminal.prototype.setScrollRegion = function(params) {
3661 if (this.prefix) return;
3662 this.scrollTop = (params[0] || 1) - 1;
3663 this.scrollBottom = (params[1] || this.rows) - 1;
3664 this.x = 0;
3665 this.y = 0;
3666};
3667
3668// CSI s
3669// Save cursor (ANSI.SYS).
3670Terminal.prototype.saveCursor = function(params) {
3671 this.savedX = this.x;
3672 this.savedY = this.y;
3673};
3674
3675// CSI u
3676// Restore cursor (ANSI.SYS).
3677Terminal.prototype.restoreCursor = function(params) {
3678 this.x = this.savedX || 0;
3679 this.y = this.savedY || 0;
3680};
3681
3682/**
3683 * Lesser Used
3684 */
3685
3686// CSI Ps I
3687// Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
3688Terminal.prototype.cursorForwardTab = function(params) {
3689 var param = params[0] || 1;
3690 while (param--) {
3691 this.x = this.nextStop();
3692 }
3693};
3694
3695// CSI Ps S Scroll up Ps lines (default = 1) (SU).
3696Terminal.prototype.scrollUp = function(params) {
3697 var param = params[0] || 1;
3698 while (param--) {
3699 this.lines.splice(this.ybase + this.scrollTop, 1);
3700 this.lines.splice(this.ybase + this.scrollBottom, 0, this.blankLine());
3701 }
3702 // this.maxRange();
3703 this.updateRange(this.scrollTop);
3704 this.updateRange(this.scrollBottom);
3705};
3706
3707// CSI Ps T Scroll down Ps lines (default = 1) (SD).
3708Terminal.prototype.scrollDown = function(params) {
3709 var param = params[0] || 1;
3710 while (param--) {
3711 this.lines.splice(this.ybase + this.scrollBottom, 1);
3712 this.lines.splice(this.ybase + this.scrollTop, 0, this.blankLine());
3713 }
3714 // this.maxRange();
3715 this.updateRange(this.scrollTop);
3716 this.updateRange(this.scrollBottom);
3717};
3718
3719// CSI Ps ; Ps ; Ps ; Ps ; Ps T
3720// Initiate highlight mouse tracking. Parameters are
3721// [func;startx;starty;firstrow;lastrow]. See the section Mouse
3722// Tracking.
3723Terminal.prototype.initMouseTracking = function(params) {
3724 // Relevant: DECSET 1001
3725};
3726
3727// CSI > Ps; Ps T
3728// Reset one or more features of the title modes to the default
3729// value. Normally, "reset" disables the feature. It is possi-
3730// ble to disable the ability to reset features by compiling a
3731// different default for the title modes into xterm.
3732// Ps = 0 -> Do not set window/icon labels using hexadecimal.
3733// Ps = 1 -> Do not query window/icon labels using hexadeci-
3734// mal.
3735// Ps = 2 -> Do not set window/icon labels using UTF-8.
3736// Ps = 3 -> Do not query window/icon labels using UTF-8.
3737// (See discussion of "Title Modes").
3738Terminal.prototype.resetTitleModes = function(params) {
3739 ;
3740};
3741
3742// CSI Ps Z Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
3743Terminal.prototype.cursorBackwardTab = function(params) {
3744 var param = params[0] || 1;
3745 while (param--) {
3746 this.x = this.prevStop();
3747 }
3748};
3749
3750// CSI Ps b Repeat the preceding graphic character Ps times (REP).
3751Terminal.prototype.repeatPrecedingCharacter = function(params) {
3752 var param = params[0] || 1
3753 , line = this.lines[this.ybase + this.y]
3754 , ch = line[this.x - 1] || [this.defAttr, ' '];
3755
3756 while (param--) line[this.x++] = ch;
3757};
3758
3759// CSI Ps g Tab Clear (TBC).
3760// Ps = 0 -> Clear Current Column (default).
3761// Ps = 3 -> Clear All.
3762// Potentially:
3763// Ps = 2 -> Clear Stops on Line.
3764// http://vt100.net/annarbor/aaa-ug/section6.html
3765Terminal.prototype.tabClear = function(params) {
3766 var param = params[0];
3767 if (param <= 0) {
3768 delete this.tabs[this.x];
3769 } else if (param === 3) {
3770 this.tabs = {};
3771 }
3772};
3773
3774// CSI Pm i Media Copy (MC).
3775// Ps = 0 -> Print screen (default).
3776// Ps = 4 -> Turn off printer controller mode.
3777// Ps = 5 -> Turn on printer controller mode.
3778// CSI ? Pm i
3779// Media Copy (MC, DEC-specific).
3780// Ps = 1 -> Print line containing cursor.
3781// Ps = 4 -> Turn off autoprint mode.
3782// Ps = 5 -> Turn on autoprint mode.
3783// Ps = 1 0 -> Print composed display, ignores DECPEX.
3784// Ps = 1 1 -> Print all pages.
3785Terminal.prototype.mediaCopy = function(params) {
3786 ;
3787};
3788
3789// CSI > Ps; Ps m
3790// Set or reset resource-values used by xterm to decide whether
3791// to construct escape sequences holding information about the
3792// modifiers pressed with a given key. The first parameter iden-
3793// tifies the resource to set/reset. The second parameter is the
3794// value to assign to the resource. If the second parameter is
3795// omitted, the resource is reset to its initial value.
3796// Ps = 1 -> modifyCursorKeys.
3797// Ps = 2 -> modifyFunctionKeys.
3798// Ps = 4 -> modifyOtherKeys.
3799// If no parameters are given, all resources are reset to their
3800// initial values.
3801Terminal.prototype.setResources = function(params) {
3802 ;
3803};
3804
3805// CSI > Ps n
3806// Disable modifiers which may be enabled via the CSI > Ps; Ps m
3807// sequence. This corresponds to a resource value of "-1", which
3808// cannot be set with the other sequence. The parameter identi-
3809// fies the resource to be disabled:
3810// Ps = 1 -> modifyCursorKeys.
3811// Ps = 2 -> modifyFunctionKeys.
3812// Ps = 4 -> modifyOtherKeys.
3813// If the parameter is omitted, modifyFunctionKeys is disabled.
3814// When modifyFunctionKeys is disabled, xterm uses the modifier
3815// keys to make an extended sequence of functions rather than
3816// adding a parameter to each function key to denote the modi-
3817// fiers.
3818Terminal.prototype.disableModifiers = function(params) {
3819 ;
3820};
3821
3822// CSI > Ps p
3823// Set resource value pointerMode. This is used by xterm to
3824// decide whether to hide the pointer cursor as the user types.
3825// Valid values for the parameter:
3826// Ps = 0 -> never hide the pointer.
3827// Ps = 1 -> hide if the mouse tracking mode is not enabled.
3828// Ps = 2 -> always hide the pointer. If no parameter is
3829// given, xterm uses the default, which is 1 .
3830Terminal.prototype.setPointerMode = function(params) {
3831 ;
3832};
3833
3834// CSI ! p Soft terminal reset (DECSTR).
3835// http://vt100.net/docs/vt220-rm/table4-10.html
3836Terminal.prototype.softReset = function(params) {
3837 this.cursorHidden = false;
3838 this.insertMode = false;
3839 this.originMode = false;
3840 this.wraparoundMode = false; // autowrap
3841 this.applicationKeypad = false; // ?
3842 this.applicationCursor = false;
3843 this.scrollTop = 0;
3844 this.scrollBottom = this.rows - 1;
3845 this.curAttr = this.defAttr;
3846 this.x = this.y = 0; // ?
3847 this.charset = null;
3848 this.glevel = 0; // ??
3849 this.charsets = [null]; // ??
3850};
3851
3852// CSI Ps$ p
3853// Request ANSI mode (DECRQM). For VT300 and up, reply is
3854// CSI Ps; Pm$ y
3855// where Ps is the mode number as in RM, and Pm is the mode
3856// value:
3857// 0 - not recognized
3858// 1 - set
3859// 2 - reset
3860// 3 - permanently set
3861// 4 - permanently reset
3862Terminal.prototype.requestAnsiMode = function(params) {
3863 ;
3864};
3865
3866// CSI ? Ps$ p
3867// Request DEC private mode (DECRQM). For VT300 and up, reply is
3868// CSI ? Ps; Pm$ p
3869// where Ps is the mode number as in DECSET, Pm is the mode value
3870// as in the ANSI DECRQM.
3871Terminal.prototype.requestPrivateMode = function(params) {
3872 ;
3873};
3874
3875// CSI Ps ; Ps " p
3876// Set conformance level (DECSCL). Valid values for the first
3877// parameter:
3878// Ps = 6 1 -> VT100.
3879// Ps = 6 2 -> VT200.
3880// Ps = 6 3 -> VT300.
3881// Valid values for the second parameter:
3882// Ps = 0 -> 8-bit controls.
3883// Ps = 1 -> 7-bit controls (always set for VT100).
3884// Ps = 2 -> 8-bit controls.
3885Terminal.prototype.setConformanceLevel = function(params) {
3886 ;
3887};
3888
3889// CSI Ps q Load LEDs (DECLL).
3890// Ps = 0 -> Clear all LEDS (default).
3891// Ps = 1 -> Light Num Lock.
3892// Ps = 2 -> Light Caps Lock.
3893// Ps = 3 -> Light Scroll Lock.
3894// Ps = 2 1 -> Extinguish Num Lock.
3895// Ps = 2 2 -> Extinguish Caps Lock.
3896// Ps = 2 3 -> Extinguish Scroll Lock.
3897Terminal.prototype.loadLEDs = function(params) {
3898 ;
3899};
3900
3901// CSI Ps SP q
3902// Set cursor style (DECSCUSR, VT520).
3903// Ps = 0 -> blinking block.
3904// Ps = 1 -> blinking block (default).
3905// Ps = 2 -> steady block.
3906// Ps = 3 -> blinking underline.
3907// Ps = 4 -> steady underline.
3908Terminal.prototype.setCursorStyle = function(params) {
3909 ;
3910};
3911
3912// CSI Ps " q
3913// Select character protection attribute (DECSCA). Valid values
3914// for the parameter:
3915// Ps = 0 -> DECSED and DECSEL can erase (default).
3916// Ps = 1 -> DECSED and DECSEL cannot erase.
3917// Ps = 2 -> DECSED and DECSEL can erase.
3918Terminal.prototype.setCharProtectionAttr = function(params) {
3919 ;
3920};
3921
3922// CSI ? Pm r
3923// Restore DEC Private Mode Values. The value of Ps previously
3924// saved is restored. Ps values are the same as for DECSET.
3925Terminal.prototype.restorePrivateValues = function(params) {
3926 ;
3927};
3928
3929// CSI Pt; Pl; Pb; Pr; Ps$ r
3930// Change Attributes in Rectangular Area (DECCARA), VT400 and up.
3931// Pt; Pl; Pb; Pr denotes the rectangle.
3932// Ps denotes the SGR attributes to change: 0, 1, 4, 5, 7.
3933// NOTE: xterm doesn't enable this code by default.
3934Terminal.prototype.setAttrInRectangle = function(params) {
3935 var t = params[0]
3936 , l = params[1]
3937 , b = params[2]
3938 , r = params[3]
3939 , attr = params[4];
3940
3941 var line
3942 , i;
3943
3944 for (; t < b + 1; t++) {
3945 line = this.lines[this.ybase + t];
3946 for (i = l; i < r; i++) {
3947 line[i] = [attr, line[i][1]];
3948 }
3949 }
3950
3951 // this.maxRange();
3952 this.updateRange(params[0]);
3953 this.updateRange(params[2]);
3954};
3955
3956// CSI ? Pm s
3957// Save DEC Private Mode Values. Ps values are the same as for
3958// DECSET.
3959Terminal.prototype.savePrivateValues = function(params) {
3960 ;
3961};
3962
3963// CSI Ps ; Ps ; Ps t
3964// Window manipulation (from dtterm, as well as extensions).
3965// These controls may be disabled using the allowWindowOps
3966// resource. Valid values for the first (and any additional
3967// parameters) are:
3968// Ps = 1 -> De-iconify window.
3969// Ps = 2 -> Iconify window.
3970// Ps = 3 ; x ; y -> Move window to [x, y].
3971// Ps = 4 ; height ; width -> Resize the xterm window to
3972// height and width in pixels.
3973// Ps = 5 -> Raise the xterm window to the front of the stack-
3974// ing order.
3975// Ps = 6 -> Lower the xterm window to the bottom of the
3976// stacking order.
3977// Ps = 7 -> Refresh the xterm window.
3978// Ps = 8 ; height ; width -> Resize the text area to
3979// [height;width] in characters.
3980// Ps = 9 ; 0 -> Restore maximized window.
3981// Ps = 9 ; 1 -> Maximize window (i.e., resize to screen
3982// size).
3983// Ps = 1 0 ; 0 -> Undo full-screen mode.
3984// Ps = 1 0 ; 1 -> Change to full-screen.
3985// Ps = 1 1 -> Report xterm window state. If the xterm window
3986// is open (non-iconified), it returns CSI 1 t . If the xterm
3987// window is iconified, it returns CSI 2 t .
3988// Ps = 1 3 -> Report xterm window position. Result is CSI 3
3989// ; x ; y t
3990// Ps = 1 4 -> Report xterm window in pixels. Result is CSI
3991// 4 ; height ; width t
3992// Ps = 1 8 -> Report the size of the text area in characters.
3993// Result is CSI 8 ; height ; width t
3994// Ps = 1 9 -> Report the size of the screen in characters.
3995// Result is CSI 9 ; height ; width t
3996// Ps = 2 0 -> Report xterm window's icon label. Result is
3997// OSC L label ST
3998// Ps = 2 1 -> Report xterm window's title. Result is OSC l
3999// label ST
4000// Ps = 2 2 ; 0 -> Save xterm icon and window title on
4001// stack.
4002// Ps = 2 2 ; 1 -> Save xterm icon title on stack.
4003// Ps = 2 2 ; 2 -> Save xterm window title on stack.
4004// Ps = 2 3 ; 0 -> Restore xterm icon and window title from
4005// stack.
4006// Ps = 2 3 ; 1 -> Restore xterm icon title from stack.
4007// Ps = 2 3 ; 2 -> Restore xterm window title from stack.
4008// Ps >= 2 4 -> Resize to Ps lines (DECSLPP).
4009Terminal.prototype.manipulateWindow = function(params) {
4010 ;
4011};
4012
4013// CSI Pt; Pl; Pb; Pr; Ps$ t
4014// Reverse Attributes in Rectangular Area (DECRARA), VT400 and
4015// up.
4016// Pt; Pl; Pb; Pr denotes the rectangle.
4017// Ps denotes the attributes to reverse, i.e., 1, 4, 5, 7.
4018// NOTE: xterm doesn't enable this code by default.
4019Terminal.prototype.reverseAttrInRectangle = function(params) {
4020 ;
4021};
4022
4023// CSI > Ps; Ps t
4024// Set one or more features of the title modes. Each parameter
4025// enables a single feature.
4026// Ps = 0 -> Set window/icon labels using hexadecimal.
4027// Ps = 1 -> Query window/icon labels using hexadecimal.
4028// Ps = 2 -> Set window/icon labels using UTF-8.
4029// Ps = 3 -> Query window/icon labels using UTF-8. (See dis-
4030// cussion of "Title Modes")
4031Terminal.prototype.setTitleModeFeature = function(params) {
4032 ;
4033};
4034
4035// CSI Ps SP t
4036// Set warning-bell volume (DECSWBV, VT520).
4037// Ps = 0 or 1 -> off.
4038// Ps = 2 , 3 or 4 -> low.
4039// Ps = 5 , 6 , 7 , or 8 -> high.
4040Terminal.prototype.setWarningBellVolume = function(params) {
4041 ;
4042};
4043
4044// CSI Ps SP u
4045// Set margin-bell volume (DECSMBV, VT520).
4046// Ps = 1 -> off.
4047// Ps = 2 , 3 or 4 -> low.
4048// Ps = 0 , 5 , 6 , 7 , or 8 -> high.
4049Terminal.prototype.setMarginBellVolume = function(params) {
4050 ;
4051};
4052
4053// CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v
4054// Copy Rectangular Area (DECCRA, VT400 and up).
4055// Pt; Pl; Pb; Pr denotes the rectangle.
4056// Pp denotes the source page.
4057// Pt; Pl denotes the target location.
4058// Pp denotes the target page.
4059// NOTE: xterm doesn't enable this code by default.
4060Terminal.prototype.copyRectangle = function(params) {
4061 ;
4062};
4063
4064// CSI Pt ; Pl ; Pb ; Pr ' w
4065// Enable Filter Rectangle (DECEFR), VT420 and up.
4066// Parameters are [top;left;bottom;right].
4067// Defines the coordinates of a filter rectangle and activates
4068// it. Anytime the locator is detected outside of the filter
4069// rectangle, an outside rectangle event is generated and the
4070// rectangle is disabled. Filter rectangles are always treated
4071// as "one-shot" events. Any parameters that are omitted default
4072// to the current locator position. If all parameters are omit-
4073// ted, any locator motion will be reported. DECELR always can-
4074// cels any prevous rectangle definition.
4075Terminal.prototype.enableFilterRectangle = function(params) {
4076 ;
4077};
4078
4079// CSI Ps x Request Terminal Parameters (DECREQTPARM).
4080// if Ps is a "0" (default) or "1", and xterm is emulating VT100,
4081// the control sequence elicits a response of the same form whose
4082// parameters describe the terminal:
4083// Ps -> the given Ps incremented by 2.
4084// Pn = 1 <- no parity.
4085// Pn = 1 <- eight bits.
4086// Pn = 1 <- 2 8 transmit 38.4k baud.
4087// Pn = 1 <- 2 8 receive 38.4k baud.
4088// Pn = 1 <- clock multiplier.
4089// Pn = 0 <- STP flags.
4090Terminal.prototype.requestParameters = function(params) {
4091 ;
4092};
4093
4094// CSI Ps x Select Attribute Change Extent (DECSACE).
4095// Ps = 0 -> from start to end position, wrapped.
4096// Ps = 1 -> from start to end position, wrapped.
4097// Ps = 2 -> rectangle (exact).
4098Terminal.prototype.selectChangeExtent = function(params) {
4099 ;
4100};
4101
4102// CSI Pc; Pt; Pl; Pb; Pr$ x
4103// Fill Rectangular Area (DECFRA), VT420 and up.
4104// Pc is the character to use.
4105// Pt; Pl; Pb; Pr denotes the rectangle.
4106// NOTE: xterm doesn't enable this code by default.
4107Terminal.prototype.fillRectangle = function(params) {
4108 var ch = params[0]
4109 , t = params[1]
4110 , l = params[2]
4111 , b = params[3]
4112 , r = params[4];
4113
4114 var line
4115 , i;
4116
4117 for (; t < b + 1; t++) {
4118 line = this.lines[this.ybase + t];
4119 for (i = l; i < r; i++) {
4120 line[i] = [line[i][0], String.fromCharCode(ch)];
4121 }
4122 }
4123
4124 // this.maxRange();
4125 this.updateRange(params[1]);
4126 this.updateRange(params[3]);
4127};
4128
4129// CSI Ps ; Pu ' z
4130// Enable Locator Reporting (DECELR).
4131// Valid values for the first parameter:
4132// Ps = 0 -> Locator disabled (default).
4133// Ps = 1 -> Locator enabled.
4134// Ps = 2 -> Locator enabled for one report, then disabled.
4135// The second parameter specifies the coordinate unit for locator
4136// reports.
4137// Valid values for the second parameter:
4138// Pu = 0 <- or omitted -> default to character cells.
4139// Pu = 1 <- device physical pixels.
4140// Pu = 2 <- character cells.
4141Terminal.prototype.enableLocatorReporting = function(params) {
4142 var val = params[0] > 0;
4143 //this.mouseEvents = val;
4144 //this.decLocator = val;
4145};
4146
4147// CSI Pt; Pl; Pb; Pr$ z
4148// Erase Rectangular Area (DECERA), VT400 and up.
4149// Pt; Pl; Pb; Pr denotes the rectangle.
4150// NOTE: xterm doesn't enable this code by default.
4151Terminal.prototype.eraseRectangle = function(params) {
4152 var t = params[0]
4153 , l = params[1]
4154 , b = params[2]
4155 , r = params[3];
4156
4157 var line
4158 , i
4159 , ch;
4160
4161 ch = [this.eraseAttr(), ' ']; // xterm?
4162
4163 for (; t < b + 1; t++) {
4164 line = this.lines[this.ybase + t];
4165 for (i = l; i < r; i++) {
4166 line[i] = ch;
4167 }
4168 }
4169
4170 // this.maxRange();
4171 this.updateRange(params[0]);
4172 this.updateRange(params[2]);
4173};
4174
4175// CSI Pm ' {
4176// Select Locator Events (DECSLE).
4177// Valid values for the first (and any additional parameters)
4178// are:
4179// Ps = 0 -> only respond to explicit host requests (DECRQLP).
4180// (This is default). It also cancels any filter
4181// rectangle.
4182// Ps = 1 -> report button down transitions.
4183// Ps = 2 -> do not report button down transitions.
4184// Ps = 3 -> report button up transitions.
4185// Ps = 4 -> do not report button up transitions.
4186Terminal.prototype.setLocatorEvents = function(params) {
4187 ;
4188};
4189
4190// CSI Pt; Pl; Pb; Pr$ {
4191// Selective Erase Rectangular Area (DECSERA), VT400 and up.
4192// Pt; Pl; Pb; Pr denotes the rectangle.
4193Terminal.prototype.selectiveEraseRectangle = function(params) {
4194 ;
4195};
4196
4197// CSI Ps ' |
4198// Request Locator Position (DECRQLP).
4199// Valid values for the parameter are:
4200// Ps = 0 , 1 or omitted -> transmit a single DECLRP locator
4201// report.
4202
4203// If Locator Reporting has been enabled by a DECELR, xterm will
4204// respond with a DECLRP Locator Report. This report is also
4205// generated on button up and down events if they have been
4206// enabled with a DECSLE, or when the locator is detected outside
4207// of a filter rectangle, if filter rectangles have been enabled
4208// with a DECEFR.
4209
4210// -> CSI Pe ; Pb ; Pr ; Pc ; Pp & w
4211
4212// Parameters are [event;button;row;column;page].
4213// Valid values for the event:
4214// Pe = 0 -> locator unavailable - no other parameters sent.
4215// Pe = 1 -> request - xterm received a DECRQLP.
4216// Pe = 2 -> left button down.
4217// Pe = 3 -> left button up.
4218// Pe = 4 -> middle button down.
4219// Pe = 5 -> middle button up.
4220// Pe = 6 -> right button down.
4221// Pe = 7 -> right button up.
4222// Pe = 8 -> M4 button down.
4223// Pe = 9 -> M4 button up.
4224// Pe = 1 0 -> locator outside filter rectangle.
4225// ``button'' parameter is a bitmask indicating which buttons are
4226// pressed:
4227// Pb = 0 <- no buttons down.
4228// Pb & 1 <- right button down.
4229// Pb & 2 <- middle button down.
4230// Pb & 4 <- left button down.
4231// Pb & 8 <- M4 button down.
4232// ``row'' and ``column'' parameters are the coordinates of the
4233// locator position in the xterm window, encoded as ASCII deci-
4234// mal.
4235// The ``page'' parameter is not used by xterm, and will be omit-
4236// ted.
4237Terminal.prototype.requestLocatorPosition = function(params) {
4238 ;
4239};
4240
4241// CSI P m SP }
4242// Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
4243// NOTE: xterm doesn't enable this code by default.
4244Terminal.prototype.insertColumns = function() {
4245 var param = params[0]
4246 , l = this.ybase + this.rows
4247 , ch = [this.eraseAttr(), ' '] // xterm?
4248 , i;
4249
4250 while (param--) {
4251 for (i = this.ybase; i < l; i++) {
4252 this.lines[i].splice(this.x + 1, 0, ch);
4253 this.lines[i].pop();
4254 }
4255 }
4256
4257 this.maxRange();
4258};
4259
4260// CSI P m SP ~
4261// Delete P s Column(s) (default = 1) (DECDC), VT420 and up
4262// NOTE: xterm doesn't enable this code by default.
4263Terminal.prototype.deleteColumns = function() {
4264 var param = params[0]
4265 , l = this.ybase + this.rows
4266 , ch = [this.eraseAttr(), ' '] // xterm?
4267 , i;
4268
4269 while (param--) {
4270 for (i = this.ybase; i < l; i++) {
4271 this.lines[i].splice(this.x, 1);
4272 this.lines[i].push(ch);
4273 }
4274 }
4275
4276 this.maxRange();
4277};
4278
4279/**
4280 * Character Sets
4281 */
4282
4283Terminal.charsets = {};
4284
4285// DEC Special Character and Line Drawing Set.
4286// http://vt100.net/docs/vt102-ug/table5-13.html
4287// A lot of curses apps use this if they see TERM=xterm.
4288// testing: echo -e '\e(0a\e(B'
4289// The xterm output sometimes seems to conflict with the
4290// reference above. xterm seems in line with the reference
4291// when running vttest however.
4292// The table below now uses xterm's output from vttest.
4293Terminal.charsets.SCLD = { // (0
4294 '`': '\u25c6', // '◆'
4295 'a': '\u2592', // '▒'
4296 'b': '\u0009', // '\t'
4297 'c': '\u000c', // '\f'
4298 'd': '\u000d', // '\r'
4299 'e': '\u000a', // '\n'
4300 'f': '\u00b0', // '°'
4301 'g': '\u00b1', // '±'
4302 'h': '\u2424', // '\u2424' (NL)
4303 'i': '\u000b', // '\v'
4304 'j': '\u2518', // '┘'
4305 'k': '\u2510', // '┐'
4306 'l': '\u250c', // '┌'
4307 'm': '\u2514', // '└'
4308 'n': '\u253c', // '┼'
4309 'o': '\u23ba', // '⎺'
4310 'p': '\u23bb', // '⎻'
4311 'q': '\u2500', // '─'
4312 'r': '\u23bc', // '⎼'
4313 's': '\u23bd', // '⎽'
4314 't': '\u251c', // '├'
4315 'u': '\u2524', // '┤'
4316 'v': '\u2534', // '┴'
4317 'w': '\u252c', // '┬'
4318 'x': '\u2502', // '│'
4319 'y': '\u2264', // '≤'
4320 'z': '\u2265', // '≥'
4321 '{': '\u03c0', // 'π'
4322 '|': '\u2260', // '≠'
4323 '}': '\u00a3', // '£'
4324 '~': '\u00b7' // '·'
4325};
4326
4327Terminal.charsets.UK = null; // (A
4328Terminal.charsets.US = null; // (B (USASCII)
4329Terminal.charsets.Dutch = null; // (4
4330Terminal.charsets.Finnish = null; // (C or (5
4331Terminal.charsets.French = null; // (R
4332Terminal.charsets.FrenchCanadian = null; // (Q
4333Terminal.charsets.German = null; // (K
4334Terminal.charsets.Italian = null; // (Y
4335Terminal.charsets.NorwegianDanish = null; // (E or (6
4336Terminal.charsets.Spanish = null; // (Z
4337Terminal.charsets.Swedish = null; // (H or (7
4338Terminal.charsets.Swiss = null; // (=
4339Terminal.charsets.ISOLatin = null; // /A
4340
4341/**
4342 * Helpers
4343 */
4344
4345function on(el, type, handler, capture) {
4346 el.addEventListener(type, handler, capture || false);
4347}
4348
4349function off(el, type, handler, capture) {
4350 el.removeEventListener(type, handler, capture || false);
4351}
4352
4353function cancel(ev) {
4354 if (ev.preventDefault) ev.preventDefault();
4355 ev.returnValue = false;
4356 if (ev.stopPropagation) ev.stopPropagation();
4357 ev.cancelBubble = true;
4358 return false;
4359}
4360
4361function inherits(child, parent) {
4362 function f() {
4363 this.constructor = child;
4364 }
4365 f.prototype = parent.prototype;
4366 child.prototype = new f;
4367}
4368
4369var isMac = ~navigator.userAgent.indexOf('Mac');
4370
4371// if bold is broken, we can't
4372// use it in the terminal.
91273161 4373function isBoldBroken(document) {
8bc844c0
CJ
4374 var el = document.createElement('span');
4375 el.innerHTML = 'hello world';
4376 document.body.appendChild(el);
4377 var w1 = el.scrollWidth;
4378 el.style.fontWeight = 'bold';
4379 var w2 = el.scrollWidth;
4380 document.body.removeChild(el);
4381 return w1 !== w2;
4382}
4383
4384var String = this.String;
4385var setTimeout = this.setTimeout;
4386var setInterval = this.setInterval;
4387
6cc8b3cd
CJ
4388function indexOf(obj, el) {
4389 var i = obj.length;
4390 while (i--) {
4391 if (obj[i] === el) return i;
4392 }
4393 return -1;
4394}
4395
efa0e3c1 4396var wideChars = new RegExp('(['
14248234
CJ
4397 + '\\uff01-\\uffbe'
4398 + '\\uffc2-\\uffc7'
4399 + '\\uffca-\\uffcf'
4400 + '\\uffd2-\\uffd7'
4401 + '\\uffda-\\uffdc'
4402 + '\\uffe0-\\uffe6'
4403 + '\\uffe8-\\uffee'
4404 + '])', 'g');
4405
a68c8336
CJ
4406function matchColor(r1, g1, b1) {
4407 var hash = (r1 << 16) | (g1 << 8) | b1;
4408
4409 if (matchColor._cache[hash] != null) {
4410 return matchColor._cache[hash];
4411 }
4412
4413 var ldiff = Infinity
4414 , li = -1
4415 , i = 0
4416 , c
4417 , r2
4418 , g2
4419 , b2
4420 , diff;
4421
4422 for (; i < Terminal.vcolors.length; i++) {
4423 c = Terminal.vcolors[i];
4424 r2 = c[0];
4425 g2 = c[1];
4426 b2 = c[2];
4427
4428 diff = matchColor.distance(r1, g1, b1, r2, g2, b2);
4429
4430 if (diff === 0) {
4431 li = i;
4432 break;
4433 }
4434
4435 if (diff < ldiff) {
4436 ldiff = diff;
4437 li = i;
4438 }
4439 }
4440
4441 return matchColor._cache[hash] = li;
4442}
4443
4444matchColor._cache = {};
4445
4446// http://stackoverflow.com/questions/1633828
4447matchColor.distance = function(r1, g1, b1, r2, g2, b2) {
4448 return Math.pow(30 * (r1 - r2), 2)
4449 + Math.pow(59 * (g1 - g2), 2)
4450 + Math.pow(11 * (b1 - b2), 2);
4451};
4452
8bc844c0
CJ
4453/**
4454 * Expose
4455 */
4456
4457Terminal.EventEmitter = EventEmitter;
4458Terminal.isMac = isMac;
4459Terminal.inherits = inherits;
4460Terminal.on = on;
4461Terminal.off = off;
4462Terminal.cancel = cancel;
4463
4464if (typeof module !== 'undefined') {
4465 module.exports = Terminal;
4466} else {
4467 this.Terminal = Terminal;
4468}
4469
4470}).call(function() {
4471 return this || (typeof window !== 'undefined' ? window : global);
4472}());