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