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