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