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