Advertisement
pastepin57

term.js

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