Terminal emulation: implement the CSI b sequence.
CSI b repeats the previous character, if it was printable and not an escape sequence.
This commit is contained in:
parent
f2256500e1
commit
9004afebdc
1 changed files with 126 additions and 70 deletions
196
termemu.js
196
termemu.js
|
|
@ -71,6 +71,7 @@ var termemu = {
|
|||
scrB: 0, // init() will set this properly
|
||||
c: null, // Contains cursor position and text attributes
|
||||
offedge: false, // Going off the edge doesn't mean adding a new line
|
||||
lastcode: 0, // Last printed character
|
||||
clearAttrs: function () {
|
||||
/* Make sure to reset ALL attribute properties and NOTHING else. */
|
||||
this.c.bold = false;
|
||||
|
|
@ -460,6 +461,7 @@ var termemu = {
|
|||
this.screen.replaceChild(this.makeRow(), this.screen.childNodes[i]);
|
||||
}
|
||||
this.flipCursor(); // make it appear in the new row
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
},
|
||||
write: function (codes) {
|
||||
|
|
@ -531,6 +533,10 @@ var termemu = {
|
|||
debug(1, "Unrecognized sequence ESC " + codes[i].toString(16));
|
||||
this.comseq = [];
|
||||
}
|
||||
if (this.comseq.length == 0) {
|
||||
// A complete sequence was processed, clear lastcode.
|
||||
this.lastcode = 0;
|
||||
}
|
||||
}
|
||||
else if (this.comseq.length == 2 && this.comseq[0] == 27) {
|
||||
/* An ESC C N sequence. Not implemented. Doesn't check validity
|
||||
|
|
@ -555,6 +561,7 @@ var termemu = {
|
|||
String.fromCharCode(this.comseq[1]) + " 0x" +
|
||||
codes[i].toString(16));
|
||||
this.comseq = [];
|
||||
this.lastcode = 0;
|
||||
}
|
||||
else if (this.comseq[0] == 157) {
|
||||
/* Commands beginning with OSC */
|
||||
|
|
@ -566,6 +573,7 @@ var termemu = {
|
|||
debug(0, "Got " + (this.comseq.length - 1) + "-byte OSC sequence");
|
||||
this.oscProcess();
|
||||
this.comseq = [];
|
||||
this.lastcode = 0;
|
||||
}
|
||||
else
|
||||
this.comseq.push(codes[i]);
|
||||
|
|
@ -582,15 +590,17 @@ var termemu = {
|
|||
/* Chars in csiPre can only occur right after the CSI */
|
||||
debug(1, "Invalid CSI sequence: misplaced prefix");
|
||||
this.comseq = [];
|
||||
this.lastcode = 0;
|
||||
}
|
||||
else
|
||||
this.comseq.push(codes[i]);
|
||||
}
|
||||
else if (csiPost.indexOf(this.comseq[this.comseq.length - 1]) >= 0 &&
|
||||
!csiFinal(codes[i])) {
|
||||
/* Chars is csiPost must come right before the final char */
|
||||
/* Chars in csiPost must come right before the final char */
|
||||
debug(1, "Invalid CSI sequence: misplaced postfix");
|
||||
this.comseq = [];
|
||||
this.lastcode = 0;
|
||||
}
|
||||
else if ((codes[i] >= 48 && codes[i] <= 57) || codes[i] == 59 ||
|
||||
csiPost.indexOf(codes[i]) >= 0) {
|
||||
|
|
@ -605,91 +615,102 @@ var termemu = {
|
|||
else {
|
||||
debug(1, "Invalid CSI sequence: unknown code " + codes[i].toString(16));
|
||||
this.comseq = [];
|
||||
this.lastcode = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
debug(1, "Unknown sequence with " + this.comseq[0].toString(16));
|
||||
this.comseq = [];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* Treat it as a single character. */
|
||||
if (codes[i] == 5) {
|
||||
sendback("06");
|
||||
}
|
||||
else if (codes[i] == 7) {
|
||||
/* bell */
|
||||
bell(true);
|
||||
}
|
||||
else if (codes[i] == 8) {
|
||||
/* backspace */
|
||||
if (this.offedge)
|
||||
this.offedge = false;
|
||||
else if (this.c.x > 0)
|
||||
this.cmove(null, this.c.x - 1);
|
||||
}
|
||||
else if (codes[i] == 9) {
|
||||
/* tab */
|
||||
var xnew;
|
||||
if (this.c.x < this.w - 1) {
|
||||
xnew = 8 * (Math.floor(this.c.x / 8) + 1);
|
||||
if (xnew >= this.w)
|
||||
xnew = this.w - 1;
|
||||
this.cmove(null, xnew);
|
||||
}
|
||||
else {
|
||||
this.offedge = true;
|
||||
this.lastcode = 0;
|
||||
}
|
||||
}
|
||||
else if (codes[i] >= 10 && codes[i] <= 12) {
|
||||
/* newline, vertical tab, form feed */
|
||||
if (this.offedge)
|
||||
this.newline(true);
|
||||
else
|
||||
this.newline(false);
|
||||
}
|
||||
else if (codes[i] == 13) {
|
||||
/* carriage return \r */
|
||||
this.cmove(null, 0);
|
||||
}
|
||||
else if (codes[i] == 14) {
|
||||
/* shift out */
|
||||
// Currently assuming that G1 is DEC Special & Line Drawing
|
||||
this.c.cset = "0";
|
||||
debug(0, "Using DEC graphics charset.");
|
||||
}
|
||||
else if (codes[i] == 15) {
|
||||
/* shift in */
|
||||
// Currently assuming that G0 is ASCII
|
||||
this.c.cset = "B";
|
||||
debug(0, "Using ASCII charset.");
|
||||
}
|
||||
else if (codes[i] == 27) {
|
||||
/* escape */
|
||||
this.comseq.push(codes[i]);
|
||||
}
|
||||
else if (codes[i] < 32 || (codes[i] >= 127 && codes[i] < 160)) {
|
||||
/* Some kind of control character. */
|
||||
debug(1, "Unprintable character 0x" + codes[i].toString(16));
|
||||
}
|
||||
else {
|
||||
else if ((codes[i] >= 32 && codes[i] < 127) || codes[i] >= 160) {
|
||||
/* If it's ASCII, it's printable; take a risk on anything higher */
|
||||
if ((this.c.cset == "0") && (codes[i] in decChars)) {
|
||||
// DEC special character set
|
||||
this.placechar(String.fromCharCode(decChars[codes[i]]));
|
||||
this.lastcode = decChars[codes[i]];
|
||||
}
|
||||
else {
|
||||
this.placechar(String.fromCharCode(codes[i]));
|
||||
this.lastcode = codes[i];
|
||||
}
|
||||
this.placechar(String.fromCharCode(this.lastcode));
|
||||
}
|
||||
else {
|
||||
/* Treat it as a single control character. */
|
||||
this.singleCtl(codes[i]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
},
|
||||
singleCtl: function (ctlcode) {
|
||||
if (ctlcode == 5) {
|
||||
sendback("06");
|
||||
}
|
||||
else if (ctlcode == 7) {
|
||||
/* bell */
|
||||
bell(true);
|
||||
}
|
||||
else if (ctlcode == 8) {
|
||||
/* backspace */
|
||||
if (this.offedge)
|
||||
this.offedge = false;
|
||||
else if (this.c.x > 0)
|
||||
this.cmove(null, this.c.x - 1);
|
||||
}
|
||||
else if (ctlcode == 9) {
|
||||
/* tab */
|
||||
var xnew;
|
||||
if (this.c.x < this.w - 1) {
|
||||
xnew = 8 * (Math.floor(this.c.x / 8) + 1);
|
||||
if (xnew >= this.w)
|
||||
xnew = this.w - 1;
|
||||
this.cmove(null, xnew);
|
||||
}
|
||||
else {
|
||||
this.offedge = true;
|
||||
}
|
||||
}
|
||||
else if (ctlcode >= 10 && ctlcode <= 12) {
|
||||
/* newline, vertical tab, form feed */
|
||||
if (this.offedge)
|
||||
this.newline(true);
|
||||
else
|
||||
this.newline(false);
|
||||
}
|
||||
else if (ctlcode == 13) {
|
||||
/* carriage return \r */
|
||||
this.cmove(null, 0);
|
||||
}
|
||||
else if (ctlcode == 14) {
|
||||
/* shift out */
|
||||
// Currently assuming that G1 is DEC Special & Line Drawing
|
||||
this.c.cset = "0";
|
||||
debug(0, "Using DEC graphics charset.");
|
||||
}
|
||||
else if (ctlcode == 15) {
|
||||
/* shift in */
|
||||
// Currently assuming that G0 is ASCII
|
||||
this.c.cset = "B";
|
||||
debug(0, "Using ASCII charset.");
|
||||
}
|
||||
else if (ctlcode == 27) {
|
||||
/* escape */
|
||||
this.comseq.push(27);
|
||||
}
|
||||
else {
|
||||
debug(1, "Unprintable character 0x" + ctlcode.toString(16));
|
||||
}
|
||||
if (ctlcode != 27) {
|
||||
// Sequences should preserve lastcode until they are completed
|
||||
this.lastcode = 0;
|
||||
}
|
||||
},
|
||||
csiProcess: function () {
|
||||
/* Processes the CSI sequence in this.comseq */
|
||||
var c = this.comseq[this.comseq.length - 1];
|
||||
if (this.comseq[0] != 155 || !csiFinal(c))
|
||||
return;
|
||||
var printed = false;
|
||||
var comstr = "";
|
||||
for (var i = 1; i < this.comseq.length; i++)
|
||||
comstr += String.fromCharCode(this.comseq[i]);
|
||||
|
|
@ -698,6 +719,7 @@ var termemu = {
|
|||
var matchCSI = comstr.match(reCSI);
|
||||
if (!matchCSI) {
|
||||
debug(1, "Unrecognized CSI sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
var prefix = null;
|
||||
|
|
@ -725,6 +747,7 @@ var termemu = {
|
|||
/* @ - insert spaces at cursor */
|
||||
if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI @ sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
/* The cursor stays still, but characters move out from under it. */
|
||||
|
|
@ -745,6 +768,7 @@ var termemu = {
|
|||
/* E - next line, F - previous line, G - to column */
|
||||
if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
/* These may be out of range, but cmove will take care of that. */
|
||||
|
|
@ -769,6 +793,7 @@ var termemu = {
|
|||
var y = 0;
|
||||
if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI H sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
if (params[0])
|
||||
|
|
@ -787,6 +812,7 @@ var termemu = {
|
|||
var x = this.c.x;
|
||||
if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI I sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
while (count > 0) {
|
||||
|
|
@ -808,6 +834,7 @@ var termemu = {
|
|||
debug(1, "Warning: CSI ?J not implemented");
|
||||
else if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI J sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
if (!params[0]) {
|
||||
|
|
@ -828,6 +855,7 @@ var termemu = {
|
|||
}
|
||||
else {
|
||||
debug(1, "Unimplemented parameter in CSI J sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
for (var nrow = start; nrow <= end; nrow++) {
|
||||
|
|
@ -855,6 +883,7 @@ var termemu = {
|
|||
debug(1, "Warning: CSI ?K not implemented");
|
||||
else if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI K sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
/* 0 (default): right, 1: left, 2: all. Include cursor position. */
|
||||
|
|
@ -885,11 +914,14 @@ var termemu = {
|
|||
* M - delete current lines */
|
||||
if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
/* CSI LM have no effect outside of the scrolling region */
|
||||
if (this.c.y < this.scrT || this.c.y > this.scrB)
|
||||
if (this.c.y < this.scrT || this.c.y > this.scrB) {
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
this.flipCursor();
|
||||
while (count > 0) {
|
||||
var blankrow = this.makeRow();
|
||||
|
|
@ -915,6 +947,7 @@ var termemu = {
|
|||
/* P - delete at active position, causing cells on the right to shift. */
|
||||
if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI P sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
var cursrow = this.screen.childNodes[this.c.y];
|
||||
|
|
@ -930,6 +963,7 @@ var termemu = {
|
|||
/* S - scroll up, T - scroll down */
|
||||
if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
if (c == 83)
|
||||
|
|
@ -941,6 +975,7 @@ var termemu = {
|
|||
/* X - erase characters */
|
||||
if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
var row = this.screen.childNodes[this.c.y];
|
||||
|
|
@ -954,6 +989,7 @@ var termemu = {
|
|||
var x = this.c.x;
|
||||
if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI Z sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
while (count > 0) {
|
||||
|
|
@ -970,14 +1006,26 @@ var termemu = {
|
|||
/* ` - go to col */
|
||||
if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI ` sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
this.cmove(null, count - 1);
|
||||
}
|
||||
else if (c == 98) {
|
||||
/* b - repeat previous character */
|
||||
if (this.lastcode !== 0) {
|
||||
while (count > 0) {
|
||||
this.placechar(String.fromCharCode(this.lastcode));
|
||||
count--;
|
||||
}
|
||||
printed = true;
|
||||
}
|
||||
}
|
||||
else if (c == 99) {
|
||||
/* c - query terminal attributes */
|
||||
if (prefix !== null) {
|
||||
debug(1, "Unimplemented CSI sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
/* "CSI ? 1 ; 2 c" - VT100 */
|
||||
|
|
@ -987,6 +1035,7 @@ var termemu = {
|
|||
/* d - go to row */
|
||||
if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI d sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
this.cmove(count - 1, null);
|
||||
|
|
@ -997,6 +1046,7 @@ var termemu = {
|
|||
var y = 0;
|
||||
if (prefix || postfix) {
|
||||
debug(1, "Invalid CSI f sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
if (params[0])
|
||||
|
|
@ -1009,6 +1059,7 @@ var termemu = {
|
|||
/* h - set modes */
|
||||
if (prefix != '?') {
|
||||
debug(1, "Unimplemented CSI sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
|
|
@ -1047,6 +1098,7 @@ var termemu = {
|
|||
}
|
||||
else {
|
||||
debug(1, "Unimplemented CSI sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1080,6 +1132,7 @@ var termemu = {
|
|||
/* m - character attributes */
|
||||
if (prefix !== null) {
|
||||
debug(1, "Unimplemented CSI sequence: " + comstr);
|
||||
this.lastcode = 0;
|
||||
return;
|
||||
}
|
||||
if (params.length == 0)
|
||||
|
|
@ -1133,15 +1186,18 @@ var termemu = {
|
|||
t = params[0] - 1;
|
||||
if (params[1] && params[1] <= this.h)
|
||||
b = params[1] - 1;
|
||||
if (b <= t)
|
||||
return;
|
||||
this.scrT = t;
|
||||
this.scrB = b;
|
||||
this.cmove(0, 0);
|
||||
if (b > t) {
|
||||
this.scrT = t;
|
||||
this.scrB = b;
|
||||
this.cmove(0, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
debug(1, "Unimplemented CSI sequence: " + comstr);
|
||||
}
|
||||
if (!printed) {
|
||||
this.lastcode = 0;
|
||||
}
|
||||
return;
|
||||
},
|
||||
oscProcess: function () {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue