UNPKG

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