From f9a286a851dba75c8a77e4c12ca9bc5893a6e417 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 12 Jan 2017 20:32:15 -0800 Subject: [PATCH] Convert more CSI codes --- src/InputHandler.ts | 209 ++++++++++++++++++++++++++++++++++++++++++++ src/Interfaces.ts | 47 +++++----- src/Parser.ts | 73 ++-------------- src/xterm.js | 202 ------------------------------------------ 4 files changed, 243 insertions(+), 288 deletions(-) diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 51c6a2d..8ecc075 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -302,6 +302,215 @@ export class InputHandler implements IInputHandler { } } + /** + * CSI Ps L + * Insert Ps Line(s) (default = 1) (IL). + */ + public insertLines(params: number[]): void { + let param, row, j; + + param = params[0]; + if (param < 1) { + param = 1; + } + row = this._terminal.y + this._terminal.ybase; + + j = this._terminal.rows - 1 - this._terminal.scrollBottom; + j = this._terminal.rows - 1 + this._terminal.ybase - j + 1; + + while (param--) { + if (this._terminal.lines.length === this._terminal.lines.maxLength) { + // Trim the start of lines to make room for the new line + this._terminal.lines.trimStart(1); + this._terminal.ybase--; + this._terminal.ydisp--; + row--; + j--; + } + // test: echo -e '\e[44m\e[1L\e[0m' + // blankLine(true) - xterm/linux behavior + this._terminal.lines.splice(row, 0, this._terminal.blankLine(true)); + this._terminal.lines.splice(j, 1); + } + + // this.maxRange(); + this._terminal.updateRange(this._terminal.y); + this._terminal.updateRange(this._terminal.scrollBottom); + } + + /** + * CSI Ps M + * Delete Ps Line(s) (default = 1) (DL). + */ + public deleteLines(params: number[]): void { + let param, row, j; + + param = params[0]; + if (param < 1) { + param = 1; + } + row = this._terminal.y + this._terminal.ybase; + + j = this._terminal.rows - 1 - this._terminal.scrollBottom; + j = this._terminal.rows - 1 + this._terminal.ybase - j; + + while (param--) { + if (this._terminal.lines.length === this._terminal.lines.maxLength) { + // Trim the start of lines to make room for the new line + this._terminal.lines.trimStart(1); + this._terminal.ybase -= 1; + this._terminal.ydisp -= 1; + } + // test: echo -e '\e[44m\e[1M\e[0m' + // blankLine(true) - xterm/linux behavior + this._terminal.lines.splice(j + 1, 0, this._terminal.blankLine(true)); + this._terminal.lines.splice(row, 1); + } + + // this.maxRange(); + this._terminal.updateRange(this._terminal.y); + this._terminal.updateRange(this._terminal.scrollBottom); + } + + /** + * CSI Ps P + * Delete Ps Character(s) (default = 1) (DCH). + */ + public deleteChars(params: number[]): void { + let param, row, ch; + + param = params[0]; + if (param < 1) { + param = 1; + } + + row = this._terminal.y + this._terminal.ybase; + ch = [this._terminal.eraseAttr(), ' ', 1]; // xterm + + while (param--) { + this._terminal.lines.get(row).splice(this._terminal.x, 1); + this._terminal.lines.get(row).push(ch); + } + } + + /** + * CSI Ps X + * Erase Ps Character(s) (default = 1) (ECH). + */ + public eraseChars(params: number[]): void { + let param, row, j, ch; + + param = params[0]; + if (param < 1) { + param = 1; + } + + row = this._terminal.y + this._terminal.ybase; + j = this._terminal.x; + ch = [this._terminal.eraseAttr(), ' ', 1]; // xterm + + while (param-- && j < this._terminal.cols) { + this._terminal.lines.get(row)[j++] = ch; + } + } + + /** + * CSI Pm ` Character Position Absolute + * [column] (default = [row,1]) (HPA). + */ + public charPosAbsolute(params: number[]): void { + let param = params[0]; + if (param < 1) { + param = 1; + } + this._terminal.x = param - 1; + if (this._terminal.x >= this._terminal.cols) { + this._terminal.x = this._terminal.cols - 1; + } + } + + /** + * CSI Pm a Character Position Relative + * [columns] (default = [row,col+1]) (HPR) + * reuse CSI Ps C ? + */ + public HPositionRelative(params: number[]): void { + let param = params[0]; + if (param < 1) { + param = 1; + } + this._terminal.x += param; + if (this._terminal.x >= this._terminal.cols) { + this._terminal.x = this._terminal.cols - 1; + } + } + + /** + * CSI Ps c Send Device Attributes (Primary DA). + * Ps = 0 or omitted -> request attributes from terminal. The + * response depends on the decTerminalID resource setting. + * -> CSI ? 1 ; 2 c (``VT100 with Advanced Video Option'') + * -> CSI ? 1 ; 0 c (``VT101 with No Options'') + * -> CSI ? 6 c (``VT102'') + * -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c (``VT220'') + * The VT100-style response parameters do not mean anything by + * themselves. VT220 parameters do, telling the host what fea- + * tures the terminal supports: + * Ps = 1 -> 132-columns. + * Ps = 2 -> Printer. + * Ps = 6 -> Selective erase. + * Ps = 8 -> User-defined keys. + * Ps = 9 -> National replacement character sets. + * Ps = 1 5 -> Technical characters. + * Ps = 2 2 -> ANSI color, e.g., VT525. + * Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode). + * CSI > Ps c + * Send Device Attributes (Secondary DA). + * Ps = 0 or omitted -> request the terminal's identification + * code. The response depends on the decTerminalID resource set- + * ting. It should apply only to VT220 and up, but xterm extends + * this to VT100. + * -> CSI > Pp ; Pv ; Pc c + * where Pp denotes the terminal type + * Pp = 0 -> ``VT100''. + * Pp = 1 -> ``VT220''. + * and Pv is the firmware version (for xterm, this was originally + * the XFree86 patch number, starting with 95). In a DEC termi- + * nal, Pc indicates the ROM cartridge registration number and is + * always zero. + * More information: + * xterm/charproc.c - line 2012, for more information. + * vim responds with ^[[?0c or ^[[?1c after the terminal's response (?) + */ + public sendDeviceAttributes(params: number[]): void { + if (params[0] > 0) { + return; + } + + if (!this._terminal.prefix) { + if (this._terminal.is('xterm') || this._terminal.is('rxvt-unicode') || this._terminal.is('screen')) { + this._terminal.send(C0.ESC + '[?1;2c'); + } else if (this._terminal.is('linux')) { + this._terminal.send(C0.ESC + '[?6c'); + } + } else if (this._terminal.prefix === '>') { + // xterm and urxvt + // seem to spit this + // out around ~370 times (?). + if (this._terminal.is('xterm')) { + this._terminal.send(C0.ESC + '[>0;276;0c'); + } else if (this._terminal.is('rxvt-unicode')) { + this._terminal.send(C0.ESC + '[>85;95;0c'); + } else if (this._terminal.is('linux')) { + // not supported by linux console. + // linux console echoes parameters. + this._terminal.send(params[0] + 'c'); + } else if (this._terminal.is('screen')) { + this._terminal.send(C0.ESC + '[>83;40003;0c'); + } + } + } + /** * CSI Pm m Character Attributes (SGR). * Ps = 0 -> Normal (default). diff --git a/src/Interfaces.ts b/src/Interfaces.ts index a2cb71a..e79fe50 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -37,24 +37,31 @@ export interface ITerminal { * Handles actions generated by the parser. */ export interface IInputHandler { - bell(): void; - lineFeed(): void; - carriageReturn(): void; - backspace(): void; - tab(): void; - shiftOut(): void; - shiftIn(): void; - insertChars(params); - cursorUp(params: number[]): void; - cursorDown(params: number[]): void; - cursorForward(params: number[]): void; - cursorBackward(params: number[]): void; - cursorNextLine(params: number[]): void; - cursorPrecedingLine(params: number[]): void; - cursorCharAbsolute(params: number[]): void; - cursorPosition(params: number[]): void; - eraseInDisplay(params: number[]): void; - eraseInLine(params: number[]): void; - charAttributes(params: number[]): void; - deviceStatus(params: number[]): void; + /** C0 BEL */ bell(): void; + /** C0 LF */ lineFeed(): void; + /** C0 CR */ carriageReturn(): void; + /** C0 BS */ backspace(): void; + /** C0 HT */ tab(): void; + /** C0 SO */ shiftOut(): void; + /** C0 SI */ shiftIn(): void; + /** CSI @ */ insertChars(params); + /** CSI A */ cursorUp(params: number[]): void; + /** CSI B */ cursorDown(params: number[]): void; + /** CSI C */ cursorForward(params: number[]): void; + /** CSI D */ cursorBackward(params: number[]): void; + /** CSI E */ cursorNextLine(params: number[]): void; + /** CSI F */ cursorPrecedingLine(params: number[]): void; + /** CSI G */ cursorCharAbsolute(params: number[]): void; + /** CSI H */ cursorPosition(params: number[]): void; + /** CSI J */ eraseInDisplay(params: number[]): void; + /** CSI K */ eraseInLine(params: number[]): void; + /** CSI L */ insertLines(params: number[]): void; + /** CSI M */ deleteLines(params: number[]): void; + /** CSI P */ deleteChars(params: number[]): void; + /** CSI X */ eraseChars(params: number[]): void; + /** CSI ` */ charPosAbsolute(params: number[]): void; + /** CSI a */ HPositionRelative(params: number[]): void; + /** CSI c */ sendDeviceAttributes(params: number[]): void; + /** CSI m */ charAttributes(params: number[]): void; + /** CSI n */ deviceStatus(params: number[]): void; } diff --git a/src/Parser.ts b/src/Parser.ts index 9a14bdf..f438e6b 100644 --- a/src/Parser.ts +++ b/src/Parser.ts @@ -46,6 +46,13 @@ csiStateHandler['G'] = (handler, params) => handler.cursorCharAbsolute(params); csiStateHandler['H'] = (handler, params) => handler.cursorPosition(params); csiStateHandler['J'] = (handler, params) => handler.eraseInDisplay(params); csiStateHandler['K'] = (handler, params) => handler.eraseInLine(params); +csiStateHandler['L'] = (handler, params) => handler.insertLines(params); +csiStateHandler['M'] = (handler, params) => handler.deleteLines(params); +csiStateHandler['P'] = (handler, params) => handler.deleteChars(params); +csiStateHandler['X'] = (handler, params) => handler.eraseChars(params); +csiStateHandler['`'] = (handler, params) => handler.charPosAbsolute(params); +csiStateHandler['a'] = (handler, params) => handler.HPositionRelative(params); +csiStateHandler['c'] = (handler, params) => handler.sendDeviceAttributes(params); csiStateHandler['m'] = (handler, params) => handler.charAttributes(params); csiStateHandler['n'] = (handler, params) => handler.deviceStatus(params); @@ -543,72 +550,6 @@ export class Parser { switch (ch) { - /** - * Additions - */ - - // CSI Ps E - // Cursor Next Line Ps Times (default = 1) (CNL). - case 'E': - this._terminal.cursorNextLine(this._terminal.params); - break; - - // CSI Ps F - // Cursor Preceding Line Ps Times (default = 1) (CNL). - case 'F': - this._terminal.cursorPrecedingLine(this._terminal.params); - break; - - // CSI Ps G - // Cursor Character Absolute [column] (default = [row,1]) (CHA). - case 'G': - this._terminal.cursorCharAbsolute(this._terminal.params); - break; - - // CSI Ps L - // Insert Ps Line(s) (default = 1) (IL). - case 'L': - this._terminal.insertLines(this._terminal.params); - break; - - // CSI Ps M - // Delete Ps Line(s) (default = 1) (DL). - case 'M': - this._terminal.deleteLines(this._terminal.params); - break; - - // CSI Ps P - // Delete Ps Character(s) (default = 1) (DCH). - case 'P': - this._terminal.deleteChars(this._terminal.params); - break; - - // CSI Ps X - // Erase Ps Character(s) (default = 1) (ECH). - case 'X': - this._terminal.eraseChars(this._terminal.params); - break; - - // CSI Pm ` Character Position Absolute - // [column] (default = [row,1]) (HPA). - case '`': - this._terminal.charPosAbsolute(this._terminal.params); - break; - - // 141 61 a * HPR - - // Horizontal Position Relative - case 'a': - this._terminal.HPositionRelative(this._terminal.params); - break; - - // CSI P s c - // Send Device Attributes (Primary DA). - // CSI > P s c - // Send Device Attributes (Secondary DA) - case 'c': - this._terminal.sendDeviceAttributes(this._terminal.params); - break; - // CSI Pm d // Line Position Absolute [row] (default = [1,column]) (VPA). case 'd': diff --git a/src/xterm.js b/src/xterm.js index 62baf51..c624615 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -2326,208 +2326,6 @@ Terminal.prototype.tabSet = function() { */ -/** - * CSI Ps L - * Insert Ps Line(s) (default = 1) (IL). - */ -Terminal.prototype.insertLines = function(params) { - var param, row, j; - - param = params[0]; - if (param < 1) param = 1; - row = this.y + this.ybase; - - j = this.rows - 1 - this.scrollBottom; - j = this.rows - 1 + this.ybase - j + 1; - - while (param--) { - if (this.lines.length === this.lines.maxLength) { - // Trim the start of lines to make room for the new line - this.lines.trimStart(1); - this.ybase--; - this.ydisp--; - row--; - j--; - } - // test: echo -e '\e[44m\e[1L\e[0m' - // blankLine(true) - xterm/linux behavior - this.lines.splice(row, 0, this.blankLine(true)); - this.lines.splice(j, 1); - } - - // this.maxRange(); - this.updateRange(this.y); - this.updateRange(this.scrollBottom); -}; - - -/** - * CSI Ps M - * Delete Ps Line(s) (default = 1) (DL). - */ -Terminal.prototype.deleteLines = function(params) { - var param, row, j; - - param = params[0]; - if (param < 1) param = 1; - row = this.y + this.ybase; - - j = this.rows - 1 - this.scrollBottom; - j = this.rows - 1 + this.ybase - j; - - while (param--) { - if (this.lines.length === this.lines.maxLength) { - // Trim the start of lines to make room for the new line - this.lines.trimStart(1); - this.ybase -= 1; - this.ydisp -= 1; - } - // test: echo -e '\e[44m\e[1M\e[0m' - // blankLine(true) - xterm/linux behavior - this.lines.splice(j + 1, 0, this.blankLine(true)); - this.lines.splice(row, 1); - } - - // this.maxRange(); - this.updateRange(this.y); - this.updateRange(this.scrollBottom); -}; - - -/** - * CSI Ps P - * Delete Ps Character(s) (default = 1) (DCH). - */ -Terminal.prototype.deleteChars = function(params) { - var param, row, ch; - - param = params[0]; - if (param < 1) param = 1; - - row = this.y + this.ybase; - ch = [this.eraseAttr(), ' ', 1]; // xterm - - while (param--) { - this.lines.get(row).splice(this.x, 1); - this.lines.get(row).push(ch); - } -}; - -/** - * CSI Ps X - * Erase Ps Character(s) (default = 1) (ECH). - */ -Terminal.prototype.eraseChars = function(params) { - var param, row, j, ch; - - param = params[0]; - if (param < 1) param = 1; - - row = this.y + this.ybase; - j = this.x; - ch = [this.eraseAttr(), ' ', 1]; // xterm - - while (param-- && j < this.cols) { - this.lines.get(row)[j++] = ch; - } -}; - -/** - * CSI Pm ` Character Position Absolute - * [column] (default = [row,1]) (HPA). - */ -Terminal.prototype.charPosAbsolute = function(params) { - var param = params[0]; - if (param < 1) param = 1; - this.x = param - 1; - if (this.x >= this.cols) { - this.x = this.cols - 1; - } -}; - - -/** - * 141 61 a * HPR - - * Horizontal Position Relative - * reuse CSI Ps C ? - */ -Terminal.prototype.HPositionRelative = function(params) { - var param = params[0]; - if (param < 1) param = 1; - this.x += param; - if (this.x >= this.cols) { - this.x = this.cols - 1; - } -}; - - -/** - * CSI Ps c Send Device Attributes (Primary DA). - * Ps = 0 or omitted -> request attributes from terminal. The - * response depends on the decTerminalID resource setting. - * -> CSI ? 1 ; 2 c (``VT100 with Advanced Video Option'') - * -> CSI ? 1 ; 0 c (``VT101 with No Options'') - * -> CSI ? 6 c (``VT102'') - * -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c (``VT220'') - * The VT100-style response parameters do not mean anything by - * themselves. VT220 parameters do, telling the host what fea- - * tures the terminal supports: - * Ps = 1 -> 132-columns. - * Ps = 2 -> Printer. - * Ps = 6 -> Selective erase. - * Ps = 8 -> User-defined keys. - * Ps = 9 -> National replacement character sets. - * Ps = 1 5 -> Technical characters. - * Ps = 2 2 -> ANSI color, e.g., VT525. - * Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode). - * CSI > Ps c - * Send Device Attributes (Secondary DA). - * Ps = 0 or omitted -> request the terminal's identification - * code. The response depends on the decTerminalID resource set- - * ting. It should apply only to VT220 and up, but xterm extends - * this to VT100. - * -> CSI > Pp ; Pv ; Pc c - * where Pp denotes the terminal type - * Pp = 0 -> ``VT100''. - * Pp = 1 -> ``VT220''. - * and Pv is the firmware version (for xterm, this was originally - * the XFree86 patch number, starting with 95). In a DEC termi- - * nal, Pc indicates the ROM cartridge registration number and is - * always zero. - * More information: - * xterm/charproc.c - line 2012, for more information. - * vim responds with ^[[?0c or ^[[?1c after the terminal's response (?) - */ -Terminal.prototype.sendDeviceAttributes = function(params) { - if (params[0] > 0) return; - - if (!this.prefix) { - if (this.is('xterm') - || this.is('rxvt-unicode') - || this.is('screen')) { - this.send(C0.ESC + '[?1;2c'); - } else if (this.is('linux')) { - this.send(C0.ESC + '[?6c'); - } - } else if (this.prefix === '>') { - // xterm and urxvt - // seem to spit this - // out around ~370 times (?). - if (this.is('xterm')) { - this.send(C0.ESC + '[>0;276;0c'); - } else if (this.is('rxvt-unicode')) { - this.send(C0.ESC + '[>85;95;0c'); - } else if (this.is('linux')) { - // not supported by linux console. - // linux console echoes parameters. - this.send(params[0] + 'c'); - } else if (this.is('screen')) { - this.send(C0.ESC + '[>83;40003;0c'); - } - } -}; - - /** * CSI Pm d * Line Position Absolute [row] (default = [1,column]) (VPA).