UNPKG

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