From bbafdd3d06e5791f94ed17b771fb80375e8521a6 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 18 Jun 2017 20:00:22 +0300 Subject: [PATCH] Start isolating buffer attributes into Buffer class --- src/Buffer.ts | 25 +++- src/BufferSet.ts | 2 + src/InputHandler.ts | 269 +++++++++++++++++++--------------------- src/Interfaces.ts | 4 + src/Renderer.ts | 8 +- src/SelectionManager.ts | 6 +- src/Viewport.ts | 4 +- src/xterm.js | 146 +++++++++------------- 8 files changed, 222 insertions(+), 242 deletions(-) diff --git a/src/Buffer.ts b/src/Buffer.ts index ba147d8..32a406a 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -5,19 +5,32 @@ import { ITerminal } from './Interfaces'; import { CircularList } from './utils/CircularList'; +/** + * This class represents a terminal buffer (an internal state of the terminal)/ + */ export class Buffer { private _lines: CircularList; - private _ybase: number; - private _ydisp: number; - private _y: number; - private _x: number; private _tabs: any; - constructor(private terminal: ITerminal) { + /** + * Create a new Buffer. + * @param {Terminal} terminal - The terminal the buffer will belong to + * @param {number} ydisp - The scroll position of the buffer in the viewport + * @param {number} ybase - The scroll position of the y cursor (ybase + y = the y position within the buffer) + * @param {number} y - The cursor's y position after ybase + * @param {number} x - The cursor's x position after ybase + */ + constructor( + private terminal: ITerminal, + public ydisp: number = 0, + public ybase: number = 0, + public y: number = 0, + public x: number = 0, + ) { this._lines = new CircularList(this.terminal.scrollback); } - public get lines(): CircularList { + public get lines(): CircularList { return this._lines; } } diff --git a/src/BufferSet.ts b/src/BufferSet.ts index e115fe0..0429c52 100644 --- a/src/BufferSet.ts +++ b/src/BufferSet.ts @@ -38,11 +38,13 @@ export class BufferSet extends EventEmitter { public activateNormalBuffer(): void { this._activeBuffer = this._normal; + this.resetTerminal(); this.emit('activate', this._normal); } public activateAltBuffer(): void { this._activeBuffer = this._alt; + this.resetTerminal(); this.emit('activate', this._alt); } } diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 0e4c276..f629dc5 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -27,37 +27,36 @@ export class InputHandler implements IInputHandler { char = this._terminal.charset[char]; } - let row = this._terminal.y + this._terminal.ybase; + let row = this._terminal.buffer.y + this._terminal.buffer.ybase; // insert combining char in last cell // FIXME: needs handling after cursor jumps - if (!ch_width && this._terminal.x) { + if (!ch_width && this._terminal.buffer.x) { // dont overflow left - if (this._terminal.buffer.lines.get(row)[this._terminal.x - 1]) { - if (!this._terminal.buffer.lines.get(row)[this._terminal.x - 1][2]) { + if (this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1]) { + if (!this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1][2]) { // found empty cell after fullwidth, need to go 2 cells back - if (this._terminal.buffer.lines.get(row)[this._terminal.x - 2]) - this._terminal.buffer.lines.get(row)[this._terminal.x - 2][1] += char; + if (this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2]) + this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 2][1] += char; } else { - this._terminal.buffer.lines.get(row)[this._terminal.x - 1][1] += char; + this._terminal.buffer.lines.get(row)[this._terminal.buffer.x - 1][1] += char; } - this._terminal.updateRange(this._terminal.y); + this._terminal.updateRange(this._terminal.buffer.y); } return; } // goto next line if ch would overflow // TODO: needs a global min terminal width of 2 - if (this._terminal.x + ch_width - 1 >= this._terminal.cols) { + if (this._terminal.buffer.x + ch_width - 1 >= this._terminal.cols) { // autowrap - DECAWM if (this._terminal.wraparoundMode) { - this._terminal.x = 0; - this._terminal.y++; - if (this._terminal.y > this._terminal.scrollBottom) { - // Insert a new line, scroll and mark as a wrapped line - this._terminal.y--; + this._terminal.buffer.x = 0; + this._terminal.buffer.y++; + if (this._terminal.buffer.y > this._terminal.scrollBottom) { + this._terminal.buffer.y--; this._terminal.scroll(true); } else { // The line already exists (eg. the initial viewport), mark it as a @@ -69,7 +68,7 @@ export class InputHandler implements IInputHandler { return; } } - row = this._terminal.y + this._terminal.ybase; + row = this._terminal.buffer.y + this._terminal.buffer.ybase; // insert mode: move characters to right if (this._terminal.insertMode) { @@ -77,7 +76,7 @@ export class InputHandler implements IInputHandler { for (let moves = 0; moves < ch_width; ++moves) { // remove last cell, if it's width is 0 // we have to adjust the second last cell as well - const removed = this._terminal.buffer.lines.get(this._terminal.y + this._terminal.ybase).pop(); + const removed = this._terminal.buffer.lines.get(this._terminal.buffer.y + this._terminal.buffer.ybase).pop(); if (removed[2] === 0 && this._terminal.buffer.lines.get(row)[this._terminal.cols - 2] && this._terminal.buffer.lines.get(row)[this._terminal.cols - 2][2] === 2) { @@ -85,18 +84,18 @@ export class InputHandler implements IInputHandler { } // insert empty cell at cursor - this._terminal.buffer.lines.get(row).splice(this._terminal.x, 0, [this._terminal.curAttr, ' ', 1]); + this._terminal.buffer.lines.get(row).splice(this._terminal.buffer.x, 0, [this._terminal.curAttr, ' ', 1]); } } - this._terminal.buffer.lines.get(row)[this._terminal.x] = [this._terminal.curAttr, char, ch_width]; - this._terminal.x++; - this._terminal.updateRange(this._terminal.y); + this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, char, ch_width]; + this._terminal.buffer.x++; + this._terminal.updateRange(this._terminal.buffer.y); // fullwidth char - set next cell width to zero and advance cursor if (ch_width === 2) { - this._terminal.buffer.lines.get(row)[this._terminal.x] = [this._terminal.curAttr, '', 0]; - this._terminal.x++; + this._terminal.buffer.lines.get(row)[this._terminal.buffer.x] = [this._terminal.curAttr, '', 0]; + this._terminal.buffer.x++; } } } @@ -122,16 +121,16 @@ export class InputHandler implements IInputHandler { */ public lineFeed(): void { if (this._terminal.convertEol) { - this._terminal.x = 0; + this._terminal.buffer.x = 0; } - this._terminal.y++; - if (this._terminal.y > this._terminal.scrollBottom) { - this._terminal.y--; + this._terminal.buffer.y++; + if (this._terminal.buffer.y > this._terminal.scrollBottom) { + this._terminal.buffer.y--; this._terminal.scroll(); } // If the end of the line is hit, prevent this action from wrapping around to the next line. - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x--; + if (this._terminal.buffer.x >= this._terminal.cols) { + this._terminal.buffer.x--; } } @@ -140,7 +139,7 @@ export class InputHandler implements IInputHandler { * Carriage Return (Ctrl-M). */ public carriageReturn(): void { - this._terminal.x = 0; + this._terminal.buffer.x = 0; } /** @@ -148,8 +147,8 @@ export class InputHandler implements IInputHandler { * Backspace (Ctrl-H). */ public backspace(): void { - if (this._terminal.x > 0) { - this._terminal.x--; + if (this._terminal.buffer.x > 0) { + this._terminal.buffer.x--; } } @@ -158,7 +157,7 @@ export class InputHandler implements IInputHandler { * Horizontal Tab (HT) (Ctrl-I). */ public tab(): void { - this._terminal.x = this._terminal.nextStop(); + this._terminal.buffer.x = this._terminal.nextStop(); } /** @@ -189,8 +188,8 @@ export class InputHandler implements IInputHandler { param = params[0]; if (param < 1) param = 1; - row = this._terminal.y + this._terminal.ybase; - j = this._terminal.x; + row = this._terminal.buffer.y + this._terminal.buffer.ybase; + j = this._terminal.buffer.x; ch = [this._terminal.eraseAttr(), ' ', 1]; // xterm while (param-- && j < this._terminal.cols) { @@ -208,9 +207,9 @@ export class InputHandler implements IInputHandler { if (param < 1) { param = 1; } - this._terminal.y -= param; - if (this._terminal.y < 0) { - this._terminal.y = 0; + this._terminal.buffer.y -= param; + if (this._terminal.buffer.y < 0) { + this._terminal.buffer.y = 0; } } @@ -223,13 +222,13 @@ export class InputHandler implements IInputHandler { if (param < 1) { param = 1; } - this._terminal.y += param; - if (this._terminal.y >= this._terminal.rows) { - this._terminal.y = this._terminal.rows - 1; + this._terminal.buffer.y += param; + if (this._terminal.buffer.y >= this._terminal.rows) { + this._terminal.buffer.y = this._terminal.rows - 1; } // If the end of the line is hit, prevent this action from wrapping around to the next line. - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x--; + if (this._terminal.buffer.x >= this._terminal.cols) { + this._terminal.buffer.x--; } } @@ -242,9 +241,9 @@ export class InputHandler implements IInputHandler { if (param < 1) { param = 1; } - this._terminal.x += param; - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x = this._terminal.cols - 1; + this._terminal.buffer.x += param; + if (this._terminal.buffer.x >= this._terminal.cols) { + this._terminal.buffer.x = this._terminal.cols - 1; } } @@ -258,12 +257,12 @@ export class InputHandler implements IInputHandler { param = 1; } // If the end of the line is hit, prevent this action from wrapping around to the next line. - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x--; + if (this._terminal.buffer.x >= this._terminal.cols) { + this._terminal.buffer.x--; } - this._terminal.x -= param; - if (this._terminal.x < 0) { - this._terminal.x = 0; + this._terminal.buffer.x -= param; + if (this._terminal.buffer.x < 0) { + this._terminal.buffer.x = 0; } } @@ -277,11 +276,11 @@ export class InputHandler implements IInputHandler { if (param < 1) { param = 1; } - this._terminal.y += param; - if (this._terminal.y >= this._terminal.rows) { - this._terminal.y = this._terminal.rows - 1; + this._terminal.buffer.y += param; + if (this._terminal.buffer.y >= this._terminal.rows) { + this._terminal.buffer.y = this._terminal.rows - 1; } - this._terminal.x = 0; + this._terminal.buffer.x = 0; }; @@ -295,11 +294,11 @@ export class InputHandler implements IInputHandler { if (param < 1) { param = 1; } - this._terminal.y -= param; - if (this._terminal.y < 0) { - this._terminal.y = 0; + this._terminal.buffer.y -= param; + if (this._terminal.buffer.y < 0) { + this._terminal.buffer.y = 0; } - this._terminal.x = 0; + this._terminal.buffer.x = 0; }; @@ -312,7 +311,7 @@ export class InputHandler implements IInputHandler { if (param < 1) { param = 1; } - this._terminal.x = param - 1; + this._terminal.buffer.x = param - 1; } /** @@ -342,8 +341,8 @@ export class InputHandler implements IInputHandler { col = this._terminal.cols - 1; } - this._terminal.x = col; - this._terminal.y = row; + this._terminal.buffer.x = col; + this._terminal.buffer.y = row; } /** @@ -353,7 +352,7 @@ export class InputHandler implements IInputHandler { public cursorForwardTab(params: number[]): void { let param = params[0] || 1; while (param--) { - this._terminal.x = this._terminal.nextStop(); + this._terminal.buffer.x = this._terminal.nextStop(); } } @@ -373,15 +372,15 @@ export class InputHandler implements IInputHandler { let j; switch (params[0]) { case 0: - this._terminal.eraseRight(this._terminal.x, this._terminal.y); - j = this._terminal.y + 1; + this._terminal.eraseRight(this._terminal.buffer.x, this._terminal.buffer.y); + j = this._terminal.buffer.y + 1; for (; j < this._terminal.rows; j++) { this._terminal.eraseLine(j); } break; case 1: - this._terminal.eraseLeft(this._terminal.x, this._terminal.y); - j = this._terminal.y; + this._terminal.eraseLeft(this._terminal.buffer.x, this._terminal.buffer.y); + j = this._terminal.buffer.y; while (j--) { this._terminal.eraseLine(j); } @@ -395,8 +394,8 @@ export class InputHandler implements IInputHandler { const scrollBackSize = this._terminal.buffer.lines.length - this._terminal.rows; if (scrollBackSize > 0) { this._terminal.buffer.lines.trimStart(scrollBackSize); - this._terminal.ybase = Math.max(this._terminal.ybase - scrollBackSize, 0); - this._terminal.ydisp = Math.max(this._terminal.ydisp - scrollBackSize, 0); + this._terminal.buffer.ybase = Math.max(this._terminal.buffer.ybase - scrollBackSize, 0); + this._terminal.buffer.ydisp = Math.max(this._terminal.buffer.ydisp - scrollBackSize, 0); // Force a scroll event to refresh viewport this._terminal.emit('scroll', 0); } @@ -418,13 +417,13 @@ export class InputHandler implements IInputHandler { public eraseInLine(params: number[]): void { switch (params[0]) { case 0: - this._terminal.eraseRight(this._terminal.x, this._terminal.y); + this._terminal.eraseRight(this._terminal.buffer.x, this._terminal.buffer.y); break; case 1: - this._terminal.eraseLeft(this._terminal.x, this._terminal.y); + this._terminal.eraseLeft(this._terminal.buffer.x, this._terminal.buffer.y); break; case 2: - this._terminal.eraseLine(this._terminal.y); + this._terminal.eraseLine(this._terminal.buffer.y); break; } } @@ -440,17 +439,17 @@ export class InputHandler implements IInputHandler { if (param < 1) { param = 1; } - row = this._terminal.y + this._terminal.ybase; + row = this._terminal.buffer.y + this._terminal.buffer.ybase; j = this._terminal.rows - 1 - this._terminal.scrollBottom; - j = this._terminal.rows - 1 + this._terminal.ybase - j + 1; + j = this._terminal.rows - 1 + this._terminal.buffer.ybase - j + 1; while (param--) { if (this._terminal.buffer.lines.length === this._terminal.buffer.lines.maxLength) { // Trim the start of lines to make room for the new line this._terminal.buffer.lines.trimStart(1); - this._terminal.ybase--; - this._terminal.ydisp--; + this._terminal.buffer.ybase--; + this._terminal.buffer.ydisp--; row--; j--; } @@ -461,7 +460,7 @@ export class InputHandler implements IInputHandler { } // this.maxRange(); - this._terminal.updateRange(this._terminal.y); + this._terminal.updateRange(this._terminal.buffer.y); this._terminal.updateRange(this._terminal.scrollBottom); } @@ -476,17 +475,17 @@ export class InputHandler implements IInputHandler { if (param < 1) { param = 1; } - row = this._terminal.y + this._terminal.ybase; + row = this._terminal.buffer.y + this._terminal.buffer.ybase; j = this._terminal.rows - 1 - this._terminal.scrollBottom; - j = this._terminal.rows - 1 + this._terminal.ybase - j; + j = this._terminal.rows - 1 + this._terminal.buffer.ybase - j; while (param--) { if (this._terminal.buffer.lines.length === this._terminal.buffer.lines.maxLength) { // Trim the start of lines to make room for the new line this._terminal.buffer.lines.trimStart(1); - this._terminal.ybase -= 1; - this._terminal.ydisp -= 1; + this._terminal.buffer.ybase -= 1; + this._terminal.buffer.ydisp -= 1; } // test: echo -e '\e[44m\e[1M\e[0m' // blankLine(true) - xterm/linux behavior @@ -495,7 +494,7 @@ export class InputHandler implements IInputHandler { } // this.maxRange(); - this._terminal.updateRange(this._terminal.y); + this._terminal.updateRange(this._terminal.buffer.y); this._terminal.updateRange(this._terminal.scrollBottom); } @@ -511,11 +510,11 @@ export class InputHandler implements IInputHandler { param = 1; } - row = this._terminal.y + this._terminal.ybase; + row = this._terminal.buffer.y + this._terminal.buffer.ybase; ch = [this._terminal.eraseAttr(), ' ', 1]; // xterm while (param--) { - this._terminal.buffer.lines.get(row).splice(this._terminal.x, 1); + this._terminal.buffer.lines.get(row).splice(this._terminal.buffer.x, 1); this._terminal.buffer.lines.get(row).push(ch); } } @@ -526,8 +525,8 @@ export class InputHandler implements IInputHandler { public scrollUp(params: number[]): void { let param = params[0] || 1; while (param--) { - this._terminal.buffer.lines.splice(this._terminal.ybase + this._terminal.scrollTop, 1); - this._terminal.buffer.lines.splice(this._terminal.ybase + this._terminal.scrollBottom, 0, this._terminal.blankLine()); + this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.scrollTop, 1); + this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.scrollBottom, 0, this._terminal.blankLine()); } // this.maxRange(); this._terminal.updateRange(this._terminal.scrollTop); @@ -540,8 +539,8 @@ export class InputHandler implements IInputHandler { public scrollDown(params: number[]): void { let param = params[0] || 1; while (param--) { - this._terminal.buffer.lines.splice(this._terminal.ybase + this._terminal.scrollBottom, 1); - this._terminal.buffer.lines.splice(this._terminal.ybase + this._terminal.scrollTop, 0, this._terminal.blankLine()); + this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.scrollBottom, 1); + this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.scrollTop, 0, this._terminal.blankLine()); } // this.maxRange(); this._terminal.updateRange(this._terminal.scrollTop); @@ -560,8 +559,8 @@ export class InputHandler implements IInputHandler { param = 1; } - row = this._terminal.y + this._terminal.ybase; - j = this._terminal.x; + row = this._terminal.buffer.y + this._terminal.buffer.ybase; + j = this._terminal.buffer.x; ch = [this._terminal.eraseAttr(), ' ', 1]; // xterm while (param-- && j < this._terminal.cols) { @@ -575,7 +574,7 @@ export class InputHandler implements IInputHandler { public cursorBackwardTab(params: number[]): void { let param = params[0] || 1; while (param--) { - this._terminal.x = this._terminal.prevStop(); + this._terminal.buffer.x = this._terminal.prevStop(); } } @@ -588,9 +587,9 @@ export class InputHandler implements IInputHandler { if (param < 1) { param = 1; } - this._terminal.x = param - 1; - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x = this._terminal.cols - 1; + this._terminal.buffer.x = param - 1; + if (this._terminal.buffer.x >= this._terminal.cols) { + this._terminal.buffer.x = this._terminal.cols - 1; } } @@ -604,9 +603,9 @@ export class InputHandler implements IInputHandler { if (param < 1) { param = 1; } - this._terminal.x += param; - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x = this._terminal.cols - 1; + this._terminal.buffer.x += param; + if (this._terminal.buffer.x >= this._terminal.cols) { + this._terminal.buffer.x = this._terminal.cols - 1; } } @@ -615,11 +614,11 @@ export class InputHandler implements IInputHandler { */ public repeatPrecedingCharacter(params: number[]): void { let param = params[0] || 1 - , line = this._terminal.buffer.lines.get(this._terminal.ybase + this._terminal.y) - , ch = line[this._terminal.x - 1] || [this._terminal.defAttr, ' ', 1]; + , line = this._terminal.buffer.lines.get(this._terminal.buffer.ybase + this._terminal.buffer.y) + , ch = line[this._terminal.buffer.x - 1] || [this._terminal.defAttr, ' ', 1]; while (param--) { - line[this._terminal.x++] = ch; + line[this._terminal.buffer.x++] = ch; } } @@ -698,9 +697,9 @@ export class InputHandler implements IInputHandler { if (param < 1) { param = 1; } - this._terminal.y = param - 1; - if (this._terminal.y >= this._terminal.rows) { - this._terminal.y = this._terminal.rows - 1; + this._terminal.buffer.y = param - 1; + if (this._terminal.buffer.y >= this._terminal.rows) { + this._terminal.buffer.y = this._terminal.rows - 1; } } @@ -714,13 +713,13 @@ export class InputHandler implements IInputHandler { if (param < 1) { param = 1; } - this._terminal.y += param; - if (this._terminal.y >= this._terminal.rows) { - this._terminal.y = this._terminal.rows - 1; + this._terminal.buffer.y += param; + if (this._terminal.buffer.y >= this._terminal.rows) { + this._terminal.buffer.y = this._terminal.rows - 1; } // If the end of the line is hit, prevent this action from wrapping around to the next line. - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x--; + if (this._terminal.buffer.x >= this._terminal.cols) { + this._terminal.buffer.x--; } } @@ -733,14 +732,14 @@ export class InputHandler implements IInputHandler { if (params[0] < 1) params[0] = 1; if (params[1] < 1) params[1] = 1; - this._terminal.y = params[0] - 1; - if (this._terminal.y >= this._terminal.rows) { - this._terminal.y = this._terminal.rows - 1; + this._terminal.buffer.y = params[0] - 1; + if (this._terminal.buffer.y >= this._terminal.rows) { + this._terminal.buffer.y = this._terminal.rows - 1; } - this._terminal.x = params[1] - 1; - if (this._terminal.x >= this._terminal.cols) { - this._terminal.x = this._terminal.cols - 1; + this._terminal.buffer.x = params[1] - 1; + if (this._terminal.buffer.x >= this._terminal.cols) { + this._terminal.buffer.x = this._terminal.cols - 1; } } @@ -755,7 +754,7 @@ export class InputHandler implements IInputHandler { public tabClear(params: number[]): void { let param = params[0]; if (param <= 0) { - delete this._terminal.tabs[this._terminal.x]; + delete this._terminal.tabs[this._terminal.buffer.x]; } else if (param === 3) { this._terminal.tabs = {}; } @@ -907,7 +906,7 @@ export class InputHandler implements IInputHandler { // TODO: Why are params[0] compares nested within a switch for params[0]? - this._terminal.x10Mouse = params[0] === 9; + this._terminal.buffer.x10Mouse = params[0] === 9; this._terminal.vt200Mouse = params[0] === 1000; this._terminal.normalMouse = params[0] > 1000; this._terminal.mouseEvents = true; @@ -949,11 +948,6 @@ export class InputHandler implements IInputHandler { case 1047: // alt screen buffer if (!this._terminal.normal) { let normal = { - lines: this._terminal.buffers.normal.lines, - ybase: this._terminal.ybase, - ydisp: this._terminal.ydisp, - x: this._terminal.x, - y: this._terminal.y, scrollTop: this._terminal.scrollTop, scrollBottom: this._terminal.scrollBottom, tabs: this._terminal.tabs @@ -962,10 +956,7 @@ export class InputHandler implements IInputHandler { // glevel: this._terminal.glevel, // charsets: this._terminal.charsets }; - this._terminal.reset(); - this._terminal.viewport.syncScrollArea(); - this._terminal.normal = normal; - this._terminal.showCursor(); + this._terminal.buffers.activateAltBuffer(); } break; } @@ -1101,7 +1092,7 @@ export class InputHandler implements IInputHandler { case 1000: // vt200 mouse case 1002: // button event mouse case 1003: // any event mouse - this._terminal.x10Mouse = false; + this._terminal.buffer.x10Mouse = false; this._terminal.vt200Mouse = false; this._terminal.normalMouse = false; this._terminal.mouseEvents = false; @@ -1128,11 +1119,6 @@ export class InputHandler implements IInputHandler { case 47: // normal screen buffer case 1047: // normal screen buffer - clearing it first if (this._terminal.normal) { - this._terminal.buffers.activateNormalBuffer(); - this._terminal.ybase = this._terminal.normal.ybase; - this._terminal.ydisp = this._terminal.normal.ydisp; - this._terminal.x = this._terminal.normal.x; - this._terminal.y = this._terminal.normal.y; this._terminal.scrollTop = this._terminal.normal.scrollTop; this._terminal.scrollBottom = this._terminal.normal.scrollBottom; this._terminal.tabs = this._terminal.normal.tabs; @@ -1143,6 +1129,7 @@ export class InputHandler implements IInputHandler { // this.x = this.savedX; // this.y = this.savedY; // } + this._terminal.buffers.activateNormalBuffer(); this._terminal.refresh(0, this._terminal.rows - 1); this._terminal.viewport.syncScrollArea(); this._terminal.showCursor(); @@ -1366,9 +1353,9 @@ export class InputHandler implements IInputHandler { case 6: // cursor position this._terminal.send(C0.ESC + '[' - + (this._terminal.y + 1) + + (this._terminal.buffer.y + 1) + ';' - + (this._terminal.x + 1) + + (this._terminal.buffer.x + 1) + 'R'); break; } @@ -1379,9 +1366,9 @@ export class InputHandler implements IInputHandler { case 6: // cursor position this._terminal.send(C0.ESC + '[?' - + (this._terminal.y + 1) + + (this._terminal.buffer.y + 1) + ';' - + (this._terminal.x + 1) + + (this._terminal.buffer.x + 1) + 'R'); break; case 15: @@ -1419,7 +1406,7 @@ export class InputHandler implements IInputHandler { this._terminal.scrollTop = 0; this._terminal.scrollBottom = this._terminal.rows - 1; this._terminal.curAttr = this._terminal.defAttr; - this._terminal.x = this._terminal.y = 0; // ? + this._terminal.buffer.x = this._terminal.buffer.y = 0; // ? this._terminal.charset = null; this._terminal.glevel = 0; // ?? this._terminal.charsets = [null]; // ?? @@ -1465,8 +1452,8 @@ export class InputHandler implements IInputHandler { if (this._terminal.prefix) return; this._terminal.scrollTop = (params[0] || 1) - 1; this._terminal.scrollBottom = (params[1] && params[1] <= this._terminal.rows ? params[1] : this._terminal.rows) - 1; - this._terminal.x = 0; - this._terminal.y = 0; + this._terminal.buffer.x = 0; + this._terminal.buffer.y = 0; } @@ -1475,8 +1462,8 @@ export class InputHandler implements IInputHandler { * Save cursor (ANSI.SYS). */ public saveCursor(params: number[]): void { - this._terminal.savedX = this._terminal.x; - this._terminal.savedY = this._terminal.y; + this._terminal.savedX = this._terminal.buffer.x; + this._terminal.savedY = this._terminal.buffer.y; } @@ -1485,8 +1472,8 @@ export class InputHandler implements IInputHandler { * Restore cursor (ANSI.SYS). */ public restoreCursor(params: number[]): void { - this._terminal.x = this._terminal.savedX || 0; - this._terminal.y = this._terminal.savedY || 0; + this._terminal.buffer.x = this._terminal.savedX || 0; + this._terminal.buffer.y = this._terminal.savedY || 0; } } diff --git a/src/Interfaces.ts b/src/Interfaces.ts index 039e8a3..779f279 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -38,6 +38,8 @@ export interface ITerminal { y: number; defAttr: number; scrollback: number; + buffer: any; // This should be a `Buffer` class, but it would result in circular dependency + viewport: any; // This should be a `Viewport` class, but it would result in circular dependency /** * Emit the 'data' event and populate the given data. @@ -49,6 +51,8 @@ export interface ITerminal { cancel(ev: Event, force?: boolean); log(text: string): void; emit(event: string, data: any); + reset(): void; + showCursor(): void; } export interface ISelectionManager { diff --git a/src/Renderer.ts b/src/Renderer.ts index 3d4d918..236b70d 100644 --- a/src/Renderer.ts +++ b/src/Renderer.ts @@ -139,12 +139,12 @@ export class Renderer { } for (; y <= end; y++) { - let row = y + this._terminal.ydisp; + let row = y + this._terminal.buffer.ydisp; let line = this._terminal.buffer.lines.get(row); let x; - if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp) && + if (this._terminal.y === y - (this._terminal.buffer.ybase - this._terminal.buffer.ydisp) && this._terminal.cursorState && !this._terminal.cursorHidden) { x = this._terminal.x; @@ -337,8 +337,8 @@ export class Renderer { } // Translate from buffer position to viewport position - const viewportStartRow = start[1] - this._terminal.ydisp; - const viewportEndRow = end[1] - this._terminal.ydisp; + const viewportStartRow = start[1] - this._terminal.buffer.ydisp; + const viewportEndRow = end[1] - this._terminal.buffer.ydisp; const viewportCappedStartRow = Math.max(viewportStartRow, 0); const viewportCappedEndRow = Math.min(viewportEndRow, this._terminal.rows - 1); diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index 31ee8c2..58b37b9 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -281,7 +281,7 @@ export class SelectionManager extends EventEmitter { coords[0]--; coords[1]--; // Convert viewport coords to buffer coords - coords[1] += this._terminal.ydisp; + coords[1] += this._terminal.buffer.ydisp; return coords; } @@ -476,9 +476,9 @@ export class SelectionManager extends EventEmitter { this._terminal.scrollDisp(this._dragScrollAmount, false); // Re-evaluate selection if (this._dragScrollAmount > 0) { - this._model.selectionEnd = [this._terminal.cols - 1, this._terminal.ydisp + this._terminal.rows]; + this._model.selectionEnd = [this._terminal.cols - 1, this._terminal.buffer.ydisp + this._terminal.rows]; } else { - this._model.selectionEnd = [0, this._terminal.ydisp]; + this._model.selectionEnd = [0, this._terminal.buffer.ydisp]; } this.refresh(); } diff --git a/src/Viewport.ts b/src/Viewport.ts index a92836f..81ecca1 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -83,7 +83,7 @@ export class Viewport { } // Sync scrollTop - const scrollTop = this.terminal.ydisp * this.currentRowHeight; + const scrollTop = this.terminal.buffer.ydisp * this.currentRowHeight; if (this.viewportElement.scrollTop !== scrollTop) { this.viewportElement.scrollTop = scrollTop; } @@ -96,7 +96,7 @@ export class Viewport { */ private onScroll(ev: Event) { const newRow = Math.round(this.viewportElement.scrollTop / this.currentRowHeight); - const diff = newRow - this.terminal.ydisp; + const diff = newRow - this.terminal.buffer.ydisp; this.terminal.scrollDisp(diff, true); } diff --git a/src/xterm.js b/src/xterm.js index 30d7148..55c095d 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -142,27 +142,6 @@ function Terminal(options) { this.on('data', options.handler); } - /** - * The scroll position of the y cursor, ie. ybase + y = the y position within the entire - * buffer - */ - this.ybase = 0; - - /** - * The scroll position of the viewport - */ - this.ydisp = 0; - - /** - * The cursor's x position after ybase - */ - this.x = 0; - - /** - * The cursor's y position after ybase - */ - this.y = 0; - this.cursorState = 0; this.cursorHidden = false; this.convertEol; @@ -440,10 +419,10 @@ Terminal.prototype.setOption = function(key, value) { if (this.options[key] !== value) { if (this.buffer.length > value) { const amountToTrim = this.buffer.lines.length - value; - const needsRefresh = (this.ydisp - amountToTrim < 0); + const needsRefresh = (this.buffer.ydisp - amountToTrim < 0); this.buffer.lines.trimStart(amountToTrim); - this.ybase = Math.max(this.ybase - amountToTrim, 0); - this.ydisp = Math.max(this.ydisp - amountToTrim, 0); + this.buffer.ybase = Math.max(this.buffer.ybase - amountToTrim, 0); + this.buffer.ydisp = Math.max(this.buffer.ydisp - amountToTrim, 0); if (needsRefresh) { this.refresh(0, this.rows - 1); } @@ -733,8 +712,7 @@ Terminal.prototype.open = function(parent, focus) { this.viewport = new Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasure); this.renderer = new Renderer(this); -<<<<<<< HEAD - this.selectionManager = new SelectionManager(this, this.lines, this.rowContainer, this.charMeasure); + this.selectionManager = new SelectionManager(this, this.buffer.lines, this.rowContainer, this.charMeasure); this.selectionManager.on('refresh', data => { this.renderer.refreshSelection(data.start, data.end); }); @@ -746,10 +724,6 @@ Terminal.prototype.open = function(parent, focus) { this.textarea.focus(); this.textarea.select(); }); -======= - this.selectionManager = new SelectionManager(this, this.buffer.lines, this.rowContainer, this.charMeasure); - this.selectionManager.on('refresh', data => this.renderer.refreshSelection(data.start, data.end)); ->>>>>>> Create `terminal.buffer` convenience attribute this.on('scroll', () => this.selectionManager.refresh()); this.viewportElement.addEventListener('scroll', () => this.selectionManager.refresh()); @@ -1169,7 +1143,7 @@ Terminal.prototype.queueLinkification = function(start, end) { Terminal.prototype.showCursor = function() { if (!this.cursorState) { this.cursorState = 1; - this.refresh(this.y, this.y); + this.refresh(this.buffer.y, this.buffer.y); } }; @@ -1184,21 +1158,21 @@ Terminal.prototype.scroll = function(isWrapped) { // Make room for the new row in lines if (this.buffer.lines.length === this.buffer.lines.maxLength) { this.buffer.lines.trimStart(1); - this.ybase--; - if (this.ydisp !== 0) { - this.ydisp--; + this.buffer.ybase--; + if (this.buffer.ydisp !== 0) { + this.buffer.ydisp--; } } - this.ybase++; + this.buffer.ybase++; // TODO: Why is this done twice? if (!this.userScrolling) { - this.ydisp = this.ybase; + this.buffer.ydisp = this.buffer.ybase; } // last line - row = this.ybase + this.rows - 1; + row = this.buffer.ybase + this.rows - 1; // subtract the bottom scroll region row -= this.rows - 1 - this.scrollBottom; @@ -1212,13 +1186,13 @@ Terminal.prototype.scroll = function(isWrapped) { } if (this.scrollTop !== 0) { - if (this.ybase !== 0) { - this.ybase--; + if (this.buffer.ybase !== 0) { + this.buffer.ybase--; if (!this.userScrolling) { - this.ydisp = this.ybase; + this.buffer.ydisp = this.buffer.ybase; } } - this.buffer.lines.splice(this.ybase + this.scrollTop, 1); + this.buffer.lines.splice(this.buffer.ybase + this.scrollTop, 1); } // this.maxRange(); @@ -1231,7 +1205,7 @@ Terminal.prototype.scroll = function(isWrapped) { * * @event scroll */ - this.emit('scroll', this.ydisp); + this.emit('scroll', this.buffer.ydisp); }; /** @@ -1243,24 +1217,24 @@ Terminal.prototype.scroll = function(isWrapped) { */ Terminal.prototype.scrollDisp = function(disp, suppressScrollEvent) { if (disp < 0) { - if (this.ydisp === 0) { + if (this.buffer.ydisp === 0) { return; } this.userScrolling = true; - } else if (disp + this.ydisp >= this.ybase) { + } else if (disp + this.buffer.ydisp >= this.buffer.ybase) { this.userScrolling = false; } - const oldYdisp = this.ydisp; - this.ydisp = Math.max(Math.min(this.ydisp + disp, this.ybase), 0); + const oldYdisp = this.buffer.ydisp; + this.buffer.ydisp = Math.max(Math.min(this.buffer.ydisp + disp, this.buffer.ybase), 0); // No change occurred, don't trigger scroll/refresh - if (oldYdisp === this.ydisp) { + if (oldYdisp === this.buffer.ydisp) { return; } if (!suppressScrollEvent) { - this.emit('scroll', this.ydisp); + this.emit('scroll', this.buffer.ydisp); } this.refresh(0, this.rows - 1); @@ -1278,14 +1252,14 @@ Terminal.prototype.scrollPages = function(pageCount) { * Scrolls the display of the terminal to the top. */ Terminal.prototype.scrollToTop = function() { - this.scrollDisp(-this.ydisp); + this.scrollDisp(-this.buffer.ydisp); }; /** * Scrolls the display of the terminal to the bottom. */ Terminal.prototype.scrollToBottom = function() { - this.scrollDisp(this.ybase - this.ydisp); + this.scrollDisp(this.buffer.ybase - this.buffer.ydisp); }; /** @@ -1329,8 +1303,8 @@ Terminal.prototype.innerWrite = function() { this.xoffSentToCatchUp = false; } - this.refreshStart = this.y; - this.refreshEnd = this.y; + this.refreshStart = this.buffer.y; + this.refreshEnd = this.buffer.y; // HACK: Set the parser state based on it's state at the time of return. // This works around the bug #662 which saw the parser state reset in the @@ -1340,7 +1314,7 @@ Terminal.prototype.innerWrite = function() { var state = this.parser.parse(data); this.parser.setState(state); - this.updateRange(this.y); + this.updateRange(this.buffer.y); this.refresh(this.refreshStart, this.refreshEnd); } if (this.writeBuffer.length > 0) { @@ -1493,7 +1467,7 @@ Terminal.prototype.keyDown = function(ev) { this.restartCursorBlinking(); if (!this.compositionHelper.keydown.bind(this.compositionHelper)(ev)) { - if (this.ybase !== this.ydisp) { + if (this.buffer.ybase !== this.buffer.ydisp) { this.scrollToBottom(); } return false; @@ -1988,16 +1962,16 @@ Terminal.prototype.resize = function(x, y) { if (j < y) { el = this.element; while (j++ < y) { - // y is rows, not this.y - if (this.buffer.lines.length < y + this.ybase) { - if (this.ybase > 0 && this.buffer.lines.length <= this.ybase + this.y + addToY + 1) { + // y is rows, not this.buffer.y + if (this.buffer.lines.length < y + this.buffer.ybase) { + if (this.buffer.ybase > 0 && this.buffer.lines.length <= this.buffer.ybase + this.buffer.y + addToY + 1) { // There is room above the buffer and there are no empty elements below the line, // scroll up - this.ybase--; + this.buffer.ybase--; addToY++; - if (this.ydisp > 0) { + if (this.buffer.ydisp > 0) { // Viewport is at the top of the buffer, must increase downwards - this.ydisp--; + this.buffer.ydisp--; } } else { // Add a blank line if there is no buffer left at the top to scroll to, or if there @@ -2011,14 +1985,14 @@ Terminal.prototype.resize = function(x, y) { } } else { // (j > y) while (j-- > y) { - if (this.buffer.lines.length > y + this.ybase) { - if (this.buffer.lines.length > this.ybase + this.y + 1) { + if (this.buffer.lines.length > y + this.buffer.ybase) { + if (this.buffer.lines.length > this.buffer.ybase + this.buffer.y + 1) { // The line is a blank line below the cursor, remove it this.buffer.lines.pop(); } else { // The line is the cursor, scroll down - this.ybase++; - this.ydisp++; + this.buffer.ybase++; + this.buffer.ydisp++; } } if (this.children.length > y) { @@ -2031,15 +2005,15 @@ Terminal.prototype.resize = function(x, y) { this.rows = y; // Make sure that the cursor stays on screen - if (this.y >= y) { - this.y = y - 1; + if (this.buffer.y >= y) { + this.buffer.y = y - 1; } if (addToY) { - this.y += addToY; + this.buffer.y += addToY; } - if (this.x >= x) { - this.x = x - 1; + if (this.buffer.x >= x) { + this.buffer.x = x - 1; } this.scrollTop = 0; @@ -2132,7 +2106,7 @@ Terminal.prototype.nextStop = function(x) { * @param {number} y The line in which to operate. */ Terminal.prototype.eraseRight = function(x, y) { - var line = this.buffer.lines.get(this.ybase + y); + var line = this.buffer.lines.get(this.buffer.ybase + y); if (!line) { return; } @@ -2151,7 +2125,7 @@ Terminal.prototype.eraseRight = function(x, y) { * @param {number} y The line in which to operate. */ Terminal.prototype.eraseLeft = function(x, y) { - var line = this.buffer.lines.get(this.ybase + y); + var line = this.buffer.lines.get(this.buffer.ybase + y); if (!line) { return; } @@ -2167,20 +2141,20 @@ Terminal.prototype.eraseLeft = function(x, y) { * Clears the entire buffer, making the prompt line the new first line. */ Terminal.prototype.clear = function() { - if (this.ybase === 0 && this.y === 0) { + if (this.buffer.ybase === 0 && this.buffer.y === 0) { // Don't clear if it's already clear return; } - this.buffer.lines.set(0, this.buffer.lines.get(this.ybase + this.y)); + this.buffer.lines.set(0, this.buffer.lines.get(this.buffer.ybase + this.buffer.y)); this.buffer.lines.length = 1; - this.ydisp = 0; - this.ybase = 0; - this.y = 0; + this.buffer.ydisp = 0; + this.buffer.ybase = 0; + this.buffer.y = 0; for (var i = 1; i < this.rows; i++) { this.buffer.lines.push(this.blankLine()); } this.refresh(0, this.rows - 1); - this.emit('scroll', this.ydisp); + this.emit('scroll', this.buffer.ydisp); }; /** @@ -2257,7 +2231,7 @@ Terminal.prototype.handler = function(data) { } // Input is being sent to the terminal, the terminal should focus the prompt. - if (this.ybase !== this.ydisp) { + if (this.buffer.ybase !== this.buffer.ydisp) { this.scrollToBottom(); } this.emit('data', data); @@ -2287,13 +2261,13 @@ Terminal.prototype.handleTitle = function(title) { * ESC D Index (IND is 0x84). */ Terminal.prototype.index = function() { - this.y++; - if (this.y > this.scrollBottom) { - this.y--; + this.buffer.y++; + if (this.buffer.y > this.scrollBottom) { + this.buffer.y--; this.scroll(); } // If the end of the line is hit, prevent this action from wrapping around to the next line. - if (this.x >= this.cols) { + if (this.buffer.x >= this.cols) { this.x--; } }; @@ -2306,16 +2280,16 @@ Terminal.prototype.index = function() { */ Terminal.prototype.reverseIndex = function() { var j; - if (this.y === this.scrollTop) { + if (this.buffer.y === this.scrollTop) { // possibly move the code below to term.reverseScroll(); // test: echo -ne '\e[1;1H\e[44m\eM\e[0m' // blankLine(true) is xterm/linux behavior - this.buffer.lines.shiftElements(this.y + this.ybase, this.rows - 1, 1); - this.buffer.lines.set(this.y + this.ybase, this.blankLine(true)); + this.buffer.lines.shiftElements(this.buffer.y + this.buffer.ybase, this.rows - 1, 1); + this.buffer.lines.set(this.buffer.y + this.buffer.ybase, this.blankLine(true)); this.updateRange(this.scrollTop); this.updateRange(this.scrollBottom); } else { - this.y--; + this.buffer.y--; } }; -- 2.39.2