From 8ede1fc9d2d0ef91ffcc9ad53587f19cdc6d0427 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 18 Jun 2017 19:16:48 +0300 Subject: [PATCH] Create `terminal.buffer` convenience attribute --- src/BufferSet.ts | 8 ++++-- src/InputHandler.ts | 70 ++++++++++++++++++++++----------------------- src/Renderer.ts | 2 +- src/Viewport.ts | 4 +-- src/xterm.js | 69 +++++++++++++++++++++++++------------------- 5 files changed, 84 insertions(+), 69 deletions(-) diff --git a/src/BufferSet.ts b/src/BufferSet.ts index e09ba96..e115fe0 100644 --- a/src/BufferSet.ts +++ b/src/BufferSet.ts @@ -4,13 +4,15 @@ import { ITerminal } from './Interfaces'; import { Buffer } from './Buffer'; +import { EventEmitter } from './EventEmitter'; -export class BufferSet { +export class BufferSet extends EventEmitter { private _normal: Buffer; private _alt: Buffer; private _activeBuffer: Buffer; constructor(private _terminal: ITerminal) { + super(); this._normal = new Buffer(this._terminal); this._alt = new Buffer(this._terminal); this._activeBuffer = this._normal; @@ -36,9 +38,11 @@ export class BufferSet { public activateNormalBuffer(): void { this._activeBuffer = this._normal; + this.emit('activate', this._normal); } public activateAltBuffer(): void { - this._activeBuffer = this._normal; + this._activeBuffer = this._alt; + this.emit('activate', this._alt); } } diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 52e5b4a..0e4c276 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -33,15 +33,15 @@ export class InputHandler implements IInputHandler { // FIXME: needs handling after cursor jumps if (!ch_width && this._terminal.x) { // dont overflow left - if (this._terminal.lines.get(row)[this._terminal.x - 1]) { - if (!this._terminal.lines.get(row)[this._terminal.x - 1][2]) { + if (this._terminal.buffer.lines.get(row)[this._terminal.x - 1]) { + if (!this._terminal.buffer.lines.get(row)[this._terminal.x - 1][2]) { // found empty cell after fullwidth, need to go 2 cells back - if (this._terminal.lines.get(row)[this._terminal.x - 2]) - this._terminal.lines.get(row)[this._terminal.x - 2][1] += char; + if (this._terminal.buffer.lines.get(row)[this._terminal.x - 2]) + this._terminal.buffer.lines.get(row)[this._terminal.x - 2][1] += char; } else { - this._terminal.lines.get(row)[this._terminal.x - 1][1] += char; + this._terminal.buffer.lines.get(row)[this._terminal.x - 1][1] += char; } this._terminal.updateRange(this._terminal.y); } @@ -77,25 +77,25 @@ 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.lines.get(this._terminal.y + this._terminal.ybase).pop(); + const removed = this._terminal.buffer.lines.get(this._terminal.y + this._terminal.ybase).pop(); if (removed[2] === 0 - && this._terminal.lines.get(row)[this._terminal.cols - 2] - && this._terminal.lines.get(row)[this._terminal.cols - 2][2] === 2) { - this._terminal.lines.get(row)[this._terminal.cols - 2] = [this._terminal.curAttr, ' ', 1]; + && this._terminal.buffer.lines.get(row)[this._terminal.cols - 2] + && this._terminal.buffer.lines.get(row)[this._terminal.cols - 2][2] === 2) { + this._terminal.buffer.lines.get(row)[this._terminal.cols - 2] = [this._terminal.curAttr, ' ', 1]; } // insert empty cell at cursor - this._terminal.lines.get(row).splice(this._terminal.x, 0, [this._terminal.curAttr, ' ', 1]); + this._terminal.buffer.lines.get(row).splice(this._terminal.x, 0, [this._terminal.curAttr, ' ', 1]); } } - this._terminal.lines.get(row)[this._terminal.x] = [this._terminal.curAttr, char, ch_width]; + this._terminal.buffer.lines.get(row)[this._terminal.x] = [this._terminal.curAttr, char, ch_width]; this._terminal.x++; this._terminal.updateRange(this._terminal.y); // fullwidth char - set next cell width to zero and advance cursor if (ch_width === 2) { - this._terminal.lines.get(row)[this._terminal.x] = [this._terminal.curAttr, '', 0]; + this._terminal.buffer.lines.get(row)[this._terminal.x] = [this._terminal.curAttr, '', 0]; this._terminal.x++; } } @@ -194,8 +194,8 @@ export class InputHandler implements IInputHandler { ch = [this._terminal.eraseAttr(), ' ', 1]; // xterm while (param-- && j < this._terminal.cols) { - this._terminal.lines.get(row).splice(j++, 0, ch); - this._terminal.lines.get(row).pop(); + this._terminal.buffer.lines.get(row).splice(j++, 0, ch); + this._terminal.buffer.lines.get(row).pop(); } } @@ -392,9 +392,9 @@ export class InputHandler implements IInputHandler { break; case 3: // Clear scrollback (everything not in viewport) - const scrollBackSize = this._terminal.lines.length - this._terminal.rows; + const scrollBackSize = this._terminal.buffer.lines.length - this._terminal.rows; if (scrollBackSize > 0) { - this._terminal.lines.trimStart(scrollBackSize); + 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); // Force a scroll event to refresh viewport @@ -446,9 +446,9 @@ export class InputHandler implements IInputHandler { j = this._terminal.rows - 1 + this._terminal.ybase - j + 1; while (param--) { - if (this._terminal.lines.length === this._terminal.lines.maxLength) { + 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.lines.trimStart(1); + this._terminal.buffer.lines.trimStart(1); this._terminal.ybase--; this._terminal.ydisp--; row--; @@ -456,8 +456,8 @@ export class InputHandler implements IInputHandler { } // 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._terminal.buffer.lines.splice(row, 0, this._terminal.blankLine(true)); + this._terminal.buffer.lines.splice(j, 1); } // this.maxRange(); @@ -482,16 +482,16 @@ export class InputHandler implements IInputHandler { j = this._terminal.rows - 1 + this._terminal.ybase - j; while (param--) { - if (this._terminal.lines.length === this._terminal.lines.maxLength) { + 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.lines.trimStart(1); + this._terminal.buffer.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._terminal.buffer.lines.splice(j + 1, 0, this._terminal.blankLine(true)); + this._terminal.buffer.lines.splice(row, 1); } // this.maxRange(); @@ -515,8 +515,8 @@ export class InputHandler implements IInputHandler { 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); + this._terminal.buffer.lines.get(row).splice(this._terminal.x, 1); + this._terminal.buffer.lines.get(row).push(ch); } } @@ -526,8 +526,8 @@ export class InputHandler implements IInputHandler { public scrollUp(params: number[]): void { let param = params[0] || 1; while (param--) { - this._terminal.lines.splice(this._terminal.ybase + this._terminal.scrollTop, 1); - this._terminal.lines.splice(this._terminal.ybase + this._terminal.scrollBottom, 0, this._terminal.blankLine()); + 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.maxRange(); this._terminal.updateRange(this._terminal.scrollTop); @@ -540,8 +540,8 @@ export class InputHandler implements IInputHandler { public scrollDown(params: number[]): void { let param = params[0] || 1; while (param--) { - this._terminal.lines.splice(this._terminal.ybase + this._terminal.scrollBottom, 1); - this._terminal.lines.splice(this._terminal.ybase + this._terminal.scrollTop, 0, this._terminal.blankLine()); + 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.maxRange(); this._terminal.updateRange(this._terminal.scrollTop); @@ -565,7 +565,7 @@ export class InputHandler implements IInputHandler { ch = [this._terminal.eraseAttr(), ' ', 1]; // xterm while (param-- && j < this._terminal.cols) { - this._terminal.lines.get(row)[j++] = ch; + this._terminal.buffer.lines.get(row)[j++] = ch; } } @@ -615,7 +615,7 @@ export class InputHandler implements IInputHandler { */ public repeatPrecedingCharacter(params: number[]): void { let param = params[0] || 1 - , line = this._terminal.lines.get(this._terminal.ybase + this._terminal.y) + , line = this._terminal.buffer.lines.get(this._terminal.ybase + this._terminal.y) , ch = line[this._terminal.x - 1] || [this._terminal.defAttr, ' ', 1]; while (param--) { @@ -949,7 +949,7 @@ export class InputHandler implements IInputHandler { case 1047: // alt screen buffer if (!this._terminal.normal) { let normal = { - lines: this._terminal.lines, + lines: this._terminal.buffers.normal.lines, ybase: this._terminal.ybase, ydisp: this._terminal.ydisp, x: this._terminal.x, @@ -1128,7 +1128,7 @@ export class InputHandler implements IInputHandler { case 47: // normal screen buffer case 1047: // normal screen buffer - clearing it first if (this._terminal.normal) { - this._terminal.lines = this._terminal.normal.lines; + 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; @@ -1138,7 +1138,7 @@ export class InputHandler implements IInputHandler { this._terminal.tabs = this._terminal.normal.tabs; this._terminal.normal = null; // Ensure the selection manager has the correct buffer - this._terminal.selectionManager.setBuffer(this._terminal.lines); + this._terminal.selectionManager.setBuffer(this._terminal.buffer.lines); // if (params === 1049) { // this.x = this.savedX; // this.y = this.savedY; diff --git a/src/Renderer.ts b/src/Renderer.ts index f057a91..3d4d918 100644 --- a/src/Renderer.ts +++ b/src/Renderer.ts @@ -141,7 +141,7 @@ export class Renderer { for (; y <= end; y++) { let row = y + this._terminal.ydisp; - let line = this._terminal.lines.get(row); + let line = this._terminal.buffer.lines.get(row); let x; if (this._terminal.y === y - (this._terminal.ybase - this._terminal.ydisp) && diff --git a/src/Viewport.ts b/src/Viewport.ts index 5be6bff..a92836f 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -68,9 +68,9 @@ export class Viewport { * Updates dimensions and synchronizes the scroll area if necessary. */ public syncScrollArea(): void { - if (this.lastRecordedBufferLength !== this.terminal.lines.length) { + if (this.lastRecordedBufferLength !== this.terminal.buffer.lines.length) { // If buffer height changed - this.lastRecordedBufferLength = this.terminal.lines.length; + this.lastRecordedBufferLength = this.terminal.buffer.lines.length; this.refresh(); } else if (this.lastRecordedViewportHeight !== this.terminal.rows) { // If viewport height changed diff --git a/src/xterm.js b/src/xterm.js index 4b54057..30d7148 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -244,19 +244,25 @@ function Terminal(options) { // leftover surrogate high from previous write invocation this.surrogate_high = ''; + // Create the terminal's buffers and set the current buffer this.buffers = new BufferSet(this); + this.buffer = this.buffers.active; // Convenience shortcut; + this.buffers.on('activate', function (buffer) { + this.buffer = buffer; + }); + /** * An array of all lines in the entire buffer, including the prompt. The lines are array of * characters which are 2-length arrays where [0] is an attribute and [1] is the character. */ - this.lines = new CircularList(this.scrollback); var i = this.rows; + while (i--) { - this.lines.push(this.blankLine()); + this.buffer.lines.push(this.blankLine()); } // Ensure the selection manager has the correct buffer if (this.selectionManager) { - this.selectionManager.setBuffer(this.lines); + this.selectionManager.setBuffer(this.buffer.lines); } this.tabs; @@ -432,17 +438,17 @@ Terminal.prototype.setOption = function(key, value) { } if (this.options[key] !== value) { - if (this.lines.length > value) { - const amountToTrim = this.lines.length - value; + if (this.buffer.length > value) { + const amountToTrim = this.buffer.lines.length - value; const needsRefresh = (this.ydisp - amountToTrim < 0); - this.lines.trimStart(amountToTrim); + this.buffer.lines.trimStart(amountToTrim); this.ybase = Math.max(this.ybase - amountToTrim, 0); this.ydisp = Math.max(this.ydisp - amountToTrim, 0); if (needsRefresh) { this.refresh(0, this.rows - 1); } } - this.lines.maxLength = value; + this.buffer.lines.maxLength = value; this.viewport.syncScrollArea(); } break; @@ -727,6 +733,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.on('refresh', data => { this.renderer.refreshSelection(data.start, data.end); @@ -739,6 +746,10 @@ 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()); @@ -1171,8 +1182,8 @@ Terminal.prototype.scroll = function(isWrapped) { var row; // Make room for the new row in lines - if (this.lines.length === this.lines.maxLength) { - this.lines.trimStart(1); + if (this.buffer.lines.length === this.buffer.lines.maxLength) { + this.buffer.lines.trimStart(1); this.ybase--; if (this.ydisp !== 0) { this.ydisp--; @@ -1192,12 +1203,12 @@ Terminal.prototype.scroll = function(isWrapped) { // subtract the bottom scroll region row -= this.rows - 1 - this.scrollBottom; - if (row === this.lines.length) { + if (row === this.buffer.lines.length) { // Optimization: pushing is faster than splicing when they amount to the same behavior - this.lines.push(this.blankLine(undefined, isWrapped)); + this.buffer.lines.push(this.blankLine(undefined, isWrapped)); } else { // add our new line - this.lines.splice(row, 0, this.blankLine(undefined, isWrapped)); + this.buffer.lines.splice(row, 0, this.blankLine(undefined, isWrapped)); } if (this.scrollTop !== 0) { @@ -1207,7 +1218,7 @@ Terminal.prototype.scroll = function(isWrapped) { this.ydisp = this.ybase; } } - this.lines.splice(this.ybase + this.scrollTop, 1); + this.buffer.lines.splice(this.ybase + this.scrollTop, 1); } // this.maxRange(); @@ -1960,10 +1971,10 @@ Terminal.prototype.resize = function(x, y) { j = this.cols; if (j < x) { ch = [this.defAttr, ' ', 1]; // does xterm use the default attr? - i = this.lines.length; + i = this.buffer.lines.length; while (i--) { - while (this.lines.get(i).length < x) { - this.lines.get(i).push(ch); + while (this.buffer.lines.get(i).length < x) { + this.buffer.lines.get(i).push(ch); } } } @@ -1978,8 +1989,8 @@ Terminal.prototype.resize = function(x, y) { el = this.element; while (j++ < y) { // y is rows, not this.y - if (this.lines.length < y + this.ybase) { - if (this.ybase > 0 && this.lines.length <= this.ybase + this.y + addToY + 1) { + if (this.buffer.lines.length < y + this.ybase) { + if (this.ybase > 0 && this.buffer.lines.length <= this.ybase + this.y + addToY + 1) { // There is room above the buffer and there are no empty elements below the line, // scroll up this.ybase--; @@ -1991,7 +2002,7 @@ Terminal.prototype.resize = function(x, y) { } else { // Add a blank line if there is no buffer left at the top to scroll to, or if there // are blank lines after the cursor - this.lines.push(this.blankLine()); + this.buffer.lines.push(this.blankLine()); } } if (this.children.length < y) { @@ -2000,10 +2011,10 @@ Terminal.prototype.resize = function(x, y) { } } else { // (j > y) while (j-- > y) { - if (this.lines.length > y + this.ybase) { - if (this.lines.length > this.ybase + this.y + 1) { + if (this.buffer.lines.length > y + this.ybase) { + if (this.buffer.lines.length > this.ybase + this.y + 1) { // The line is a blank line below the cursor, remove it - this.lines.pop(); + this.buffer.lines.pop(); } else { // The line is the cursor, scroll down this.ybase++; @@ -2121,7 +2132,7 @@ Terminal.prototype.nextStop = function(x) { * @param {number} y The line in which to operate. */ Terminal.prototype.eraseRight = function(x, y) { - var line = this.lines.get(this.ybase + y); + var line = this.buffer.lines.get(this.ybase + y); if (!line) { return; } @@ -2140,7 +2151,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.lines.get(this.ybase + y); + var line = this.buffer.lines.get(this.ybase + y); if (!line) { return; } @@ -2160,13 +2171,13 @@ Terminal.prototype.clear = function() { // Don't clear if it's already clear return; } - this.lines.set(0, this.lines.get(this.ybase + this.y)); - this.lines.length = 1; + this.buffer.lines.set(0, this.buffer.lines.get(this.ybase + this.y)); + this.buffer.lines.length = 1; this.ydisp = 0; this.ybase = 0; this.y = 0; for (var i = 1; i < this.rows; i++) { - this.lines.push(this.blankLine()); + this.buffer.lines.push(this.blankLine()); } this.refresh(0, this.rows - 1); this.emit('scroll', this.ydisp); @@ -2299,8 +2310,8 @@ Terminal.prototype.reverseIndex = function() { // 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.lines.shiftElements(this.y + this.ybase, this.rows - 1, 1); - this.lines.set(this.y + this.ybase, this.blankLine(true)); + this.buffer.lines.shiftElements(this.y + this.ybase, this.rows - 1, 1); + this.buffer.lines.set(this.y + this.ybase, this.blankLine(true)); this.updateRange(this.scrollTop); this.updateRange(this.scrollBottom); } else { -- 2.39.2