/** * tty.js - an xterm emulator * Christopher Jeffrey (https://github.com/chjj/tty.js) * * Originally forked from (with the author's permission): * * Fabrice Bellard's javascript vt100 for jslinux: * http://bellard.org/jslinux/ * Copyright (c) 2011 Fabrice Bellard * (Redistribution or commercial use is prohibited * without the author's permission.) * * The original design remains. The terminal itself * has been extended to include xterm CSI codes, among * other features. */ ;(function() { /** * Terminal Emulation References: * http://vt100.net/ * http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html * http://invisible-island.net/vttest/ * http://www.inwap.com/pdp10/ansicode.txt * http://linux.die.net/man/4/console_codes * http://linux.die.net/man/7/urxvt */ 'use strict'; /** * Shared */ var window = this , document = this.document; /** * EventEmitter */ function EventEmitter() { this._events = {}; } EventEmitter.prototype.addListener = function(type, listener) { this._events[type] = this._events[type] || []; this._events[type].push(listener); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.removeListener = function(type, listener) { if (!this._events[type]) return; var obj = this._events[type] , i = obj.length; while (i--) { if (obj[i] === listener || obj[i].listener === listener) { obj.splice(i, 1); return; } } }; EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.removeAllListeners = function(type) { if (this._events[type]) delete this._events[type]; }; EventEmitter.prototype.once = function(type, listener) { function on() { var args = Array.prototype.slice.call(arguments); this.removeListener(type, on); return listener.apply(this, args); } on.listener = listener; return this.on(type, on); }; EventEmitter.prototype.emit = function(type) { if (!this._events[type]) return; var args = Array.prototype.slice.call(arguments, 1) , obj = this._events[type] , l = obj.length , i = 0; for (; i < l; i++) { obj[i].apply(this, args); } }; EventEmitter.prototype.listeners = function(type) { return this._events[type] = this._events[type] || []; }; /** * States */ var normal = 0 , escaped = 1 , csi = 2 , osc = 3 , charset = 4 , dcs = 5 , ignore = 6; /** * Terminal */ function Terminal(cols, rows, handler) { EventEmitter.call(this); var options; if (typeof cols === 'object') { options = cols; cols = options.cols; rows = options.rows; handler = options.handler; } this._options = options || {}; this.cols = cols || Terminal.geometry[0]; this.rows = rows || Terminal.geometry[1]; if (handler) { this.on('data', handler); } this.ybase = 0; this.ydisp = 0; this.x = 0; this.y = 0; this.cursorState = 0; this.cursorHidden = false; this.convertEol = false; this.state = 0; this.queue = ''; this.scrollTop = 0; this.scrollBottom = this.rows - 1; // modes this.applicationKeypad = false; this.originMode = false; this.insertMode = false; this.wraparoundMode = false; this.normal = null; // charset this.charset = null; this.gcharset = null; this.glevel = 0; this.charsets = [null]; // mouse properties this.decLocator; this.x10Mouse; this.vt200Mouse; this.vt300Mouse; this.normalMouse; this.mouseEvents; this.sendFocus; this.utfMouse; this.sgrMouse; this.urxvtMouse; // misc this.element; this.children; this.refreshStart; this.refreshEnd; this.savedX; this.savedY; this.savedCols; // stream this.readable = true; this.writable = true; this.defAttr = (257 << 9) | 256; this.curAttr = this.defAttr; this.params = []; this.currentParam = 0; this.prefix = ''; this.postfix = ''; this.lines = []; var i = this.rows; while (i--) { this.lines.push(this.blankLine()); } this.tabs; this.setupStops(); } inherits(Terminal, EventEmitter); /** * Colors */ // Colors 0-15 Terminal.colors = [ // dark: '#2e3436', '#cc0000', '#4e9a06', '#c4a000', '#3465a4', '#75507b', '#06989a', '#d3d7cf', // bright: '#555753', '#ef2929', '#8ae234', '#fce94f', '#729fcf', '#ad7fa8', '#34e2e2', '#eeeeec' ]; // Colors 16-255 // Much thanks to TooTallNate for writing this. Terminal.colors = (function() { var colors = Terminal.colors , r = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff] , i; // 16-231 i = 0; for (; i < 216; i++) { out(r[(i / 36) % 6 | 0], r[(i / 6) % 6 | 0], r[i % 6]); } // 232-255 (grey) i = 0; for (; i < 24; i++) { r = 8 + i * 10; out(r, r, r); } function out(r, g, b) { colors.push('#' + hex(r) + hex(g) + hex(b)); } function hex(c) { c = c.toString(16); return c.length < 2 ? '0' + c : c; } return colors; })(); // Default BG/FG Terminal.defaultColors = { bg: '#000000', fg: '#f0f0f0' }; Terminal.colors[256] = Terminal.defaultColors.bg; Terminal.colors[257] = Terminal.defaultColors.fg; /** * Options */ Terminal.termName = 'xterm'; Terminal.geometry = [80, 30]; Terminal.cursorBlink = true; Terminal.visualBell = false; Terminal.popOnBell = false; Terminal.scrollback = 1000; Terminal.screenKeys = false; Terminal.programFeatures = false; Terminal.debug = false; /** * Focused Terminal */ Terminal.focus = null; Terminal.prototype.focus = function() { if (Terminal.focus === this) return; if (Terminal.focus) { Terminal.focus.cursorState = 0; Terminal.focus.refresh(Terminal.focus.y, Terminal.focus.y); if (Terminal.focus.sendFocus) Terminal.focus.send('\x1b[O'); } Terminal.focus = this; if (this.sendFocus) this.send('\x1b[I'); this.showCursor(); }; /** * Global Events for key handling */ Terminal.bindKeys = function() { if (Terminal.focus) return; // We could put an "if (Terminal.focus)" check // here, but it shouldn't be necessary. on(document, 'keydown', function(ev) { return Terminal.focus.keyDown(ev); }, true); on(document, 'keypress', function(ev) { return Terminal.focus.keyPress(ev); }, true); }; /** * Open Terminal */ Terminal.prototype.open = function() { var self = this , i = 0 , div; this.element = document.createElement('div'); this.element.className = 'terminal'; this.children = []; for (; i < this.rows; i++) { div = document.createElement('div'); this.element.appendChild(div); this.children.push(div); } document.body.appendChild(this.element); this.refresh(0, this.rows - 1); Terminal.bindKeys(); this.focus(); this.startBlink(); on(this.element, 'mousedown', function() { self.focus(); }); // This probably shouldn't work, // ... but it does. Firefox's paste // event seems to only work for textareas? on(this.element, 'mousedown', function(ev) { var button = ev.button != null ? +ev.button : ev.which != null ? ev.which - 1 : null; // Does IE9 do this? if (~navigator.userAgent.indexOf('MSIE')) { button = button === 1 ? 0 : button === 4 ? 1 : button; } if (button !== 2) return; self.element.contentEditable = 'true'; setTimeout(function() { self.element.contentEditable = 'inherit'; // 'false'; }, 1); }, true); on(this.element, 'paste', function(ev) { if (ev.clipboardData) { self.send(ev.clipboardData.getData('text/plain')); } else if (window.clipboardData) { self.send(window.clipboardData.getData('Text')); } // Not necessary. Do it anyway for good measure. self.element.contentEditable = 'inherit'; return cancel(ev); }); this.bindMouse(); // XXX - hack, move this somewhere else. if (Terminal.brokenBold == null) { Terminal.brokenBold = isBoldBroken(); } // sync default bg/fg colors this.element.style.backgroundColor = Terminal.defaultColors.bg; this.element.style.color = Terminal.defaultColors.fg; //this.emit('open'); }; // XTerm mouse events // http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking // To better understand these // the xterm code is very helpful: // Relevant files: // button.c, charproc.c, misc.c // Relevant functions in xterm/button.c: // BtnCode, EmitButtonCode, EditorButton, SendMousePosition Terminal.prototype.bindMouse = function() { var el = this.element , self = this , pressed = 32; var wheelEvent = 'onmousewheel' in window ? 'mousewheel' : 'DOMMouseScroll'; // mouseup, mousedown, mousewheel // left click: ^[[M 3<^[[M#3< // mousewheel up: ^[[M`3> function sendButton(ev) { var button , pos; // get the xterm-style button button = getButton(ev); // get mouse coordinates pos = getCoords(ev); if (!pos) return; sendEvent(button, pos); switch (ev.type) { case 'mousedown': pressed = button; break; case 'mouseup': // keep it at the left // button, just in case. pressed = 32; break; case wheelEvent: // nothing. don't // interfere with // `pressed`. break; } } // motion example of a left click: // ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7< function sendMove(ev) { var button = pressed , pos; pos = getCoords(ev); if (!pos) return; // buttons marked as motions // are incremented by 32 button += 32; sendEvent(button, pos); } // encode button and // position to characters function encode(data, ch) { if (!self.utfMouse) { if (ch === 255) return data.push(0); if (ch > 127) ch = 127; data.push(ch); } else { if (ch === 2047) return data.push(0); if (ch < 127) { data.push(ch); } else { if (ch > 2047) ch = 2047; data.push(0xC0 | (ch >> 6)); data.push(0x80 | (ch & 0x3F)); } } } // send a mouse event: // regular/utf8: ^[[M Cb Cx Cy // urxvt: ^[[ Cb ; Cx ; Cy M // sgr: ^[[ Cb ; Cx ; Cy M/m // vt300: ^[[ 24(1/3/5)~ [ Cx , Cy ] \r // locator: CSI P e ; P b ; P r ; P c ; P p & w function sendEvent(button, pos) { // self.emit('mouse', { // x: pos.x - 32, // y: pos.x - 32, // button: button // }); if (self.vt300Mouse) { // NOTE: Unstable. // http://www.vt100.net/docs/vt3xx-gp/chapter15.html button &= 3; pos.x -= 32; pos.y -= 32; var data = '\x1b[24'; if (button === 0) data += '1'; else if (button === 1) data += '3'; else if (button === 2) data += '5'; else if (button === 3) return; else data += '0'; data += '~[' + pos.x + ',' + pos.y + ']\r'; self.send(data); return; } if (self.decLocator) { // NOTE: Unstable. button &= 3; pos.x -= 32; pos.y -= 32; if (button === 0) button = 2; else if (button === 1) button = 4; else if (button === 2) button = 6; else if (button === 3) button = 3; self.send('\x1b[' + button + ';' + (button === 3 ? 4 : 0) + ';' + pos.y + ';' + pos.x + ';' + (pos.page || 0) + '&w'); return; } if (self.urxvtMouse) { pos.x -= 32; pos.y -= 32; pos.x++; pos.y++; self.send('\x1b[' + button + ';' + pos.x + ';' + pos.y + 'M'); return; } if (self.sgrMouse) { pos.x -= 32; pos.y -= 32; self.send('\x1b[<' + ((button & 3) === 3 ? button & ~3 : button) + ';' + pos.x + ';' + pos.y + ((button & 3) === 3 ? 'm' : 'M')); return; } var data = []; encode(data, button); encode(data, pos.x); encode(data, pos.y); self.send('\x1b[M' + String.fromCharCode.apply(String, data)); } function getButton(ev) { var button , shift , meta , ctrl , mod; // two low bits: // 0 = left // 1 = middle // 2 = right // 3 = release // wheel up/down: // 1, and 2 - with 64 added switch (ev.type) { case 'mousedown': button = ev.button != null ? +ev.button : ev.which != null ? ev.which - 1 : null; if (~navigator.userAgent.indexOf('MSIE')) { button = button === 1 ? 0 : button === 4 ? 1 : button; } break; case 'mouseup': button = 3; break; case 'DOMMouseScroll': button = ev.detail < 0 ? 64 : 65; break; case 'mousewheel': button = ev.wheelDeltaY > 0 ? 64 : 65; break; } // next three bits are the modifiers: // 4 = shift, 8 = meta, 16 = control shift = ev.shiftKey ? 4 : 0; meta = ev.metaKey ? 8 : 0; ctrl = ev.ctrlKey ? 16 : 0; mod = shift | meta | ctrl; // no mods if (self.vt200Mouse) { // ctrl only mod &= ctrl; } else if (!self.normalMouse) { mod = 0; } // increment to SP button = (32 + (mod << 2)) + button; return button; } // mouse coordinates measured in cols/rows function getCoords(ev) { var x, y, w, h, el; // ignore browsers without pageX for now if (ev.pageX == null) return; x = ev.pageX; y = ev.pageY; el = self.element; // should probably check offsetParent // but this is more portable while (el !== document.documentElement) { x -= el.offsetLeft; y -= el.offsetTop; el = el.parentNode; } // convert to cols/rows w = self.element.clientWidth; h = self.element.clientHeight; x = ((x / w) * self.cols) | 0; y = ((y / h) * self.rows) | 0; // be sure to avoid sending // bad positions to the program if (x < 0) x = 0; if (x > self.cols) x = self.cols; if (y < 0) y = 0; if (y > self.rows) y = self.rows; // xterm sends raw bytes and // starts at 32 (SP) for each. x += 32; y += 32; return { x: x, y: y, down: ev.type === 'mousedown', up: ev.type === 'mouseup', wheel: ev.type === wheelEvent, move: ev.type === 'mousemove' }; } on(el, 'mousedown', function(ev) { if (!self.mouseEvents) return; // send the button sendButton(ev); // ensure focus self.focus(); // fix for odd bug if (self.vt200Mouse) { sendButton({ __proto__: ev, type: 'mouseup' }); return cancel(ev); } // bind events if (self.normalMouse) on(document, 'mousemove', sendMove); // x10 compatibility mode can't send button releases if (!self.x10Mouse) { on(document, 'mouseup', function up(ev) { sendButton(ev); if (self.normalMouse) off(document, 'mousemove', sendMove); off(document, 'mouseup', up); return cancel(ev); }); } return cancel(ev); }); on(el, wheelEvent, function(ev) { if (!self.mouseEvents) return; if (self.x10Mouse || self.vt300Mouse || self.decLocator) return; sendButton(ev); return cancel(ev); }); // allow mousewheel scrolling in // the shell for example on(el, wheelEvent, function(ev) { if (self.mouseEvents) return; if (self.applicationKeypad) return; if (ev.type === 'DOMMouseScroll') { self.scrollDisp(ev.detail < 0 ? -5 : 5); } else { self.scrollDisp(ev.wheelDeltaY > 0 ? -5 : 5); } return cancel(ev); }); }; /** * Destroy Terminal */ Terminal.prototype.destroy = function() { this.readable = false; this.writable = false; this._events = {}; this.handler = function() {}; this.write = function() {}; //this.emit('close'); }; /** * Rendering Engine */ // In the screen buffer, each character // is stored as a an array with a character // and a 32-bit integer. // First value: a utf-16 character. // Second value: // Next 9 bits: background color (0-511). // Next 9 bits: foreground color (0-511). // Next 14 bits: a mask for misc. flags: // 1=bold, 2=underline, 4=inverse Terminal.prototype.refresh = function(start, end) { var x , y , i , line , out , ch , width , data , attr , fgColor , bgColor , flags , row , parent; if (end - start >= this.rows / 2) { parent = this.element.parentNode; if (parent) parent.removeChild(this.element); } width = this.cols; y = start; for (; y <= end; y++) { row = y + this.ydisp; line = this.lines[row]; out = ''; if (y === this.y && this.cursorState && this.ydisp === this.ybase && !this.cursorHidden) { x = this.x; } else { x = -1; } attr = this.defAttr; i = 0; for (; i < width; i++) { data = line[i][0]; ch = line[i][1]; if (i === x) data = -1; if (data !== attr) { if (attr !== this.defAttr) { out += ''; } if (data !== this.defAttr) { if (data === -1) { out += ''; } else { out += ''; } } } switch (ch) { case '&': out += '&'; break; case '<': out += '<'; break; case '>': out += '>'; break; default: if (ch <= ' ') { out += ' '; } else { out += ch; } break; } attr = data; } if (attr !== this.defAttr) { out += ''; } this.children[y].innerHTML = out; } if (parent) parent.appendChild(this.element); }; Terminal.prototype.cursorBlink = function() { if (Terminal.focus !== this) return; this.cursorState ^= 1; this.refresh(this.y, this.y); }; Terminal.prototype.showCursor = function() { if (!this.cursorState) { this.cursorState = 1; this.refresh(this.y, this.y); } else { // Temporarily disabled: // this.refreshBlink(); } }; Terminal.prototype.startBlink = function() { if (!Terminal.cursorBlink) return; var self = this; this._blinker = function() { self.cursorBlink(); }; this._blink = setInterval(this._blinker, 500); }; Terminal.prototype.refreshBlink = function() { if (!Terminal.cursorBlink) return; clearInterval(this._blink); this._blink = setInterval(this._blinker, 500); }; Terminal.prototype.scroll = function() { var row; if (++this.ybase === Terminal.scrollback) { this.ybase = this.ybase / 2 | 0; this.lines = this.lines.slice(-(this.ybase + this.rows) + 1); } this.ydisp = this.ybase; // last line row = this.ybase + this.rows - 1; // subtract the bottom scroll region row -= this.rows - 1 - this.scrollBottom; if (row === this.lines.length) { // potential optimization: // pushing is faster than splicing // when they amount to the same // behavior. this.lines.push(this.blankLine()); } else { // add our new line this.lines.splice(row, 0, this.blankLine()); } if (this.scrollTop !== 0) { if (this.ybase !== 0) { this.ybase--; this.ydisp = this.ybase; } this.lines.splice(this.ybase + this.scrollTop, 1); } // this.maxRange(); this.updateRange(this.scrollTop); this.updateRange(this.scrollBottom); }; Terminal.prototype.scrollDisp = function(disp) { this.ydisp += disp; if (this.ydisp > this.ybase) { this.ydisp = this.ybase; } else if (this.ydisp < 0) { this.ydisp = 0; } this.refresh(0, this.rows - 1); }; Terminal.prototype.write = function(data) { var l = data.length , i = 0 , cs , ch; this.refreshStart = this.y; this.refreshEnd = this.y; if (this.ybase !== this.ydisp) { this.ydisp = this.ybase; this.maxRange(); } // this.log(JSON.stringify(data.replace(/\x1b/g, '^['))); for (; i < l; i++) { ch = data[i]; switch (this.state) { case normal: switch (ch) { // '\0' // case '\0': // break; // '\a' case '\x07': this.bell(); break; // '\n', '\v', '\f' case '\n': case '\x0b': case '\x0c': if (this.convertEol) { this.x = 0; } this.y++; if (this.y > this.scrollBottom) { this.y--; this.scroll(); } break; // '\r' case '\r': this.x = 0; break; // '\b' case '\x08': if (this.x > 0) { this.x--; } break; // '\t' case '\t': this.x = this.nextStop(); break; // shift out case '\x0e': this.setgLevel(1); break; // shift in case '\x0f': this.setgLevel(0); break; // '\e' case '\x1b': this.state = escaped; break; default: // ' ' if (ch >= ' ') { if (this.charset && this.charset[ch]) { ch = this.charset[ch]; } if (this.x >= this.cols) { this.x = 0; this.y++; if (this.y > this.scrollBottom) { this.y--; this.scroll(); } } this.lines[this.y + this.ybase][this.x] = [this.curAttr, ch]; this.x++; this.updateRange(this.y); } break; } break; case escaped: switch (ch) { // ESC [ Control Sequence Introducer ( CSI is 0x9b). case '[': this.params = []; this.currentParam = 0; this.state = csi; break; // ESC ] Operating System Command ( OSC is 0x9d). case ']': this.params = []; this.currentParam = 0; this.state = osc; break; // ESC P Device Control String ( DCS is 0x90). case 'P': this.params = []; this.currentParam = 0; this.state = dcs; break; // ESC _ Application Program Command ( APC is 0x9f). case '_': this.state = ignore; break; // ESC ^ Privacy Message ( PM is 0x9e). case '^': this.state = ignore; break; // ESC c Full Reset (RIS). case 'c': this.reset(); break; // ESC E Next Line ( NEL is 0x85). // ESC D Index ( IND is 0x84). case 'E': this.x = 0; ; case 'D': this.index(); break; // ESC M Reverse Index ( RI is 0x8d). case 'M': this.reverseIndex(); break; // ESC % Select default/utf-8 character set. // @ = default, G = utf-8 case '%': //this.charset = null; this.setgLevel(0); this.setgCharset(0, Terminal.charsets.US); this.state = normal; i++; break; // ESC (,),*,+,-,. Designate G0-G2 Character Set. case '(': // <-- this seems to get all the attention case ')': case '*': case '+': case '-': case '.': switch (ch) { case '(': this.gcharset = 0; break; case ')': this.gcharset = 1; break; case '*': this.gcharset = 2; break; case '+': this.gcharset = 3; break; case '-': this.gcharset = 1; break; case '.': this.gcharset = 2; break; } this.state = charset; break; // Designate G3 Character Set (VT300). // A = ISO Latin-1 Supplemental. // Not implemented. case '/': this.gcharset = 3; this.state = charset; i--; break; // ESC N // Single Shift Select of G2 Character Set // ( SS2 is 0x8e). This affects next character only. case 'N': break; // ESC O // Single Shift Select of G3 Character Set // ( SS3 is 0x8f). This affects next character only. case 'O': break; // ESC n // Invoke the G2 Character Set as GL (LS2). case 'n': this.setgLevel(2); break; // ESC o // Invoke the G3 Character Set as GL (LS3). case 'o': this.setgLevel(3); break; // ESC | // Invoke the G3 Character Set as GR (LS3R). case '|': this.setgLevel(3); break; // ESC } // Invoke the G2 Character Set as GR (LS2R). case '}': this.setgLevel(2); break; // ESC ~ // Invoke the G1 Character Set as GR (LS1R). case '~': this.setgLevel(1); break; // ESC 7 Save Cursor (DECSC). case '7': this.saveCursor(); this.state = normal; break; // ESC 8 Restore Cursor (DECRC). case '8': this.restoreCursor(); this.state = normal; break; // ESC # 3 DEC line height/width case '#': this.state = normal; i++; break; // ESC H Tab Set (HTS is 0x88). case 'H': this.tabSet(); break; // ESC = Application Keypad (DECPAM). case '=': this.log('Serial port requested application keypad.'); this.applicationKeypad = true; this.state = normal; break; // ESC > Normal Keypad (DECPNM). case '>': this.log('Switching back to normal keypad.'); this.applicationKeypad = false; this.state = normal; break; default: this.state = normal; this.error('Unknown ESC control: %s.', ch); break; } break; case charset: switch (ch) { case '0': // DEC Special Character and Line Drawing Set. cs = Terminal.charsets.SCLD; break; case 'A': // UK cs = Terminal.charsets.UK; break; case 'B': // United States (USASCII). cs = Terminal.charsets.US; break; case '4': // Dutch cs = Terminal.charsets.Dutch; break; case 'C': // Finnish case '5': cs = Terminal.charsets.Finnish; break; case 'R': // French cs = Terminal.charsets.French; break; case 'Q': // FrenchCanadian cs = Terminal.charsets.FrenchCanadian; break; case 'K': // German cs = Terminal.charsets.German; break; case 'Y': // Italian cs = Terminal.charsets.Italian; break; case 'E': // NorwegianDanish case '6': cs = Terminal.charsets.NorwegianDanish; break; case 'Z': // Spanish cs = Terminal.charsets.Spanish; break; case 'H': // Swedish case '7': cs = Terminal.charsets.Swedish; break; case '=': // Swiss cs = Terminal.charsets.Swiss; break; case '/': // ISOLatin (actually /A) cs = Terminal.charsets.ISOLatin; i++; break; default: // Default cs = Terminal.charsets.US; break; } this.setgCharset(this.gcharset, cs); this.gcharset = null; this.state = normal; break; case osc: // OSC Ps ; Pt ST // OSC Ps ; Pt BEL // Set Text Parameters. if (ch === '\x1b' || ch === '\x07') { if (ch === '\x1b') i++; this.params.push(this.currentParam); switch (this.params[0]) { case 0: case 1: case 2: if (this.params[1]) { this.title = this.params[1]; this.handleTitle(this.title); } break; case 3: // set X property break; case 4: case 5: // change dynamic colors break; case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: // change dynamic ui colors break; case 46: // change log file break; case 50: // dynamic font break; case 51: // emacs shell break; case 52: // manipulate selection data break; case 104: case 105: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: // reset colors break; } this.params = []; this.currentParam = 0; this.state = normal; } else { if (!this.params.length) { if (ch >= '0' && ch <= '9') { this.currentParam = this.currentParam * 10 + ch.charCodeAt(0) - 48; } else if (ch === ';') { this.params.push(this.currentParam); this.currentParam = ''; } } else { this.currentParam += ch; } } break; case csi: // '?', '>', '!' if (ch === '?' || ch === '>' || ch === '!') { this.prefix = ch; break; } // 0 - 9 if (ch >= '0' && ch <= '9') { this.currentParam = this.currentParam * 10 + ch.charCodeAt(0) - 48; break; } // '$', '"', ' ', '\'' if (ch === '$' || ch === '"' || ch === ' ' || ch === '\'') { this.postfix = ch; break; } this.params.push(this.currentParam); this.currentParam = 0; // ';' if (ch === ';') break; this.state = normal; switch (ch) { // CSI Ps A // Cursor Up Ps Times (default = 1) (CUU). case 'A': this.cursorUp(this.params); break; // CSI Ps B // Cursor Down Ps Times (default = 1) (CUD). case 'B': this.cursorDown(this.params); break; // CSI Ps C // Cursor Forward Ps Times (default = 1) (CUF). case 'C': this.cursorForward(this.params); break; // CSI Ps D // Cursor Backward Ps Times (default = 1) (CUB). case 'D': this.cursorBackward(this.params); break; // CSI Ps ; Ps H // Cursor Position [row;column] (default = [1,1]) (CUP). case 'H': this.cursorPos(this.params); break; // CSI Ps J Erase in Display (ED). case 'J': this.eraseInDisplay(this.params); break; // CSI Ps K Erase in Line (EL). case 'K': this.eraseInLine(this.params); break; // CSI Pm m Character Attributes (SGR). case 'm': this.charAttributes(this.params); break; // CSI Ps n Device Status Report (DSR). case 'n': this.deviceStatus(this.params); break; /** * Additions */ // CSI Ps @ // Insert Ps (Blank) Character(s) (default = 1) (ICH). case '@': this.insertChars(this.params); break; // CSI Ps E // Cursor Next Line Ps Times (default = 1) (CNL). case 'E': this.cursorNextLine(this.params); break; // CSI Ps F // Cursor Preceding Line Ps Times (default = 1) (CNL). case 'F': this.cursorPrecedingLine(this.params); break; // CSI Ps G // Cursor Character Absolute [column] (default = [row,1]) (CHA). case 'G': this.cursorCharAbsolute(this.params); break; // CSI Ps L // Insert Ps Line(s) (default = 1) (IL). case 'L': this.insertLines(this.params); break; // CSI Ps M // Delete Ps Line(s) (default = 1) (DL). case 'M': this.deleteLines(this.params); break; // CSI Ps P // Delete Ps Character(s) (default = 1) (DCH). case 'P': this.deleteChars(this.params); break; // CSI Ps X // Erase Ps Character(s) (default = 1) (ECH). case 'X': this.eraseChars(this.params); break; // CSI Pm ` Character Position Absolute // [column] (default = [row,1]) (HPA). case '`': this.charPosAbsolute(this.params); break; // 141 61 a * HPR - // Horizontal Position Relative case 'a': this.HPositionRelative(this.params); break; // CSI P s c // Send Device Attributes (Primary DA). // CSI > P s c // Send Device Attributes (Secondary DA) case 'c': this.sendDeviceAttributes(this.params); break; // CSI Pm d // Line Position Absolute [row] (default = [1,column]) (VPA). case 'd': this.linePosAbsolute(this.params); break; // 145 65 e * VPR - Vertical Position Relative case 'e': this.VPositionRelative(this.params); break; // CSI Ps ; Ps f // Horizontal and Vertical Position [row;column] (default = // [1,1]) (HVP). case 'f': this.HVPosition(this.params); break; // CSI Pm h Set Mode (SM). // CSI ? Pm h - mouse escape codes, cursor escape codes case 'h': this.setMode(this.params); break; // CSI Pm l Reset Mode (RM). // CSI ? Pm l case 'l': this.resetMode(this.params); break; // CSI Ps ; Ps r // Set Scrolling Region [top;bottom] (default = full size of win- // dow) (DECSTBM). // CSI ? Pm r case 'r': this.setScrollRegion(this.params); break; // CSI s // Save cursor (ANSI.SYS). case 's': this.saveCursor(this.params); break; // CSI u // Restore cursor (ANSI.SYS). case 'u': this.restoreCursor(this.params); break; /** * Lesser Used */ // CSI Ps I // Cursor Forward Tabulation Ps tab stops (default = 1) (CHT). case 'I': this.cursorForwardTab(this.params); break; // CSI Ps S Scroll up Ps lines (default = 1) (SU). case 'S': this.scrollUp(this.params); break; // CSI Ps T Scroll down Ps lines (default = 1) (SD). // CSI Ps ; Ps ; Ps ; Ps ; Ps T // CSI > Ps; Ps T case 'T': // if (this.prefix === '>') { // this.resetTitleModes(this.params); // break; // } // if (this.params.length > 2) { // this.initMouseTracking(this.params); // break; // } if (this.params.length < 2 && !this.prefix) { this.scrollDown(this.params); } break; // CSI Ps Z // Cursor Backward Tabulation Ps tab stops (default = 1) (CBT). case 'Z': this.cursorBackwardTab(this.params); break; // CSI Ps b Repeat the preceding graphic character Ps times (REP). case 'b': this.repeatPrecedingCharacter(this.params); break; // CSI Ps g Tab Clear (TBC). case 'g': this.tabClear(this.params); break; // CSI Pm i Media Copy (MC). // CSI ? Pm i // case 'i': // this.mediaCopy(this.params); // break; // CSI Pm m Character Attributes (SGR). // CSI > Ps; Ps m // case 'm': // duplicate // if (this.prefix === '>') { // this.setResources(this.params); // } else { // this.charAttributes(this.params); // } // break; // CSI Ps n Device Status Report (DSR). // CSI > Ps n // case 'n': // duplicate // if (this.prefix === '>') { // this.disableModifiers(this.params); // } else { // this.deviceStatus(this.params); // } // break; // CSI > Ps p Set pointer mode. // CSI ! p Soft terminal reset (DECSTR). // CSI Ps$ p // Request ANSI mode (DECRQM). // CSI ? Ps$ p // Request DEC private mode (DECRQM). // CSI Ps ; Ps " p case 'p': switch (this.prefix) { // case '>': // this.setPointerMode(this.params); // break; case '!': this.softReset(this.params); break; // case '?': // if (this.postfix === '$') { // this.requestPrivateMode(this.params); // } // break; // default: // if (this.postfix === '"') { // this.setConformanceLevel(this.params); // } else if (this.postfix === '$') { // this.requestAnsiMode(this.params); // } // break; } break; // CSI Ps q Load LEDs (DECLL). // CSI Ps SP q // CSI Ps " q // case 'q': // if (this.postfix === ' ') { // this.setCursorStyle(this.params); // break; // } // if (this.postfix === '"') { // this.setCharProtectionAttr(this.params); // break; // } // this.loadLEDs(this.params); // break; // CSI Ps ; Ps r // Set Scrolling Region [top;bottom] (default = full size of win- // dow) (DECSTBM). // CSI ? Pm r // CSI Pt; Pl; Pb; Pr; Ps$ r // case 'r': // duplicate // if (this.prefix === '?') { // this.restorePrivateValues(this.params); // } else if (this.postfix === '$') { // this.setAttrInRectangle(this.params); // } else { // this.setScrollRegion(this.params); // } // break; // CSI s Save cursor (ANSI.SYS). // CSI ? Pm s // case 's': // duplicate // if (this.prefix === '?') { // this.savePrivateValues(this.params); // } else { // this.saveCursor(this.params); // } // break; // CSI Ps ; Ps ; Ps t // CSI Pt; Pl; Pb; Pr; Ps$ t // CSI > Ps; Ps t // CSI Ps SP t // case 't': // if (this.postfix === '$') { // this.reverseAttrInRectangle(this.params); // } else if (this.postfix === ' ') { // this.setWarningBellVolume(this.params); // } else { // if (this.prefix === '>') { // this.setTitleModeFeature(this.params); // } else { // this.manipulateWindow(this.params); // } // } // break; // CSI u Restore cursor (ANSI.SYS). // CSI Ps SP u // case 'u': // duplicate // if (this.postfix === ' ') { // this.setMarginBellVolume(this.params); // } else { // this.restoreCursor(this.params); // } // break; // CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v // case 'v': // if (this.postfix === '$') { // this.copyRectagle(this.params); // } // break; // CSI Pt ; Pl ; Pb ; Pr ' w // case 'w': // if (this.postfix === '\'') { // this.enableFilterRectangle(this.params); // } // break; // CSI Ps x Request Terminal Parameters (DECREQTPARM). // CSI Ps x Select Attribute Change Extent (DECSACE). // CSI Pc; Pt; Pl; Pb; Pr$ x // case 'x': // if (this.postfix === '$') { // this.fillRectangle(this.params); // } else { // this.requestParameters(this.params); // //this.__(this.params); // } // break; // CSI Ps ; Pu ' z // CSI Pt; Pl; Pb; Pr$ z // case 'z': // if (this.postfix === '\'') { // this.enableLocatorReporting(this.params); // } else if (this.postfix === '$') { // this.eraseRectangle(this.params); // } // break; // CSI Pm ' { // CSI Pt; Pl; Pb; Pr$ { // case '{': // if (this.postfix === '\'') { // this.setLocatorEvents(this.params); // } else if (this.postfix === '$') { // this.selectiveEraseRectangle(this.params); // } // break; // CSI Ps ' | // case '|': // if (this.postfix === '\'') { // this.requestLocatorPosition(this.params); // } // break; // CSI P m SP } // Insert P s Column(s) (default = 1) (DECIC), VT420 and up. // case '}': // if (this.postfix === ' ') { // this.insertColumns(this.params); // } // break; // CSI P m SP ~ // Delete P s Column(s) (default = 1) (DECDC), VT420 and up // case '~': // if (this.postfix === ' ') { // this.deleteColumns(this.params); // } // break; default: this.error('Unknown CSI code: %s.', ch); break; } this.prefix = ''; this.postfix = ''; break; case dcs: if (ch === '\x1b' || ch === '\x07') { if (ch === '\x1b') i++; switch (this.prefix) { // User-Defined Keys (DECUDK). case '': break; // Request Status String (DECRQSS). // test: echo -e '\eP$q"p\e\\' case '$q': var pt = this.currentParam , valid = false; switch (pt) { // DECSCA case '"q': pt = '0"q'; break; // DECSCL case '"p': pt = '61"p'; break; // DECSTBM case 'r': pt = '' + (this.scrollTop + 1) + ';' + (this.scrollBottom + 1) + 'r'; break; // SGR case 'm': pt = '0m'; break; default: this.error('Unknown DCS Pt: %s.', pt); pt = ''; break; } this.send('\x1bP' + +valid + '$r' + pt + '\x1b\\'); break; // Set Termcap/Terminfo Data (xterm, experimental). case '+p': break; // Request Termcap/Terminfo String (xterm, experimental) // Regular xterm does not even respond to this sequence. // This can cause a small glitch in vim. // test: echo -ne '\eP+q6b64\e\\' case '+q': var pt = this.currentParam , valid = false; this.send('\x1bP' + +valid + '+r' + pt + '\x1b\\'); break; default: this.error('Unknown DCS prefix: %s.', this.prefix); break; } this.currentParam = 0; this.prefix = ''; this.state = normal; } else if (!this.currentParam) { if (!this.prefix && ch !== '$' && ch !== '+') { this.currentParam = ch; } else if (this.prefix.length === 2) { this.currentParam = ch; } else { this.prefix += ch; } } else { this.currentParam += ch; } break; case ignore: // For PM and APC. if (ch === '\x1b' || ch === '\x07') { if (ch === '\x1b') i++; this.state = normal; } break; } } this.updateRange(this.y); this.refresh(this.refreshStart, this.refreshEnd); }; Terminal.prototype.writeln = function(data) { this.write(data + '\r\n'); }; Terminal.prototype.keyDown = function(ev) { var key; switch (ev.keyCode) { // backspace case 8: if (ev.shiftKey) { key = '\x08'; // ^H break; } key = '\x7f'; // ^? break; // tab case 9: if (ev.shiftKey) { key = '\x1b[Z'; break; } key = '\t'; break; // return/enter case 13: key = '\r'; break; // escape case 27: key = '\x1b'; break; // left-arrow case 37: if (this.applicationKeypad) { key = '\x1bOD'; // SS3 as ^[O for 7-bit //key = '\x8fD'; // SS3 as 0x8f for 8-bit break; } key = '\x1b[D'; break; // right-arrow case 39: if (this.applicationKeypad) { key = '\x1bOC'; break; } key = '\x1b[C'; break; // up-arrow case 38: if (this.applicationKeypad) { key = '\x1bOA'; break; } if (ev.ctrlKey) { this.scrollDisp(-1); return cancel(ev); } else { key = '\x1b[A'; } break; // down-arrow case 40: if (this.applicationKeypad) { key = '\x1bOB'; break; } if (ev.ctrlKey) { this.scrollDisp(1); return cancel(ev); } else { key = '\x1b[B'; } break; // delete case 46: key = '\x1b[3~'; break; // insert case 45: key = '\x1b[2~'; break; // home case 36: if (this.applicationKeypad) { key = '\x1bOH'; break; } key = '\x1bOH'; break; // end case 35: if (this.applicationKeypad) { key = '\x1bOF'; break; } key = '\x1bOF'; break; // page up case 33: if (ev.shiftKey) { this.scrollDisp(-(this.rows - 1)); return cancel(ev); } else { key = '\x1b[5~'; } break; // page down case 34: if (ev.shiftKey) { this.scrollDisp(this.rows - 1); return cancel(ev); } else { key = '\x1b[6~'; } break; // F1 case 112: key = '\x1bOP'; break; // F2 case 113: key = '\x1bOQ'; break; // F3 case 114: key = '\x1bOR'; break; // F4 case 115: key = '\x1bOS'; break; // F5 case 116: key = '\x1b[15~'; break; // F6 case 117: key = '\x1b[17~'; break; // F7 case 118: key = '\x1b[18~'; break; // F8 case 119: key = '\x1b[19~'; break; // F9 case 120: key = '\x1b[20~'; break; // F10 case 121: key = '\x1b[21~'; break; // F11 case 122: key = '\x1b[23~'; break; // F12 case 123: key = '\x1b[24~'; break; default: // a-z and space if (ev.ctrlKey) { if (ev.keyCode >= 65 && ev.keyCode <= 90) { key = String.fromCharCode(ev.keyCode - 64); } else if (ev.keyCode === 32) { // NUL key = String.fromCharCode(0); } else if (ev.keyCode >= 51 && ev.keyCode <= 55) { // escape, file sep, group sep, record sep, unit sep key = String.fromCharCode(ev.keyCode - 51 + 27); } else if (ev.keyCode === 56) { // delete key = String.fromCharCode(127); } else if (ev.keyCode === 219) { // ^[ - escape key = String.fromCharCode(27); } else if (ev.keyCode === 221) { // ^] - group sep key = String.fromCharCode(29); } } else if ((!isMac && ev.altKey) || (isMac && ev.metaKey)) { if (ev.keyCode >= 65 && ev.keyCode <= 90) { key = '\x1b' + String.fromCharCode(ev.keyCode + 32); } else if (ev.keyCode === 192) { key = '\x1b`'; } else if (ev.keyCode >= 48 && ev.keyCode <= 57) { key = '\x1b' + (ev.keyCode - 48); } } break; } this.emit('keydown', ev); if (key) { this.emit('key', key, ev); this.showCursor(); this.handler(key); return cancel(ev); } return true; }; Terminal.prototype.setgLevel = function(g) { this.glevel = g; this.charset = this.charsets[g]; }; Terminal.prototype.setgCharset = function(g, charset) { this.charsets[g] = charset; if (this.glevel === g) { this.charset = charset; } }; Terminal.prototype.keyPress = function(ev) { var key; cancel(ev); if (ev.charCode) { key = ev.charCode; } else if (ev.which == null) { key = ev.keyCode; } else if (ev.which !== 0 && ev.charCode !== 0) { key = ev.which; } else { return false; } if (!key || ev.ctrlKey || ev.altKey || ev.metaKey) return false; key = String.fromCharCode(key); this.emit('keypress', key, ev); this.emit('key', key, ev); this.showCursor(); this.handler(key); return false; }; Terminal.prototype.send = function(data) { var self = this; if (!this.queue) { setTimeout(function() { self.handler(self.queue); self.queue = ''; }, 1); } this.queue += data; }; Terminal.prototype.bell = function() { if (!Terminal.visualBell) return; var self = this; this.element.style.borderColor = 'white'; setTimeout(function() { self.element.style.borderColor = ''; }, 10); if (Terminal.popOnBell) this.focus(); }; Terminal.prototype.log = function() { if (!Terminal.debug) return; if (!window.console || !window.console.log) return; var args = Array.prototype.slice.call(arguments); window.console.log.apply(window.console, args); }; Terminal.prototype.error = function() { if (!Terminal.debug) return; if (!window.console || !window.console.error) return; var args = Array.prototype.slice.call(arguments); window.console.error.apply(window.console, args); }; Terminal.prototype.resize = function(x, y) { var line , el , i , j , ch; if (x < 1) x = 1; if (y < 1) y = 1; // resize cols j = this.cols; if (j < x) { ch = [this.defAttr, ' ']; i = this.lines.length; while (i--) { while (this.lines[i].length < x) { this.lines[i].push(ch); } } } else if (j > x) { i = this.lines.length; while (i--) { while (this.lines[i].length > x) { this.lines[i].pop(); } } } this.setupStops(j); this.cols = x; // resize rows j = this.rows; if (j < y) { el = this.element; while (j++ < y) { if (this.lines.length < y + this.ybase) { this.lines.push(this.blankLine()); } if (this.children.length < y) { line = document.createElement('div'); el.appendChild(line); this.children.push(line); } } } else if (j > y) { while (j-- > y) { if (this.lines.length > y + this.ybase) { this.lines.pop(); } if (this.children.length > y) { el = this.children.pop(); if (!el) continue; el.parentNode.removeChild(el); } } } this.rows = y; // make sure the cursor stays on screen if (this.y >= y) this.y = y - 1; if (this.x >= x) this.x = x - 1; this.scrollTop = 0; this.scrollBottom = y - 1; this.refresh(0, this.rows - 1); // it's a real nightmare trying // to resize the original // screen buffer. just set it // to null for now. this.normal = null; }; Terminal.prototype.updateRange = function(y) { if (y < this.refreshStart) this.refreshStart = y; if (y > this.refreshEnd) this.refreshEnd = y; }; Terminal.prototype.maxRange = function() { this.refreshStart = 0; this.refreshEnd = this.rows - 1; }; Terminal.prototype.setupStops = function(i) { if (i != null) { if (!this.tabs[i]) { i = this.prevStop(i); } } else { this.tabs = {}; i = 0; } for (; i < this.cols; i += 8) { this.tabs[i] = true; } }; Terminal.prototype.prevStop = function(x) { if (x == null) x = this.x; while (!this.tabs[--x] && x > 0); return x >= this.cols ? this.cols - 1 : x < 0 ? 0 : x; }; Terminal.prototype.nextStop = function(x) { if (x == null) x = this.x; while (!this.tabs[++x] && x < this.cols); return x >= this.cols ? this.cols - 1 : x < 0 ? 0 : x; }; Terminal.prototype.eraseRight = function(x, y) { var line = this.lines[this.ybase + y] , ch = [this.curAttr, ' ']; // xterm for (; x < this.cols; x++) { line[x] = ch; } this.updateRange(y); }; Terminal.prototype.eraseLeft = function(x, y) { var line = this.lines[this.ybase + y] , ch = [this.curAttr, ' ']; // xterm x++; while (x--) line[x] = ch; this.updateRange(y); }; Terminal.prototype.eraseLine = function(y) { this.eraseRight(0, y); }; Terminal.prototype.blankLine = function(cur) { var attr = cur ? this.curAttr : this.defAttr; var ch = [attr, ' '] , line = [] , i = 0; for (; i < this.cols; i++) { line[i] = ch; } return line; }; Terminal.prototype.ch = function(cur) { return cur ? [this.curAttr, ' '] : [this.defAttr, ' ']; }; Terminal.prototype.is = function(term) { var name = this.termName || Terminal.termName; return (name + '').indexOf(term) === 0; }; Terminal.prototype.handler = function(data) { this.emit('data', data); }; Terminal.prototype.handleTitle = function(title) { this.emit('title', title); }; /** * ESC */ // ESC D Index (IND is 0x84). Terminal.prototype.index = function() { this.y++; if (this.y > this.scrollBottom) { this.y--; this.scroll(); } this.state = normal; }; // ESC M Reverse Index (RI is 0x8d). Terminal.prototype.reverseIndex = function() { var j; this.y--; if (this.y < this.scrollTop) { this.y++; // possibly move the code below to term.reverseScroll(); // test: echo -ne '\e[1;1H\e[44m\eM\e[0m' // blankLine(true) is xterm/linux behavior this.lines.splice(this.y + this.ybase, 0, this.blankLine(true)); j = this.rows - 1 - this.scrollBottom; this.lines.splice(this.rows - 1 + this.ybase - j + 1, 1); // this.maxRange(); this.updateRange(this.scrollTop); this.updateRange(this.scrollBottom); } this.state = normal; }; // ESC c Full Reset (RIS). Terminal.prototype.reset = function() { Terminal.call(this, this.cols, this.rows); this.refresh(0, this.rows - 1); }; // ESC H Tab Set (HTS is 0x88). Terminal.prototype.tabSet = function() { this.tabs[this.x] = true; this.state = normal; }; /** * CSI */ // CSI Ps A // Cursor Up Ps Times (default = 1) (CUU). Terminal.prototype.cursorUp = function(params) { var param = params[0]; if (param < 1) param = 1; this.y -= param; if (this.y < 0) this.y = 0; }; // CSI Ps B // Cursor Down Ps Times (default = 1) (CUD). Terminal.prototype.cursorDown = function(params) { var param = params[0]; if (param < 1) param = 1; this.y += param; if (this.y >= this.rows) { this.y = this.rows - 1; } }; // CSI Ps C // Cursor Forward Ps Times (default = 1) (CUF). Terminal.prototype.cursorForward = function(params) { var param = params[0]; if (param < 1) param = 1; this.x += param; if (this.x >= this.cols) { this.x = this.cols - 1; } }; // CSI Ps D // Cursor Backward Ps Times (default = 1) (CUB). Terminal.prototype.cursorBackward = function(params) { var param = params[0]; if (param < 1) param = 1; this.x -= param; if (this.x < 0) this.x = 0; }; // CSI Ps ; Ps H // Cursor Position [row;column] (default = [1,1]) (CUP). Terminal.prototype.cursorPos = function(params) { var row, col; row = params[0] - 1; if (params.length >= 2) { col = params[1] - 1; } else { col = 0; } if (row < 0) { row = 0; } else if (row >= this.rows) { row = this.rows - 1; } if (col < 0) { col = 0; } else if (col >= this.cols) { col = this.cols - 1; } this.x = col; this.y = row; }; // CSI Ps J Erase in Display (ED). // Ps = 0 -> Erase Below (default). // Ps = 1 -> Erase Above. // Ps = 2 -> Erase All. // Ps = 3 -> Erase Saved Lines (xterm). // CSI ? Ps J // Erase in Display (DECSED). // Ps = 0 -> Selective Erase Below (default). // Ps = 1 -> Selective Erase Above. // Ps = 2 -> Selective Erase All. Terminal.prototype.eraseInDisplay = function(params) { var j; switch (params[0]) { case 0: this.eraseRight(this.x, this.y); j = this.y + 1; for (; j < this.rows; j++) { this.eraseLine(j); } break; case 1: this.eraseLeft(this.x, this.y); j = this.y; while (j--) { this.eraseLine(j); } break; case 2: j = this.rows; while (j--) this.eraseLine(j); break; case 3: ; // no saved lines break; } }; // CSI Ps K Erase in Line (EL). // Ps = 0 -> Erase to Right (default). // Ps = 1 -> Erase to Left. // Ps = 2 -> Erase All. // CSI ? Ps K // Erase in Line (DECSEL). // Ps = 0 -> Selective Erase to Right (default). // Ps = 1 -> Selective Erase to Left. // Ps = 2 -> Selective Erase All. Terminal.prototype.eraseInLine = function(params) { switch (params[0]) { case 0: this.eraseRight(this.x, this.y); break; case 1: this.eraseLeft(this.x, this.y); break; case 2: this.eraseLine(this.y); break; } }; // CSI Pm m Character Attributes (SGR). // Ps = 0 -> Normal (default). // Ps = 1 -> Bold. // Ps = 4 -> Underlined. // Ps = 5 -> Blink (appears as Bold). // Ps = 7 -> Inverse. // Ps = 8 -> Invisible, i.e., hidden (VT300). // Ps = 2 2 -> Normal (neither bold nor faint). // Ps = 2 4 -> Not underlined. // Ps = 2 5 -> Steady (not blinking). // Ps = 2 7 -> Positive (not inverse). // Ps = 2 8 -> Visible, i.e., not hidden (VT300). // Ps = 3 0 -> Set foreground color to Black. // Ps = 3 1 -> Set foreground color to Red. // Ps = 3 2 -> Set foreground color to Green. // Ps = 3 3 -> Set foreground color to Yellow. // Ps = 3 4 -> Set foreground color to Blue. // Ps = 3 5 -> Set foreground color to Magenta. // Ps = 3 6 -> Set foreground color to Cyan. // Ps = 3 7 -> Set foreground color to White. // Ps = 3 9 -> Set foreground color to default (original). // Ps = 4 0 -> Set background color to Black. // Ps = 4 1 -> Set background color to Red. // Ps = 4 2 -> Set background color to Green. // Ps = 4 3 -> Set background color to Yellow. // Ps = 4 4 -> Set background color to Blue. // Ps = 4 5 -> Set background color to Magenta. // Ps = 4 6 -> Set background color to Cyan. // Ps = 4 7 -> Set background color to White. // Ps = 4 9 -> Set background color to default (original). // If 16-color support is compiled, the following apply. Assume // that xterm's resources are set so that the ISO color codes are // the first 8 of a set of 16. Then the aixterm colors are the // bright versions of the ISO colors: // Ps = 9 0 -> Set foreground color to Black. // Ps = 9 1 -> Set foreground color to Red. // Ps = 9 2 -> Set foreground color to Green. // Ps = 9 3 -> Set foreground color to Yellow. // Ps = 9 4 -> Set foreground color to Blue. // Ps = 9 5 -> Set foreground color to Magenta. // Ps = 9 6 -> Set foreground color to Cyan. // Ps = 9 7 -> Set foreground color to White. // Ps = 1 0 0 -> Set background color to Black. // Ps = 1 0 1 -> Set background color to Red. // Ps = 1 0 2 -> Set background color to Green. // Ps = 1 0 3 -> Set background color to Yellow. // Ps = 1 0 4 -> Set background color to Blue. // Ps = 1 0 5 -> Set background color to Magenta. // Ps = 1 0 6 -> Set background color to Cyan. // Ps = 1 0 7 -> Set background color to White. // If xterm is compiled with the 16-color support disabled, it // supports the following, from rxvt: // Ps = 1 0 0 -> Set foreground and background color to // default. // If 88- or 256-color support is compiled, the following apply. // Ps = 3 8 ; 5 ; Ps -> Set foreground color to the second // Ps. // Ps = 4 8 ; 5 ; Ps -> Set background color to the second // Ps. Terminal.prototype.charAttributes = function(params) { var l = params.length , i = 0 , bg , fg , p; for (; i < l; i++) { p = params[i]; if (p >= 30 && p <= 37) { // fg color 8 this.curAttr = (this.curAttr & ~(0x1ff << 9)) | ((p - 30) << 9); } else if (p >= 40 && p <= 47) { // bg color 8 this.curAttr = (this.curAttr & ~0x1ff) | (p - 40); } else if (p >= 90 && p <= 97) { // fg color 16 p += 8; this.curAttr = (this.curAttr & ~(0x1ff << 9)) | ((p - 90) << 9); } else if (p >= 100 && p <= 107) { // bg color 16 p += 8; this.curAttr = (this.curAttr & ~0x1ff) | (p - 100); } else if (p === 0) { // default this.curAttr = this.defAttr; } else if (p === 1) { // bold text this.curAttr = this.curAttr | (1 << 18); } else if (p === 4) { // underlined text this.curAttr = this.curAttr | (2 << 18); } else if (p === 7 || p === 27) { // inverse and positive // test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m' if (p === 7) { if ((this.curAttr >> 18) & 4) continue; this.curAttr = this.curAttr | (4 << 18); } else if (p === 27) { if (~(this.curAttr >> 18) & 4) continue; this.curAttr = this.curAttr & ~(4 << 18); } bg = this.curAttr & 0x1ff; fg = (this.curAttr >> 9) & 0x1ff; this.curAttr = (this.curAttr & ~0x3ffff) | ((bg << 9) | fg); } else if (p === 22) { // not bold this.curAttr = this.curAttr & ~(1 << 18); } else if (p === 24) { // not underlined this.curAttr = this.curAttr & ~(2 << 18); } else if (p === 39) { // reset fg this.curAttr = this.curAttr & ~(0x1ff << 9); this.curAttr = this.curAttr | (((this.defAttr >> 9) & 0x1ff) << 9); } else if (p === 49) { // reset bg this.curAttr = this.curAttr & ~0x1ff; this.curAttr = this.curAttr | (this.defAttr & 0x1ff); } else if (p === 38) { // fg color 256 if (params[i+1] !== 5) continue; i += 2; p = params[i] & 0xff; // convert 88 colors to 256 // if (this.is('rxvt-unicode') && p < 88) p = p * 2.9090 | 0; this.curAttr = (this.curAttr & ~(0x1ff << 9)) | (p << 9); } else if (p === 48) { // bg color 256 if (params[i+1] !== 5) continue; i += 2; p = params[i] & 0xff; // convert 88 colors to 256 // if (this.is('rxvt-unicode') && p < 88) p = p * 2.9090 | 0; this.curAttr = (this.curAttr & ~0x1ff) | p; } } }; // CSI Ps n Device Status Report (DSR). // Ps = 5 -> Status Report. Result (``OK'') is // CSI 0 n // Ps = 6 -> Report Cursor Position (CPR) [row;column]. // Result is // CSI r ; c R // CSI ? Ps n // Device Status Report (DSR, DEC-specific). // Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI // ? r ; c R (assumes page is zero). // Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready). // or CSI ? 1 1 n (not ready). // Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked) // or CSI ? 2 1 n (locked). // Ps = 2 6 -> Report Keyboard status as // CSI ? 2 7 ; 1 ; 0 ; 0 n (North American). // The last two parameters apply to VT400 & up, and denote key- // board ready and LK01 respectively. // Ps = 5 3 -> Report Locator status as // CSI ? 5 3 n Locator available, if compiled-in, or // CSI ? 5 0 n No Locator, if not. Terminal.prototype.deviceStatus = function(params) { if (!this.prefix) { switch (params[0]) { case 5: // status report this.send('\x1b[0n'); break; case 6: // cursor position this.send('\x1b[' + (this.y + 1) + ';' + (this.x + 1) + 'R'); break; } } else if (this.prefix === '?') { // modern xterm doesnt seem to // respond to any of these except ?6, 6, and 5 switch (params[0]) { case 6: // cursor position this.send('\x1b[?' + (this.y + 1) + ';' + (this.x + 1) + 'R'); break; case 15: // no printer // this.send('\x1b[?11n'); break; case 25: // dont support user defined keys // this.send('\x1b[?21n'); break; case 26: // north american keyboard // this.send('\x1b[?27;1;0;0n'); break; case 53: // no dec locator/mouse // this.send('\x1b[?50n'); break; } } }; /** * Additions */ // CSI Ps @ // Insert Ps (Blank) Character(s) (default = 1) (ICH). Terminal.prototype.insertChars = function(params) { var param, row, j, ch; param = params[0]; if (param < 1) param = 1; row = this.y + this.ybase; j = this.x; ch = [this.curAttr, ' ']; // xterm while (param-- && j < this.cols) { this.lines[row].splice(j++, 0, ch); this.lines[row].pop(); } }; // CSI Ps E // Cursor Next Line Ps Times (default = 1) (CNL). // same as CSI Ps B ? Terminal.prototype.cursorNextLine = function(params) { var param = params[0]; if (param < 1) param = 1; this.y += param; if (this.y >= this.rows) { this.y = this.rows - 1; } this.x = 0; }; // CSI Ps F // Cursor Preceding Line Ps Times (default = 1) (CNL). // reuse CSI Ps A ? Terminal.prototype.cursorPrecedingLine = function(params) { var param = params[0]; if (param < 1) param = 1; this.y -= param; if (this.y < 0) this.y = 0; this.x = 0; }; // CSI Ps G // Cursor Character Absolute [column] (default = [row,1]) (CHA). Terminal.prototype.cursorCharAbsolute = function(params) { var param = params[0]; if (param < 1) param = 1; this.x = param - 1; }; // CSI Ps L // Insert Ps Line(s) (default = 1) (IL). Terminal.prototype.insertLines = function(params) { var param, row, j; param = params[0]; if (param < 1) param = 1; row = this.y + this.ybase; j = this.rows - 1 - this.scrollBottom; j = this.rows - 1 + this.ybase - j + 1; while (param--) { // test: echo -e '\e[44m\e[1L\e[0m' // blankLine(true) - xterm/linux behavior this.lines.splice(row, 0, this.blankLine(true)); this.lines.splice(j, 1); } // this.maxRange(); this.updateRange(this.y); this.updateRange(this.scrollBottom); }; // CSI Ps M // Delete Ps Line(s) (default = 1) (DL). Terminal.prototype.deleteLines = function(params) { var param, row, j; param = params[0]; if (param < 1) param = 1; row = this.y + this.ybase; j = this.rows - 1 - this.scrollBottom; j = this.rows - 1 + this.ybase - j; while (param--) { // test: echo -e '\e[44m\e[1M\e[0m' // blankLine(true) - xterm/linux behavior this.lines.splice(j + 1, 0, this.blankLine(true)); this.lines.splice(row, 1); } // this.maxRange(); this.updateRange(this.y); this.updateRange(this.scrollBottom); }; // CSI Ps P // Delete Ps Character(s) (default = 1) (DCH). Terminal.prototype.deleteChars = function(params) { var param, row, ch; param = params[0]; if (param < 1) param = 1; row = this.y + this.ybase; ch = [this.curAttr, ' ']; // xterm while (param--) { this.lines[row].splice(this.x, 1); this.lines[row].push(ch); } }; // CSI Ps X // Erase Ps Character(s) (default = 1) (ECH). Terminal.prototype.eraseChars = function(params) { var param, row, j, ch; param = params[0]; if (param < 1) param = 1; row = this.y + this.ybase; j = this.x; ch = [this.curAttr, ' ']; // xterm while (param-- && j < this.cols) { this.lines[row][j++] = ch; } }; // CSI Pm ` Character Position Absolute // [column] (default = [row,1]) (HPA). Terminal.prototype.charPosAbsolute = function(params) { var param = params[0]; if (param < 1) param = 1; this.x = param - 1; if (this.x >= this.cols) { this.x = this.cols - 1; } }; // 141 61 a * HPR - // Horizontal Position Relative // reuse CSI Ps C ? Terminal.prototype.HPositionRelative = function(params) { var param = params[0]; if (param < 1) param = 1; this.x += param; if (this.x >= this.cols) { this.x = this.cols - 1; } }; // CSI Ps c Send Device Attributes (Primary DA). // Ps = 0 or omitted -> request attributes from terminal. The // response depends on the decTerminalID resource setting. // -> CSI ? 1 ; 2 c (``VT100 with Advanced Video Option'') // -> CSI ? 1 ; 0 c (``VT101 with No Options'') // -> CSI ? 6 c (``VT102'') // -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c (``VT220'') // The VT100-style response parameters do not mean anything by // themselves. VT220 parameters do, telling the host what fea- // tures the terminal supports: // Ps = 1 -> 132-columns. // Ps = 2 -> Printer. // Ps = 6 -> Selective erase. // Ps = 8 -> User-defined keys. // Ps = 9 -> National replacement character sets. // Ps = 1 5 -> Technical characters. // Ps = 2 2 -> ANSI color, e.g., VT525. // Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode). // CSI > Ps c // Send Device Attributes (Secondary DA). // Ps = 0 or omitted -> request the terminal's identification // code. The response depends on the decTerminalID resource set- // ting. It should apply only to VT220 and up, but xterm extends // this to VT100. // -> CSI > Pp ; Pv ; Pc c // where Pp denotes the terminal type // Pp = 0 -> ``VT100''. // Pp = 1 -> ``VT220''. // and Pv is the firmware version (for xterm, this was originally // the XFree86 patch number, starting with 95). In a DEC termi- // nal, Pc indicates the ROM cartridge registration number and is // always zero. // More information: // xterm/charproc.c - line 2012, for more information. // vim responds with ^[[?0c or ^[[?1c after the terminal's response (?) Terminal.prototype.sendDeviceAttributes = function(params) { if (params[0] > 0) return; if (!this.prefix) { if (this.is('xterm') || this.is('rxvt-unicode') || this.is('screen')) { this.send('\x1b[?1;2c'); } else if (this.is('linux')) { this.send('\x1b[?6c'); } } else if (this.prefix === '>') { // xterm and urxvt // seem to spit this // out around ~370 times (?). if (this.is('xterm')) { this.send('\x1b[>0;276;0c'); } else if (this.is('rxvt-unicode')) { this.send('\x1b[>85;95;0c'); } else if (this.is('linux')) { // not supported by linux console. // linux console echoes parameters. this.send(params[0] + 'c'); } else if (this.is('screen')) { this.send('\x1b[>83;40003;0c'); } } }; // CSI Pm d // Line Position Absolute [row] (default = [1,column]) (VPA). Terminal.prototype.linePosAbsolute = function(params) { var param = params[0]; if (param < 1) param = 1; this.y = param - 1; if (this.y >= this.rows) { this.y = this.rows - 1; } }; // 145 65 e * VPR - Vertical Position Relative // reuse CSI Ps B ? Terminal.prototype.VPositionRelative = function(params) { var param = params[0]; if (param < 1) param = 1; this.y += param; if (this.y >= this.rows) { this.y = this.rows - 1; } }; // CSI Ps ; Ps f // Horizontal and Vertical Position [row;column] (default = // [1,1]) (HVP). Terminal.prototype.HVPosition = function(params) { if (params[0] < 1) params[0] = 1; if (params[1] < 1) params[1] = 1; this.y = params[0] - 1; if (this.y >= this.rows) { this.y = this.rows - 1; } this.x = params[1] - 1; if (this.x >= this.cols) { this.x = this.cols - 1; } }; // CSI Pm h Set Mode (SM). // Ps = 2 -> Keyboard Action Mode (AM). // Ps = 4 -> Insert Mode (IRM). // Ps = 1 2 -> Send/receive (SRM). // Ps = 2 0 -> Automatic Newline (LNM). // CSI ? Pm h // DEC Private Mode Set (DECSET). // Ps = 1 -> Application Cursor Keys (DECCKM). // Ps = 2 -> Designate USASCII for character sets G0-G3 // (DECANM), and set VT100 mode. // Ps = 3 -> 132 Column Mode (DECCOLM). // Ps = 4 -> Smooth (Slow) Scroll (DECSCLM). // Ps = 5 -> Reverse Video (DECSCNM). // Ps = 6 -> Origin Mode (DECOM). // Ps = 7 -> Wraparound Mode (DECAWM). // Ps = 8 -> Auto-repeat Keys (DECARM). // Ps = 9 -> Send Mouse X & Y on button press. See the sec- // tion Mouse Tracking. // Ps = 1 0 -> Show toolbar (rxvt). // Ps = 1 2 -> Start Blinking Cursor (att610). // Ps = 1 8 -> Print form feed (DECPFF). // Ps = 1 9 -> Set print extent to full screen (DECPEX). // Ps = 2 5 -> Show Cursor (DECTCEM). // Ps = 3 0 -> Show scrollbar (rxvt). // Ps = 3 5 -> Enable font-shifting functions (rxvt). // Ps = 3 8 -> Enter Tektronix Mode (DECTEK). // Ps = 4 0 -> Allow 80 -> 132 Mode. // Ps = 4 1 -> more(1) fix (see curses resource). // Ps = 4 2 -> Enable Nation Replacement Character sets (DECN- // RCM). // Ps = 4 4 -> Turn On Margin Bell. // Ps = 4 5 -> Reverse-wraparound Mode. // Ps = 4 6 -> Start Logging. This is normally disabled by a // compile-time option. // Ps = 4 7 -> Use Alternate Screen Buffer. (This may be dis- // abled by the titeInhibit resource). // Ps = 6 6 -> Application keypad (DECNKM). // Ps = 6 7 -> Backarrow key sends backspace (DECBKM). // Ps = 1 0 0 0 -> Send Mouse X & Y on button press and // release. See the section Mouse Tracking. // Ps = 1 0 0 1 -> Use Hilite Mouse Tracking. // Ps = 1 0 0 2 -> Use Cell Motion Mouse Tracking. // Ps = 1 0 0 3 -> Use All Motion Mouse Tracking. // Ps = 1 0 0 4 -> Send FocusIn/FocusOut events. // Ps = 1 0 0 5 -> Enable Extended Mouse Mode. // Ps = 1 0 1 0 -> Scroll to bottom on tty output (rxvt). // Ps = 1 0 1 1 -> Scroll to bottom on key press (rxvt). // Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit. // (enables the eightBitInput resource). // Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num- // Lock keys. (This enables the numLock resource). // Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This // enables the metaSendsEscape resource). // Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete // key. // Ps = 1 0 3 9 -> Send ESC when Alt modifies a key. (This // enables the altSendsEscape resource). // Ps = 1 0 4 0 -> Keep selection even if not highlighted. // (This enables the keepSelection resource). // Ps = 1 0 4 1 -> Use the CLIPBOARD selection. (This enables // the selectToClipboard resource). // Ps = 1 0 4 2 -> Enable Urgency window manager hint when // Control-G is received. (This enables the bellIsUrgent // resource). // Ps = 1 0 4 3 -> Enable raising of the window when Control-G // is received. (enables the popOnBell resource). // Ps = 1 0 4 7 -> Use Alternate Screen Buffer. (This may be // disabled by the titeInhibit resource). // Ps = 1 0 4 8 -> Save cursor as in DECSC. (This may be dis- // abled by the titeInhibit resource). // Ps = 1 0 4 9 -> Save cursor as in DECSC and use Alternate // Screen Buffer, clearing it first. (This may be disabled by // the titeInhibit resource). This combines the effects of the 1 // 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based // applications rather than the 4 7 mode. // Ps = 1 0 5 0 -> Set terminfo/termcap function-key mode. // Ps = 1 0 5 1 -> Set Sun function-key mode. // Ps = 1 0 5 2 -> Set HP function-key mode. // Ps = 1 0 5 3 -> Set SCO function-key mode. // Ps = 1 0 6 0 -> Set legacy keyboard emulation (X11R6). // Ps = 1 0 6 1 -> Set VT220 keyboard emulation. // Ps = 2 0 0 4 -> Set bracketed paste mode. // Modes: // http://vt100.net/docs/vt220-rm/chapter4.html Terminal.prototype.setMode = function(params) { if (typeof params === 'object') { var l = params.length , i = 0; for (; i < l; i++) { this.setMode(params[i]); } return; } if (!this.prefix) { switch (params) { case 4: this.insertMode = true; break; case 20: //this.convertEol = true; break; } } else if (this.prefix === '?') { switch (params) { case 1: this.applicationKeypad = true; break; case 2: this.setgCharset(0, Terminal.charsets.US); this.setgCharset(1, Terminal.charsets.US); this.setgCharset(2, Terminal.charsets.US); this.setgCharset(3, Terminal.charsets.US); // set VT100 mode here break; case 3: // 132 col mode this.savedCols = this.cols; this.resize(132, this.rows); break; case 6: this.originMode = true; break; case 7: this.wraparoundMode = true; break; case 12: // this.cursorBlink = true; break; case 9: // X10 Mouse // no release, no motion, no wheel, no modifiers. case 1000: // vt200 mouse // no motion. // no modifiers, except control on the wheel. case 1002: // button event mouse case 1003: // any event mouse // any event - sends motion events, // even if there is no button held down. this.x10Mouse = params === 9; this.vt200Mouse = params === 1000; this.normalMouse = params > 1000; this.mouseEvents = true; this.element.style.cursor = 'default'; this.log('Binding to mouse events.'); break; case 1004: // send focusin/focusout events // focusin: ^[[I // focusout: ^[[O this.sendFocus = true; break; case 1005: // utf8 ext mode mouse this.utfMouse = true; // for wide terminals // simply encodes large values as utf8 characters break; case 1006: // sgr ext mode mouse this.sgrMouse = true; // for wide terminals // does not add 32 to fields // press: ^[[ Keyboard Action Mode (AM). // Ps = 4 -> Replace Mode (IRM). // Ps = 1 2 -> Send/receive (SRM). // Ps = 2 0 -> Normal Linefeed (LNM). // CSI ? Pm l // DEC Private Mode Reset (DECRST). // Ps = 1 -> Normal Cursor Keys (DECCKM). // Ps = 2 -> Designate VT52 mode (DECANM). // Ps = 3 -> 80 Column Mode (DECCOLM). // Ps = 4 -> Jump (Fast) Scroll (DECSCLM). // Ps = 5 -> Normal Video (DECSCNM). // Ps = 6 -> Normal Cursor Mode (DECOM). // Ps = 7 -> No Wraparound Mode (DECAWM). // Ps = 8 -> No Auto-repeat Keys (DECARM). // Ps = 9 -> Don't send Mouse X & Y on button press. // Ps = 1 0 -> Hide toolbar (rxvt). // Ps = 1 2 -> Stop Blinking Cursor (att610). // Ps = 1 8 -> Don't print form feed (DECPFF). // Ps = 1 9 -> Limit print to scrolling region (DECPEX). // Ps = 2 5 -> Hide Cursor (DECTCEM). // Ps = 3 0 -> Don't show scrollbar (rxvt). // Ps = 3 5 -> Disable font-shifting functions (rxvt). // Ps = 4 0 -> Disallow 80 -> 132 Mode. // Ps = 4 1 -> No more(1) fix (see curses resource). // Ps = 4 2 -> Disable Nation Replacement Character sets (DEC- // NRCM). // Ps = 4 4 -> Turn Off Margin Bell. // Ps = 4 5 -> No Reverse-wraparound Mode. // Ps = 4 6 -> Stop Logging. (This is normally disabled by a // compile-time option). // Ps = 4 7 -> Use Normal Screen Buffer. // Ps = 6 6 -> Numeric keypad (DECNKM). // Ps = 6 7 -> Backarrow key sends delete (DECBKM). // Ps = 1 0 0 0 -> Don't send Mouse X & Y on button press and // release. See the section Mouse Tracking. // Ps = 1 0 0 1 -> Don't use Hilite Mouse Tracking. // Ps = 1 0 0 2 -> Don't use Cell Motion Mouse Tracking. // Ps = 1 0 0 3 -> Don't use All Motion Mouse Tracking. // Ps = 1 0 0 4 -> Don't send FocusIn/FocusOut events. // Ps = 1 0 0 5 -> Disable Extended Mouse Mode. // Ps = 1 0 1 0 -> Don't scroll to bottom on tty output // (rxvt). // Ps = 1 0 1 1 -> Don't scroll to bottom on key press (rxvt). // Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables // the eightBitInput resource). // Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num- // Lock keys. (This disables the numLock resource). // Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key. // (This disables the metaSendsEscape resource). // Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad // Delete key. // Ps = 1 0 3 9 -> Don't send ESC when Alt modifies a key. // (This disables the altSendsEscape resource). // Ps = 1 0 4 0 -> Do not keep selection when not highlighted. // (This disables the keepSelection resource). // Ps = 1 0 4 1 -> Use the PRIMARY selection. (This disables // the selectToClipboard resource). // Ps = 1 0 4 2 -> Disable Urgency window manager hint when // Control-G is received. (This disables the bellIsUrgent // resource). // Ps = 1 0 4 3 -> Disable raising of the window when Control- // G is received. (This disables the popOnBell resource). // Ps = 1 0 4 7 -> Use Normal Screen Buffer, clearing screen // first if in the Alternate Screen. (This may be disabled by // the titeInhibit resource). // Ps = 1 0 4 8 -> Restore cursor as in DECRC. (This may be // disabled by the titeInhibit resource). // Ps = 1 0 4 9 -> Use Normal Screen Buffer and restore cursor // as in DECRC. (This may be disabled by the titeInhibit // resource). This combines the effects of the 1 0 4 7 and 1 0 // 4 8 modes. Use this with terminfo-based applications rather // than the 4 7 mode. // Ps = 1 0 5 0 -> Reset terminfo/termcap function-key mode. // Ps = 1 0 5 1 -> Reset Sun function-key mode. // Ps = 1 0 5 2 -> Reset HP function-key mode. // Ps = 1 0 5 3 -> Reset SCO function-key mode. // Ps = 1 0 6 0 -> Reset legacy keyboard emulation (X11R6). // Ps = 1 0 6 1 -> Reset keyboard emulation to Sun/PC style. // Ps = 2 0 0 4 -> Reset bracketed paste mode. Terminal.prototype.resetMode = function(params) { if (typeof params === 'object') { var l = params.length , i = 0; for (; i < l; i++) { this.resetMode(params[i]); } return; } if (!this.prefix) { switch (params) { case 4: this.insertMode = false; break; case 20: //this.convertEol = false; break; } } else if (this.prefix === '?') { switch (params) { case 1: this.applicationKeypad = false; break; case 3: if (this.cols === 132 && this.savedCols) { this.resize(this.savedCols, this.rows); } delete this.savedCols; break; case 6: this.originMode = false; break; case 7: this.wraparoundMode = false; break; case 12: // this.cursorBlink = false; break; case 9: // X10 Mouse case 1000: // vt200 mouse case 1002: // button event mouse case 1003: // any event mouse this.x10Mouse = false; this.vt200Mouse = false; this.normalMouse = false; this.mouseEvents = false; this.element.style.cursor = ''; break; case 1004: // send focusin/focusout events this.sendFocus = false; break; case 1005: // utf8 ext mode mouse this.utfMouse = false; break; case 1006: // sgr ext mode mouse this.sgrMouse = false; break; case 1015: // urxvt ext mode mouse this.urxvtMouse = false; break; case 25: // hide cursor this.cursorHidden = true; break; case 1049: // alt screen buffer cursor ; // FALL-THROUGH case 47: // normal screen buffer case 1047: // normal screen buffer - clearing it first if (this.normal) { this.lines = this.normal.lines; this.ybase = this.normal.ybase; this.ydisp = this.normal.ydisp; this.x = this.normal.x; this.y = this.normal.y; this.scrollTop = this.normal.scrollTop; this.scrollBottom = this.normal.scrollBottom; this.tabs = this.normal.tabs; this.normal = null; // if (params === 1049) { // this.x = this.savedX; // this.y = this.savedY; // } this.refresh(0, this.rows - 1); this.showCursor(); } break; } } }; // CSI Ps ; Ps r // Set Scrolling Region [top;bottom] (default = full size of win- // dow) (DECSTBM). // CSI ? Pm r Terminal.prototype.setScrollRegion = function(params) { if (this.prefix) return; this.scrollTop = (params[0] || 1) - 1; this.scrollBottom = (params[1] || this.rows) - 1; this.x = 0; this.y = 0; }; // CSI s // Save cursor (ANSI.SYS). Terminal.prototype.saveCursor = function(params) { this.savedX = this.x; this.savedY = this.y; }; // CSI u // Restore cursor (ANSI.SYS). Terminal.prototype.restoreCursor = function(params) { this.x = this.savedX || 0; this.y = this.savedY || 0; }; /** * Lesser Used */ // CSI Ps I // Cursor Forward Tabulation Ps tab stops (default = 1) (CHT). Terminal.prototype.cursorForwardTab = function(params) { var param = params[0] || 1; while (param--) { this.x = this.nextStop(); } }; // CSI Ps S Scroll up Ps lines (default = 1) (SU). Terminal.prototype.scrollUp = function(params) { var param = params[0] || 1; while (param--) { this.lines.splice(this.ybase + this.scrollTop, 1); this.lines.splice(this.ybase + this.scrollBottom, 0, this.blankLine()); } // this.maxRange(); this.updateRange(this.scrollTop); this.updateRange(this.scrollBottom); }; // CSI Ps T Scroll down Ps lines (default = 1) (SD). Terminal.prototype.scrollDown = function(params) { var param = params[0] || 1; while (param--) { this.lines.splice(this.ybase + this.scrollBottom, 1); this.lines.splice(this.ybase + this.scrollTop, 0, this.blankLine()); } // this.maxRange(); this.updateRange(this.scrollTop); this.updateRange(this.scrollBottom); }; // CSI Ps ; Ps ; Ps ; Ps ; Ps T // Initiate highlight mouse tracking. Parameters are // [func;startx;starty;firstrow;lastrow]. See the section Mouse // Tracking. Terminal.prototype.initMouseTracking = function(params) { // Relevant: DECSET 1001 }; // CSI > Ps; Ps T // Reset one or more features of the title modes to the default // value. Normally, "reset" disables the feature. It is possi- // ble to disable the ability to reset features by compiling a // different default for the title modes into xterm. // Ps = 0 -> Do not set window/icon labels using hexadecimal. // Ps = 1 -> Do not query window/icon labels using hexadeci- // mal. // Ps = 2 -> Do not set window/icon labels using UTF-8. // Ps = 3 -> Do not query window/icon labels using UTF-8. // (See discussion of "Title Modes"). Terminal.prototype.resetTitleModes = function(params) { ; }; // CSI Ps Z Cursor Backward Tabulation Ps tab stops (default = 1) (CBT). Terminal.prototype.cursorBackwardTab = function(params) { var param = params[0] || 1; while (param--) { this.x = this.prevStop(); } }; // CSI Ps b Repeat the preceding graphic character Ps times (REP). Terminal.prototype.repeatPrecedingCharacter = function(params) { var param = params[0] || 1 , line = this.lines[this.ybase + this.y] , ch = line[this.x - 1] || [this.defAttr, ' ']; while (param--) line[this.x++] = ch; }; // CSI Ps g Tab Clear (TBC). // Ps = 0 -> Clear Current Column (default). // Ps = 3 -> Clear All. // Potentially: // Ps = 2 -> Clear Stops on Line. // http://vt100.net/annarbor/aaa-ug/section6.html Terminal.prototype.tabClear = function(params) { var param = params[0]; if (param <= 0) { delete this.tabs[this.x]; } else if (param === 3) { this.tabs = {}; } }; // CSI Pm i Media Copy (MC). // Ps = 0 -> Print screen (default). // Ps = 4 -> Turn off printer controller mode. // Ps = 5 -> Turn on printer controller mode. // CSI ? Pm i // Media Copy (MC, DEC-specific). // Ps = 1 -> Print line containing cursor. // Ps = 4 -> Turn off autoprint mode. // Ps = 5 -> Turn on autoprint mode. // Ps = 1 0 -> Print composed display, ignores DECPEX. // Ps = 1 1 -> Print all pages. Terminal.prototype.mediaCopy = function(params) { ; }; // CSI > Ps; Ps m // Set or reset resource-values used by xterm to decide whether // to construct escape sequences holding information about the // modifiers pressed with a given key. The first parameter iden- // tifies the resource to set/reset. The second parameter is the // value to assign to the resource. If the second parameter is // omitted, the resource is reset to its initial value. // Ps = 1 -> modifyCursorKeys. // Ps = 2 -> modifyFunctionKeys. // Ps = 4 -> modifyOtherKeys. // If no parameters are given, all resources are reset to their // initial values. Terminal.prototype.setResources = function(params) { ; }; // CSI > Ps n // Disable modifiers which may be enabled via the CSI > Ps; Ps m // sequence. This corresponds to a resource value of "-1", which // cannot be set with the other sequence. The parameter identi- // fies the resource to be disabled: // Ps = 1 -> modifyCursorKeys. // Ps = 2 -> modifyFunctionKeys. // Ps = 4 -> modifyOtherKeys. // If the parameter is omitted, modifyFunctionKeys is disabled. // When modifyFunctionKeys is disabled, xterm uses the modifier // keys to make an extended sequence of functions rather than // adding a parameter to each function key to denote the modi- // fiers. Terminal.prototype.disableModifiers = function(params) { ; }; // CSI > Ps p // Set resource value pointerMode. This is used by xterm to // decide whether to hide the pointer cursor as the user types. // Valid values for the parameter: // Ps = 0 -> never hide the pointer. // Ps = 1 -> hide if the mouse tracking mode is not enabled. // Ps = 2 -> always hide the pointer. If no parameter is // given, xterm uses the default, which is 1 . Terminal.prototype.setPointerMode = function(params) { ; }; // CSI ! p Soft terminal reset (DECSTR). // http://vt100.net/docs/vt220-rm/table4-10.html Terminal.prototype.softReset = function(params) { this.cursorHidden = false; this.insertMode = false; this.originMode = false; this.wraparoundMode = false; // autowrap this.applicationKeypad = false; // ? this.scrollTop = 0; this.scrollBottom = this.rows - 1; this.curAttr = this.defAttr; this.x = this.y = 0; // ? this.charset = null; this.glevel = 0; // ?? this.charsets = [null]; // ?? }; // CSI Ps$ p // Request ANSI mode (DECRQM). For VT300 and up, reply is // CSI Ps; Pm$ y // where Ps is the mode number as in RM, and Pm is the mode // value: // 0 - not recognized // 1 - set // 2 - reset // 3 - permanently set // 4 - permanently reset Terminal.prototype.requestAnsiMode = function(params) { ; }; // CSI ? Ps$ p // Request DEC private mode (DECRQM). For VT300 and up, reply is // CSI ? Ps; Pm$ p // where Ps is the mode number as in DECSET, Pm is the mode value // as in the ANSI DECRQM. Terminal.prototype.requestPrivateMode = function(params) { ; }; // CSI Ps ; Ps " p // Set conformance level (DECSCL). Valid values for the first // parameter: // Ps = 6 1 -> VT100. // Ps = 6 2 -> VT200. // Ps = 6 3 -> VT300. // Valid values for the second parameter: // Ps = 0 -> 8-bit controls. // Ps = 1 -> 7-bit controls (always set for VT100). // Ps = 2 -> 8-bit controls. Terminal.prototype.setConformanceLevel = function(params) { ; }; // CSI Ps q Load LEDs (DECLL). // Ps = 0 -> Clear all LEDS (default). // Ps = 1 -> Light Num Lock. // Ps = 2 -> Light Caps Lock. // Ps = 3 -> Light Scroll Lock. // Ps = 2 1 -> Extinguish Num Lock. // Ps = 2 2 -> Extinguish Caps Lock. // Ps = 2 3 -> Extinguish Scroll Lock. Terminal.prototype.loadLEDs = function(params) { ; }; // CSI Ps SP q // Set cursor style (DECSCUSR, VT520). // Ps = 0 -> blinking block. // Ps = 1 -> blinking block (default). // Ps = 2 -> steady block. // Ps = 3 -> blinking underline. // Ps = 4 -> steady underline. Terminal.prototype.setCursorStyle = function(params) { ; }; // CSI Ps " q // Select character protection attribute (DECSCA). Valid values // for the parameter: // Ps = 0 -> DECSED and DECSEL can erase (default). // Ps = 1 -> DECSED and DECSEL cannot erase. // Ps = 2 -> DECSED and DECSEL can erase. Terminal.prototype.setCharProtectionAttr = function(params) { ; }; // CSI ? Pm r // Restore DEC Private Mode Values. The value of Ps previously // saved is restored. Ps values are the same as for DECSET. Terminal.prototype.restorePrivateValues = function(params) { ; }; // CSI Pt; Pl; Pb; Pr; Ps$ r // Change Attributes in Rectangular Area (DECCARA), VT400 and up. // Pt; Pl; Pb; Pr denotes the rectangle. // Ps denotes the SGR attributes to change: 0, 1, 4, 5, 7. // NOTE: xterm doesn't enable this code by default. Terminal.prototype.setAttrInRectangle = function(params) { var t = params[0] , l = params[1] , b = params[2] , r = params[3] , attr = params[4]; var line , i; for (; t < b + 1; t++) { line = this.lines[this.ybase + t]; for (i = l; i < r; i++) { line[i] = [attr, line[i][1]]; } } // this.maxRange(); this.updateRange(params[0]); this.updateRange(params[2]); }; // CSI ? Pm s // Save DEC Private Mode Values. Ps values are the same as for // DECSET. Terminal.prototype.savePrivateValues = function(params) { ; }; // CSI Ps ; Ps ; Ps t // Window manipulation (from dtterm, as well as extensions). // These controls may be disabled using the allowWindowOps // resource. Valid values for the first (and any additional // parameters) are: // Ps = 1 -> De-iconify window. // Ps = 2 -> Iconify window. // Ps = 3 ; x ; y -> Move window to [x, y]. // Ps = 4 ; height ; width -> Resize the xterm window to // height and width in pixels. // Ps = 5 -> Raise the xterm window to the front of the stack- // ing order. // Ps = 6 -> Lower the xterm window to the bottom of the // stacking order. // Ps = 7 -> Refresh the xterm window. // Ps = 8 ; height ; width -> Resize the text area to // [height;width] in characters. // Ps = 9 ; 0 -> Restore maximized window. // Ps = 9 ; 1 -> Maximize window (i.e., resize to screen // size). // Ps = 1 0 ; 0 -> Undo full-screen mode. // Ps = 1 0 ; 1 -> Change to full-screen. // Ps = 1 1 -> Report xterm window state. If the xterm window // is open (non-iconified), it returns CSI 1 t . If the xterm // window is iconified, it returns CSI 2 t . // Ps = 1 3 -> Report xterm window position. Result is CSI 3 // ; x ; y t // Ps = 1 4 -> Report xterm window in pixels. Result is CSI // 4 ; height ; width t // Ps = 1 8 -> Report the size of the text area in characters. // Result is CSI 8 ; height ; width t // Ps = 1 9 -> Report the size of the screen in characters. // Result is CSI 9 ; height ; width t // Ps = 2 0 -> Report xterm window's icon label. Result is // OSC L label ST // Ps = 2 1 -> Report xterm window's title. Result is OSC l // label ST // Ps = 2 2 ; 0 -> Save xterm icon and window title on // stack. // Ps = 2 2 ; 1 -> Save xterm icon title on stack. // Ps = 2 2 ; 2 -> Save xterm window title on stack. // Ps = 2 3 ; 0 -> Restore xterm icon and window title from // stack. // Ps = 2 3 ; 1 -> Restore xterm icon title from stack. // Ps = 2 3 ; 2 -> Restore xterm window title from stack. // Ps >= 2 4 -> Resize to Ps lines (DECSLPP). Terminal.prototype.manipulateWindow = function(params) { ; }; // CSI Pt; Pl; Pb; Pr; Ps$ t // Reverse Attributes in Rectangular Area (DECRARA), VT400 and // up. // Pt; Pl; Pb; Pr denotes the rectangle. // Ps denotes the attributes to reverse, i.e., 1, 4, 5, 7. // NOTE: xterm doesn't enable this code by default. Terminal.prototype.reverseAttrInRectangle = function(params) { ; }; // CSI > Ps; Ps t // Set one or more features of the title modes. Each parameter // enables a single feature. // Ps = 0 -> Set window/icon labels using hexadecimal. // Ps = 1 -> Query window/icon labels using hexadecimal. // Ps = 2 -> Set window/icon labels using UTF-8. // Ps = 3 -> Query window/icon labels using UTF-8. (See dis- // cussion of "Title Modes") Terminal.prototype.setTitleModeFeature = function(params) { ; }; // CSI Ps SP t // Set warning-bell volume (DECSWBV, VT520). // Ps = 0 or 1 -> off. // Ps = 2 , 3 or 4 -> low. // Ps = 5 , 6 , 7 , or 8 -> high. Terminal.prototype.setWarningBellVolume = function(params) { ; }; // CSI Ps SP u // Set margin-bell volume (DECSMBV, VT520). // Ps = 1 -> off. // Ps = 2 , 3 or 4 -> low. // Ps = 0 , 5 , 6 , 7 , or 8 -> high. Terminal.prototype.setMarginBellVolume = function(params) { ; }; // CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v // Copy Rectangular Area (DECCRA, VT400 and up). // Pt; Pl; Pb; Pr denotes the rectangle. // Pp denotes the source page. // Pt; Pl denotes the target location. // Pp denotes the target page. // NOTE: xterm doesn't enable this code by default. Terminal.prototype.copyRectangle = function(params) { ; }; // CSI Pt ; Pl ; Pb ; Pr ' w // Enable Filter Rectangle (DECEFR), VT420 and up. // Parameters are [top;left;bottom;right]. // Defines the coordinates of a filter rectangle and activates // it. Anytime the locator is detected outside of the filter // rectangle, an outside rectangle event is generated and the // rectangle is disabled. Filter rectangles are always treated // as "one-shot" events. Any parameters that are omitted default // to the current locator position. If all parameters are omit- // ted, any locator motion will be reported. DECELR always can- // cels any prevous rectangle definition. Terminal.prototype.enableFilterRectangle = function(params) { ; }; // CSI Ps x Request Terminal Parameters (DECREQTPARM). // if Ps is a "0" (default) or "1", and xterm is emulating VT100, // the control sequence elicits a response of the same form whose // parameters describe the terminal: // Ps -> the given Ps incremented by 2. // Pn = 1 <- no parity. // Pn = 1 <- eight bits. // Pn = 1 <- 2 8 transmit 38.4k baud. // Pn = 1 <- 2 8 receive 38.4k baud. // Pn = 1 <- clock multiplier. // Pn = 0 <- STP flags. Terminal.prototype.requestParameters = function(params) { ; }; // CSI Ps x Select Attribute Change Extent (DECSACE). // Ps = 0 -> from start to end position, wrapped. // Ps = 1 -> from start to end position, wrapped. // Ps = 2 -> rectangle (exact). Terminal.prototype.selectChangeExtent = function(params) { ; }; // CSI Pc; Pt; Pl; Pb; Pr$ x // Fill Rectangular Area (DECFRA), VT420 and up. // Pc is the character to use. // Pt; Pl; Pb; Pr denotes the rectangle. // NOTE: xterm doesn't enable this code by default. Terminal.prototype.fillRectangle = function(params) { var ch = params[0] , t = params[1] , l = params[2] , b = params[3] , r = params[4]; var line , i; for (; t < b + 1; t++) { line = this.lines[this.ybase + t]; for (i = l; i < r; i++) { line[i] = [line[i][0], String.fromCharCode(ch)]; } } // this.maxRange(); this.updateRange(params[1]); this.updateRange(params[3]); }; // CSI Ps ; Pu ' z // Enable Locator Reporting (DECELR). // Valid values for the first parameter: // Ps = 0 -> Locator disabled (default). // Ps = 1 -> Locator enabled. // Ps = 2 -> Locator enabled for one report, then disabled. // The second parameter specifies the coordinate unit for locator // reports. // Valid values for the second parameter: // Pu = 0 <- or omitted -> default to character cells. // Pu = 1 <- device physical pixels. // Pu = 2 <- character cells. Terminal.prototype.enableLocatorReporting = function(params) { var val = params[0] > 0; //this.mouseEvents = val; //this.decLocator = val; }; // CSI Pt; Pl; Pb; Pr$ z // Erase Rectangular Area (DECERA), VT400 and up. // Pt; Pl; Pb; Pr denotes the rectangle. // NOTE: xterm doesn't enable this code by default. Terminal.prototype.eraseRectangle = function(params) { var t = params[0] , l = params[1] , b = params[2] , r = params[3]; var line , i , ch; ch = [this.curAttr, ' ']; // xterm? for (; t < b + 1; t++) { line = this.lines[this.ybase + t]; for (i = l; i < r; i++) { line[i] = ch; } } // this.maxRange(); this.updateRange(params[0]); this.updateRange(params[2]); }; // CSI Pm ' { // Select Locator Events (DECSLE). // Valid values for the first (and any additional parameters) // are: // Ps = 0 -> only respond to explicit host requests (DECRQLP). // (This is default). It also cancels any filter // rectangle. // Ps = 1 -> report button down transitions. // Ps = 2 -> do not report button down transitions. // Ps = 3 -> report button up transitions. // Ps = 4 -> do not report button up transitions. Terminal.prototype.setLocatorEvents = function(params) { ; }; // CSI Pt; Pl; Pb; Pr$ { // Selective Erase Rectangular Area (DECSERA), VT400 and up. // Pt; Pl; Pb; Pr denotes the rectangle. Terminal.prototype.selectiveEraseRectangle = function(params) { ; }; // CSI Ps ' | // Request Locator Position (DECRQLP). // Valid values for the parameter are: // Ps = 0 , 1 or omitted -> transmit a single DECLRP locator // report. // If Locator Reporting has been enabled by a DECELR, xterm will // respond with a DECLRP Locator Report. This report is also // generated on button up and down events if they have been // enabled with a DECSLE, or when the locator is detected outside // of a filter rectangle, if filter rectangles have been enabled // with a DECEFR. // -> CSI Pe ; Pb ; Pr ; Pc ; Pp & w // Parameters are [event;button;row;column;page]. // Valid values for the event: // Pe = 0 -> locator unavailable - no other parameters sent. // Pe = 1 -> request - xterm received a DECRQLP. // Pe = 2 -> left button down. // Pe = 3 -> left button up. // Pe = 4 -> middle button down. // Pe = 5 -> middle button up. // Pe = 6 -> right button down. // Pe = 7 -> right button up. // Pe = 8 -> M4 button down. // Pe = 9 -> M4 button up. // Pe = 1 0 -> locator outside filter rectangle. // ``button'' parameter is a bitmask indicating which buttons are // pressed: // Pb = 0 <- no buttons down. // Pb & 1 <- right button down. // Pb & 2 <- middle button down. // Pb & 4 <- left button down. // Pb & 8 <- M4 button down. // ``row'' and ``column'' parameters are the coordinates of the // locator position in the xterm window, encoded as ASCII deci- // mal. // The ``page'' parameter is not used by xterm, and will be omit- // ted. Terminal.prototype.requestLocatorPosition = function(params) { ; }; // CSI P m SP } // Insert P s Column(s) (default = 1) (DECIC), VT420 and up. // NOTE: xterm doesn't enable this code by default. Terminal.prototype.insertColumns = function() { var param = params[0] , l = this.ybase + this.rows , ch = [this.curAttr, ' '] // xterm? , i; while (param--) { for (i = this.ybase; i < l; i++) { this.lines[i].splice(this.x + 1, 0, ch); this.lines[i].pop(); } } this.maxRange(); }; // CSI P m SP ~ // Delete P s Column(s) (default = 1) (DECDC), VT420 and up // NOTE: xterm doesn't enable this code by default. Terminal.prototype.deleteColumns = function() { var param = params[0] , l = this.ybase + this.rows , ch = [this.curAttr, ' '] // xterm? , i; while (param--) { for (i = this.ybase; i < l; i++) { this.lines[i].splice(this.x, 1); this.lines[i].push(ch); } } this.maxRange(); }; /** * Character Sets */ Terminal.charsets = {}; // DEC Special Character and Line Drawing Set. // http://vt100.net/docs/vt102-ug/table5-13.html // A lot of curses apps use this if they see TERM=xterm. // testing: echo -e '\e(0a\e(B' // The xterm output sometimes seems to conflict with the // reference above. xterm seems in line with the reference // when running vttest however. // The table below now uses xterm's output from vttest. Terminal.charsets.SCLD = { // (0 '`': '\u25c6', // '◆' 'a': '\u2592', // '▒' 'b': '\u0009', // '\t' 'c': '\u000c', // '\f' 'd': '\u000d', // '\r' 'e': '\u000a', // '\n' 'f': '\u00b0', // '°' 'g': '\u00b1', // '±' 'h': '\u2424', // '\u2424' (NL) 'i': '\u000b', // '\v' 'j': '\u2518', // '┘' 'k': '\u2510', // '┐' 'l': '\u250c', // '┌' 'm': '\u2514', // '└' 'n': '\u253c', // '┼' 'o': '\u23ba', // '⎺' 'p': '\u23bb', // '⎻' 'q': '\u2500', // '─' 'r': '\u23bc', // '⎼' 's': '\u23bd', // '⎽' 't': '\u251c', // '├' 'u': '\u2524', // '┤' 'v': '\u2534', // '┴' 'w': '\u252c', // '┬' 'x': '\u2502', // '│' 'y': '\u2264', // '≤' 'z': '\u2265', // '≥' '{': '\u03c0', // 'π' '|': '\u2260', // '≠' '}': '\u00a3', // '£' '~': '\u00b7' // '·' }; Terminal.charsets.UK = null; // (A Terminal.charsets.US = null; // (B (USASCII) Terminal.charsets.Dutch = null; // (4 Terminal.charsets.Finnish = null; // (C or (5 Terminal.charsets.French = null; // (R Terminal.charsets.FrenchCanadian = null; // (Q Terminal.charsets.German = null; // (K Terminal.charsets.Italian = null; // (Y Terminal.charsets.NorwegianDanish = null; // (E or (6 Terminal.charsets.Spanish = null; // (Z Terminal.charsets.Swedish = null; // (H or (7 Terminal.charsets.Swiss = null; // (= Terminal.charsets.ISOLatin = null; // /A /** * Helpers */ function on(el, type, handler, capture) { el.addEventListener(type, handler, capture || false); } function off(el, type, handler, capture) { el.removeEventListener(type, handler, capture || false); } function cancel(ev) { if (ev.preventDefault) ev.preventDefault(); ev.returnValue = false; if (ev.stopPropagation) ev.stopPropagation(); ev.cancelBubble = true; return false; } function inherits(child, parent) { function f() { this.constructor = child; } f.prototype = parent.prototype; child.prototype = new f; } var isMac = ~navigator.userAgent.indexOf('Mac'); // if bold is broken, we can't // use it in the terminal. function isBoldBroken() { var el = document.createElement('span'); el.innerHTML = 'hello world'; document.body.appendChild(el); var w1 = el.scrollWidth; el.style.fontWeight = 'bold'; var w2 = el.scrollWidth; document.body.removeChild(el); return w1 !== w2; } var String = this.String; var setTimeout = this.setTimeout; var setInterval = this.setInterval; /** * Expose */ Terminal.EventEmitter = EventEmitter; Terminal.isMac = isMac; Terminal.inherits = inherits; Terminal.on = on; Terminal.off = off; Terminal.cancel = cancel; if (typeof module !== 'undefined') { module.exports = Terminal; } else { this.Terminal = Terminal; } }).call(function() { return this || (typeof window !== 'undefined' ? window : global); }());