CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

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