diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 38b85367..064bb177 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -47,4 +47,48 @@ export class InputHandler implements IInputHandler { public shiftIn(): void { this._terminal.setgLevel(0); } + + public cursorUp(params: number[]): void { + let param = params[0]; + if (param < 1) { + param = 1; + } + this._terminal.y -= param; + if (this._terminal.y < 0) { + this._terminal.y = 0; + } + } + + public cursorDown(params: number[]) { + let param = params[0]; + if (param < 1) { + param = 1; + } + this._terminal.y += param; + if (this._terminal.y >= this._terminal.rows) { + this._terminal.y = this._terminal.rows - 1; + } + } + + public cursorForward(params: number[]) { + 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; + } + } + + public cursorBackward(params: number[]) { + let param = params[0]; + if (param < 1) { + param = 1; + } + this._terminal.x -= param; + if (this._terminal.x < 0) { + this._terminal.x = 0; + } + } } diff --git a/src/Interfaces.ts b/src/Interfaces.ts index ae05c79f..8eedab41 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -44,4 +44,9 @@ export interface IInputHandler { tab(): void; shiftOut(): void; shiftIn(): void; + // TODO: Make IInputHandler parameter names more friendly? (ie. cursorUp(amount: number)) + cursorUp(params: number[]): void; + cursorDown(params: number[]); + cursorForward(params: number[]); + cursorBackward(params: number[]); } diff --git a/src/Parser.ts b/src/Parser.ts index 789688fc..6bf89c4d 100644 --- a/src/Parser.ts +++ b/src/Parser.ts @@ -14,25 +14,31 @@ normalStateHandler[C0.SO] = (handler) => handler.shiftOut(); normalStateHandler[C0.SI] = (handler) => handler.shiftIn(); // TODO: Add ESC and Default cases to normalStateHandler -const csiStateHandler: {[key: string]: (handler: IInputHandler, parser: Parser) => void} = {}; -csiStateHandler['?'] = (_, parser) => parser.setPrefix('?'); -csiStateHandler['>'] = (_, parser) => parser.setPrefix('>'); -csiStateHandler['!'] = (_, parser) => parser.setPrefix('!'); -csiStateHandler['0'] = (_, parser) => parser.setParam(parser.getParam() * 10); -csiStateHandler['1'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 1); -csiStateHandler['2'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 2); -csiStateHandler['3'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 3); -csiStateHandler['4'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 4); -csiStateHandler['5'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 5); -csiStateHandler['6'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 6); -csiStateHandler['7'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 7); -csiStateHandler['8'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 8); -csiStateHandler['9'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 9); -csiStateHandler['$'] = (_, parser) => parser.setPostfix('$'); -csiStateHandler['"'] = (_, parser) => parser.setPostfix('"'); -csiStateHandler[' '] = (_, parser) => parser.setPostfix(' '); -csiStateHandler['\''] = (_, parser) => parser.setPostfix('\''); -// TODO: Add remaining CSI cases +const csiParamStateHandler: {[key: string]: (handler: IInputHandler, parser: Parser) => void} = {}; +csiParamStateHandler['?'] = (_, parser) => parser.setPrefix('?'); +csiParamStateHandler['>'] = (_, parser) => parser.setPrefix('>'); +csiParamStateHandler['!'] = (_, parser) => parser.setPrefix('!'); +csiParamStateHandler['0'] = (_, parser) => parser.setParam(parser.getParam() * 10); +csiParamStateHandler['1'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 1); +csiParamStateHandler['2'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 2); +csiParamStateHandler['3'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 3); +csiParamStateHandler['4'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 4); +csiParamStateHandler['5'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 5); +csiParamStateHandler['6'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 6); +csiParamStateHandler['7'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 7); +csiParamStateHandler['8'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 8); +csiParamStateHandler['9'] = (_, parser) => parser.setParam(parser.getParam() * 10 + 9); +csiParamStateHandler['$'] = (_, parser) => parser.setPostfix('$'); +csiParamStateHandler['"'] = (_, parser) => parser.setPostfix('"'); +csiParamStateHandler[' '] = (_, parser) => parser.setPostfix(' '); +csiParamStateHandler['\''] = (_, parser) => parser.setPostfix('\''); +// TODO: Handle ';' and default (move on to ParserState.CSI (from CSI_PARAM) + +const csiStateHandler: {[key: string]: (handler: IInputHandler, params: number[]) => void} = {}; +csiStateHandler['A'] = (handler, params) => handler.cursorUp(params); +csiStateHandler['B'] = (handler, params) => handler.cursorDown(params); +csiStateHandler['C'] = (handler, params) => handler.cursorForward(params); +csiStateHandler['D'] = (handler, params) => handler.cursorBackward(params); enum ParserState { NORMAL = 0, @@ -508,12 +514,14 @@ export class Parser { break; case ParserState.CSI: - if (ch in csiStateHandler) { - csiStateHandler[ch](this._inputHandler, this); + if (ch in csiParamStateHandler) { + csiParamStateHandler[ch](this._inputHandler, this); // Skip below switch as this has handled these codes (eventually everything will be handled here break; } + // TODO: a new state should be introduced? to differentiate checking for params and the codes + this._terminal.params.push(this._terminal.currentParam); this._terminal.currentParam = 0; @@ -522,31 +530,13 @@ export class Parser { this.state = ParserState.NORMAL; + if (ch in csiStateHandler) { + csiStateHandler[ch](this._inputHandler, this._terminal.params); + // Skip below switch as this has handled these codes (eventually everything will be handled here + break; + } + switch (ch) { - // CSI Ps A - // Cursor Up Ps Times (default = 1) (CUU). - case 'A': - this._terminal.cursorUp(this._terminal.params); - break; - - // CSI Ps B - // Cursor Down Ps Times (default = 1) (CUD). - case 'B': - this._terminal.cursorDown(this._terminal.params); - break; - - // CSI Ps C - // Cursor Forward Ps Times (default = 1) (CUF). - case 'C': - this._terminal.cursorForward(this._terminal.params); - break; - - // CSI Ps D - // Cursor Backward Ps Times (default = 1) (CUB). - case 'D': - this._terminal.cursorBackward(this._terminal.params); - break; - // CSI Ps ; Ps H // Cursor Position [row;column] (default = [1,1]) (CUP). case 'H': diff --git a/src/xterm.js b/src/xterm.js index bf9f9853..c3ef9bd6 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -2222,57 +2222,6 @@ Terminal.prototype.tabSet = function() { * CSI */ -/** - * CSI Ps A - * Cursor Up Ps Times (default = 1) (CUU). - */ -Terminal.prototype.cursorUp = function(params) { - var param = params[0]; - if (param < 1) param = 1; - this.y -= param; - if (this.y < 0) this.y = 0; -}; - - -/** - * CSI Ps B - * Cursor Down Ps Times (default = 1) (CUD). - */ -Terminal.prototype.cursorDown = function(params) { - var param = params[0]; - if (param < 1) param = 1; - this.y += param; - if (this.y >= this.rows) { - this.y = this.rows - 1; - } -}; - - -/** - * CSI Ps C - * Cursor Forward Ps Times (default = 1) (CUF). - */ -Terminal.prototype.cursorForward = 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 D - * Cursor Backward Ps Times (default = 1) (CUB). - */ -Terminal.prototype.cursorBackward = function(params) { - var param = params[0]; - if (param < 1) param = 1; - this.x -= param; - if (this.x < 0) this.x = 0; -}; - /** * CSI Ps ; Ps H