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