From b3a3501a4d5a3fca9144df8e8db8cc5771cd2e7e Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 18 Jun 2017 17:56:40 +0300 Subject: [PATCH 01/26] Introduce new Buffer and BufferSet classes --- src/Buffer.ts | 23 +++++++++++++++++++++++ src/BufferSet.ts | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/Interfaces.ts | 1 + src/xterm.js | 2 ++ 4 files changed, 70 insertions(+) create mode 100644 src/Buffer.ts create mode 100644 src/BufferSet.ts diff --git a/src/Buffer.ts b/src/Buffer.ts new file mode 100644 index 0000000000..ba147d8108 --- /dev/null +++ b/src/Buffer.ts @@ -0,0 +1,23 @@ +/** + * @license MIT + */ + +import { ITerminal } from './Interfaces'; +import { CircularList } from './utils/CircularList'; + +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) { + this._lines = new CircularList(this.terminal.scrollback); + } + + public get lines(): CircularList { + return this._lines; + } +} diff --git a/src/BufferSet.ts b/src/BufferSet.ts new file mode 100644 index 0000000000..e09ba96bf3 --- /dev/null +++ b/src/BufferSet.ts @@ -0,0 +1,44 @@ +/** + * @license MIT + */ + +import { ITerminal } from './Interfaces'; +import { Buffer } from './Buffer'; + +export class BufferSet { + private _normal: Buffer; + private _alt: Buffer; + private _activeBuffer: Buffer; + + constructor(private _terminal: ITerminal) { + this._normal = new Buffer(this._terminal); + this._alt = new Buffer(this._terminal); + this._activeBuffer = this._normal; + } + + public get alt(): Buffer { + return this._alt; + } + + public get active(): Buffer { + return this._activeBuffer; + } + + public get normal(): Buffer { + return this._normal; + } + + private resetTerminal() { + this._terminal.reset(); + this._terminal.viewport.syncScrollArea(); + this._terminal.showCursor(); + } + + public activateNormalBuffer(): void { + this._activeBuffer = this._normal; + } + + public activateAltBuffer(): void { + this._activeBuffer = this._normal; + } +} diff --git a/src/Interfaces.ts b/src/Interfaces.ts index 4de2f28582..039e8a3f39 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -37,6 +37,7 @@ export interface ITerminal { x: number; y: number; defAttr: number; + scrollback: number; /** * Emit the 'data' event and populate the given data. diff --git a/src/xterm.js b/src/xterm.js index a97070961d..4b540576e6 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -10,6 +10,7 @@ * @license MIT */ +import { BufferSet } from './BufferSet'; import { CompositionHelper } from './CompositionHelper'; import { EventEmitter } from './EventEmitter'; import { Viewport } from './Viewport'; @@ -243,6 +244,7 @@ function Terminal(options) { // leftover surrogate high from previous write invocation this.surrogate_high = ''; + this.buffers = new BufferSet(this); /** * 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. From 74ac1e1a1a373f0f851072422a087be15af33cdf Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 18 Jun 2017 19:16:48 +0300 Subject: [PATCH 02/26] 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 e09ba96bf3..e115fe001c 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 52e5b4a11c..0e4c276fae 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 f057a912bb..3d4d918b0c 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 5be6bffdfb..a92836ff65 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 4b540576e6..30d7148f0b 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 { From 65a2fd4854638a2e23b1cd664ab322d7542bcc63 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 18 Jun 2017 20:00:22 +0300 Subject: [PATCH 03/26] 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 ba147d8108..32a406a6c5 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 e115fe001c..0429c52365 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 0e4c276fae..f629dc53cb 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 039e8a3f39..779f279d96 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 3d4d918b0c..236b70d1bf 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 31ee8c2c8f..58b37b9a6e 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 a92836ff65..81ecca1b9a 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 30d7148f0b..55c095d4b9 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--; } }; From e1d39fe8800a4e0aa9627d6a5a82f1b30e767c5f Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 18 Jun 2017 21:08:59 +0300 Subject: [PATCH 04/26] Fix some references --- src/Buffer.ts | 8 ++------ src/Parser.ts | 2 +- src/Renderer.ts | 4 ++-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Buffer.ts b/src/Buffer.ts index 32a406a6c5..78882b7147 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -9,7 +9,7 @@ import { CircularList } from './utils/CircularList'; * This class represents a terminal buffer (an internal state of the terminal)/ */ export class Buffer { - private _lines: CircularList; + public lines: CircularList; private _tabs: any; /** @@ -27,10 +27,6 @@ export class Buffer { public y: number = 0, public x: number = 0, ) { - this._lines = new CircularList(this.terminal.scrollback); - } - - public get lines(): CircularList { - return this._lines; + this.lines = new CircularList(this.terminal.scrollback); } } diff --git a/src/Parser.ts b/src/Parser.ts index 00d574eec8..2bb635d872 100644 --- a/src/Parser.ts +++ b/src/Parser.ts @@ -52,7 +52,7 @@ escapedStateHandler['c'] = (parser, terminal) => { }; escapedStateHandler['E'] = (parser, terminal) => { // ESC E Next Line ( NEL is 0x85). - terminal.x = 0; + terminal.buffer.x = 0; terminal.index(); parser.setState(ParserState.NORMAL); }; diff --git a/src/Renderer.ts b/src/Renderer.ts index 236b70d1bf..db4d6a63b5 100644 --- a/src/Renderer.ts +++ b/src/Renderer.ts @@ -144,10 +144,10 @@ export class Renderer { let line = this._terminal.buffer.lines.get(row); let x; - if (this._terminal.y === y - (this._terminal.buffer.ybase - this._terminal.buffer.ydisp) && + if (this._terminal.buffer.y === y - (this._terminal.buffer.ybase - this._terminal.buffer.ydisp) && this._terminal.cursorState && !this._terminal.cursorHidden) { - x = this._terminal.x; + x = this._terminal.buffer.x; } else { x = -1; } From 60e06789929eadb01da8d14063d21dbf3acce856 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 18 Jun 2017 21:15:08 +0300 Subject: [PATCH 05/26] Fix more references to `buffer.x` --- src/xterm.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/xterm.js b/src/xterm.js index 55c095d4b9..5d552fc9da 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -2079,7 +2079,7 @@ Terminal.prototype.setupStops = function(i) { * @param {number} x The position to move the cursor to the previous tab stop. */ Terminal.prototype.prevStop = function(x) { - if (x == null) x = this.x; + if (x == null) x = this.buffer.x; while (!this.tabs[--x] && x > 0); return x >= this.cols ? this.cols - 1 @@ -2092,7 +2092,7 @@ Terminal.prototype.prevStop = function(x) { * @param {number} x The position to move the cursor one tab stop forward. */ Terminal.prototype.nextStop = function(x) { - if (x == null) x = this.x; + if (x == null) x = this.buffer.x; while (!this.tabs[++x] && x < this.cols); return x >= this.cols ? this.cols - 1 @@ -2268,7 +2268,7 @@ Terminal.prototype.index = function() { } // If the end of the line is hit, prevent this action from wrapping around to the next line. if (this.buffer.x >= this.cols) { - this.x--; + this.buffer.x--; } }; @@ -2314,7 +2314,7 @@ Terminal.prototype.reset = function() { * ESC H Tab Set (HTS is 0x88). */ Terminal.prototype.tabSet = function() { - this.tabs[this.x] = true; + this.tabs[this.buffer.x] = true; }; /** From 6628e8f4d0666c2a2c2b525315778afefa0e1c87 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Wed, 21 Jun 2017 19:08:33 +0300 Subject: [PATCH 06/26] Move `scrollTop` and `scrollBottom` into `Buffer` --- src/Buffer.ts | 5 ++- src/InputHandler.ts | 70 ++++++++++++++---------------------- src/Interfaces.ts | 5 --- src/Parser.ts | 4 +-- src/SelectionManager.test.ts | 2 +- src/SelectionModel.ts | 2 +- src/xterm.js | 39 ++++++++++---------- 7 files changed, 56 insertions(+), 71 deletions(-) diff --git a/src/Buffer.ts b/src/Buffer.ts index 78882b7147..e36ff99e6d 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -10,7 +10,6 @@ import { CircularList } from './utils/CircularList'; */ export class Buffer { public lines: CircularList; - private _tabs: any; /** * Create a new Buffer. @@ -26,7 +25,11 @@ export class Buffer { public ybase: number = 0, public y: number = 0, public x: number = 0, + public scrollBottom: number = 0, + public scrollTop: number = 0, + public tabs: any = {}, ) { this.lines = new CircularList(this.terminal.scrollback); + this.scrollBottom = this.terminal.rows - 1; } } diff --git a/src/InputHandler.ts b/src/InputHandler.ts index f629dc53cb..bf5b651ecf 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -55,7 +55,7 @@ export class InputHandler implements IInputHandler { if (this._terminal.wraparoundMode) { this._terminal.buffer.x = 0; this._terminal.buffer.y++; - if (this._terminal.buffer.y > this._terminal.scrollBottom) { + if (this._terminal.buffer.y > this._terminal.buffer.scrollBottom) { this._terminal.buffer.y--; this._terminal.scroll(true); } else { @@ -124,7 +124,7 @@ export class InputHandler implements IInputHandler { this._terminal.buffer.x = 0; } this._terminal.buffer.y++; - if (this._terminal.buffer.y > this._terminal.scrollBottom) { + if (this._terminal.buffer.y > this._terminal.buffer.scrollBottom) { this._terminal.buffer.y--; this._terminal.scroll(); } @@ -441,7 +441,7 @@ export class InputHandler implements IInputHandler { } row = this._terminal.buffer.y + this._terminal.buffer.ybase; - j = this._terminal.rows - 1 - this._terminal.scrollBottom; + j = this._terminal.rows - 1 - this._terminal.buffer.scrollBottom; j = this._terminal.rows - 1 + this._terminal.buffer.ybase - j + 1; while (param--) { @@ -461,7 +461,7 @@ export class InputHandler implements IInputHandler { // this.maxRange(); this._terminal.updateRange(this._terminal.buffer.y); - this._terminal.updateRange(this._terminal.scrollBottom); + this._terminal.updateRange(this._terminal.buffer.scrollBottom); } /** @@ -477,7 +477,7 @@ export class InputHandler implements IInputHandler { } row = this._terminal.buffer.y + this._terminal.buffer.ybase; - j = this._terminal.rows - 1 - this._terminal.scrollBottom; + j = this._terminal.rows - 1 - this._terminal.buffer.scrollBottom; j = this._terminal.rows - 1 + this._terminal.buffer.ybase - j; while (param--) { @@ -495,7 +495,7 @@ export class InputHandler implements IInputHandler { // this.maxRange(); this._terminal.updateRange(this._terminal.buffer.y); - this._terminal.updateRange(this._terminal.scrollBottom); + this._terminal.updateRange(this._terminal.buffer.scrollBottom); } /** @@ -525,12 +525,12 @@ export class InputHandler implements IInputHandler { public scrollUp(params: number[]): void { let param = params[0] || 1; while (param--) { - 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._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollTop, 1); + this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollBottom, 0, this._terminal.blankLine()); } // this.maxRange(); - this._terminal.updateRange(this._terminal.scrollTop); - this._terminal.updateRange(this._terminal.scrollBottom); + this._terminal.updateRange(this._terminal.buffer.scrollTop); + this._terminal.updateRange(this._terminal.buffer.scrollBottom); } /** @@ -539,12 +539,12 @@ export class InputHandler implements IInputHandler { public scrollDown(params: number[]): void { let param = params[0] || 1; while (param--) { - 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._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollBottom, 1); + this._terminal.buffer.lines.splice(this._terminal.buffer.ybase + this._terminal.buffer.scrollTop, 0, this._terminal.blankLine()); } // this.maxRange(); - this._terminal.updateRange(this._terminal.scrollTop); - this._terminal.updateRange(this._terminal.scrollBottom); + this._terminal.updateRange(this._terminal.buffer.scrollTop); + this._terminal.updateRange(this._terminal.buffer.scrollBottom); } /** @@ -754,9 +754,9 @@ export class InputHandler implements IInputHandler { public tabClear(params: number[]): void { let param = params[0]; if (param <= 0) { - delete this._terminal.tabs[this._terminal.buffer.x]; + delete this._terminal.buffer.tabs[this._terminal.buffer.x]; } else if (param === 3) { - this._terminal.tabs = {}; + this._terminal.buffer.tabs = {}; } } @@ -948,13 +948,7 @@ export class InputHandler implements IInputHandler { case 1047: // alt screen buffer if (!this._terminal.normal) { let normal = { - scrollTop: this._terminal.scrollTop, - scrollBottom: this._terminal.scrollBottom, - tabs: this._terminal.tabs - // XXX save charset(s) here? - // charset: this._terminal.charset, - // glevel: this._terminal.glevel, - // charsets: this._terminal.charsets + scrollBottom: this._terminal.buffer.scrollBottom, }; this._terminal.buffers.activateAltBuffer(); } @@ -1118,22 +1112,12 @@ export class InputHandler implements IInputHandler { ; // FALL-THROUGH case 47: // normal screen buffer case 1047: // normal screen buffer - clearing it first - if (this._terminal.normal) { - this._terminal.scrollTop = this._terminal.normal.scrollTop; - this._terminal.scrollBottom = this._terminal.normal.scrollBottom; - 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.buffer.lines); - // if (params === 1049) { - // 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(); - } + // Ensure the selection manager has the correct buffer + this._terminal.buffers.activateNormalBuffer(); + this._terminal.selectionManager.setBuffer(this._terminal.buffer.lines); + this._terminal.refresh(0, this._terminal.rows - 1); + this._terminal.viewport.syncScrollArea(); + this._terminal.showCursor(); break; } } @@ -1403,8 +1387,8 @@ export class InputHandler implements IInputHandler { this._terminal.applicationKeypad = false; // ? this._terminal.viewport.syncScrollArea(); this._terminal.applicationCursor = false; - this._terminal.scrollTop = 0; - this._terminal.scrollBottom = this._terminal.rows - 1; + this._terminal.buffer.scrollTop = 0; + this._terminal.buffer.scrollBottom = this._terminal.rows - 1; this._terminal.curAttr = this._terminal.defAttr; this._terminal.buffer.x = this._terminal.buffer.y = 0; // ? this._terminal.charset = null; @@ -1450,8 +1434,8 @@ export class InputHandler implements IInputHandler { */ public setScrollRegion(params: number[]): void { 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.buffer.scrollTop = (params[0] || 1) - 1; + this._terminal.buffer.scrollBottom = (params[1] && params[1] <= this._terminal.rows ? params[1] : this._terminal.rows) - 1; this._terminal.buffer.x = 0; this._terminal.buffer.y = 0; } diff --git a/src/Interfaces.ts b/src/Interfaces.ts index 779f279d96..2dafd909ae 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -24,9 +24,6 @@ export interface ITerminal { selectionManager: ISelectionManager; charMeasure: ICharMeasure; textarea: HTMLTextAreaElement; - ybase: number; - ydisp: number; - lines: ICircularList; rows: number; cols: number; browser: IBrowser; @@ -34,8 +31,6 @@ export interface ITerminal { children: HTMLElement[]; cursorHidden: boolean; cursorState: number; - x: number; - y: number; defAttr: number; scrollback: number; buffer: any; // This should be a `Buffer` class, but it would result in circular dependency diff --git a/src/Parser.ts b/src/Parser.ts index 2bb635d872..6679e366d1 100644 --- a/src/Parser.ts +++ b/src/Parser.ts @@ -499,9 +499,9 @@ export class Parser { // DECSTBM case 'r': pt = '' - + (this._terminal.scrollTop + 1) + + (this._terminal.buffer.scrollTop + 1) + ';' - + (this._terminal.scrollBottom + 1) + + (this._terminal.buffer.scrollBottom + 1) + 'r'; break; diff --git a/src/SelectionManager.test.ts b/src/SelectionManager.test.ts index 71505a294b..e09a6e3d55 100644 --- a/src/SelectionManager.test.ts +++ b/src/SelectionManager.test.ts @@ -196,7 +196,7 @@ describe('SelectionManager', () => { buffer.push(stringToRow('4')); buffer.push(stringToRow('5')); selectionManager.selectAll(); - terminal.ybase = buffer.length - terminal.rows; + terminal.buffer.ybase = buffer.length - terminal.rows; assert.equal(selectionManager.selectionText, '1\n2\n3\n4\n5'); }); }); diff --git a/src/SelectionModel.ts b/src/SelectionModel.ts index 410af3b3a6..8c599fd7ae 100644 --- a/src/SelectionModel.ts +++ b/src/SelectionModel.ts @@ -68,7 +68,7 @@ export class SelectionModel { */ public get finalSelectionEnd(): [number, number] { if (this.isSelectAllActive) { - return [this._terminal.cols, this._terminal.ybase + this._terminal.rows - 1]; + return [this._terminal.cols, this._terminal.buffer.ybase + this._terminal.rows - 1]; } if (!this.selectionStart) { diff --git a/src/xterm.js b/src/xterm.js index 5d552fc9da..d1406ccbe1 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -146,9 +146,13 @@ function Terminal(options) { this.cursorHidden = false; this.convertEol; this.queue = ''; +<<<<<<< HEAD this.scrollTop = 0; this.scrollBottom = this.rows - 1; this.customKeyEventHandler = null; +======= + this.customKeydownHandler = null; +>>>>>>> Move `scrollTop` and `scrollBottom` into `Buffer` this.cursorBlinkInterval = null; // modes @@ -244,7 +248,6 @@ function Terminal(options) { this.selectionManager.setBuffer(this.buffer.lines); } - this.tabs; this.setupStops(); // Store if user went browsing history in scrollback @@ -1175,7 +1178,7 @@ Terminal.prototype.scroll = function(isWrapped) { row = this.buffer.ybase + this.rows - 1; // subtract the bottom scroll region - row -= this.rows - 1 - this.scrollBottom; + row -= this.rows - 1 - this.buffer.scrollBottom; if (row === this.buffer.lines.length) { // Optimization: pushing is faster than splicing when they amount to the same behavior @@ -1185,19 +1188,19 @@ Terminal.prototype.scroll = function(isWrapped) { this.buffer.lines.splice(row, 0, this.blankLine(undefined, isWrapped)); } - if (this.scrollTop !== 0) { + if (this.buffer.scrollTop !== 0) { if (this.buffer.ybase !== 0) { this.buffer.ybase--; if (!this.userScrolling) { this.buffer.ydisp = this.buffer.ybase; } } - this.buffer.lines.splice(this.buffer.ybase + this.scrollTop, 1); + this.buffer.lines.splice(this.buffer.ybase + this.buffer.scrollTop, 1); } // this.maxRange(); - this.updateRange(this.scrollTop); - this.updateRange(this.scrollBottom); + this.updateRange(this.buffer.scrollTop); + this.updateRange(this.buffer.scrollBottom); /** * This event is emitted whenever the terminal is scrolled. @@ -2016,8 +2019,8 @@ Terminal.prototype.resize = function(x, y) { this.buffer.x = x - 1; } - this.scrollTop = 0; - this.scrollBottom = y - 1; + this.buffer.scrollTop = 0; + this.buffer.scrollBottom = y - 1; this.charMeasure.measure(); @@ -2060,16 +2063,16 @@ Terminal.prototype.maxRange = function() { */ Terminal.prototype.setupStops = function(i) { if (i != null) { - if (!this.tabs[i]) { + if (!this.buffer.tabs[i]) { i = this.prevStop(i); } } else { - this.tabs = {}; + this.buffer.tabs = {}; i = 0; } for (; i < this.cols; i += this.getOption('tabStopWidth')) { - this.tabs[i] = true; + this.buffer.tabs[i] = true; } }; @@ -2080,7 +2083,7 @@ Terminal.prototype.setupStops = function(i) { */ Terminal.prototype.prevStop = function(x) { if (x == null) x = this.buffer.x; - while (!this.tabs[--x] && x > 0); + while (!this.buffer.tabs[--x] && x > 0); return x >= this.cols ? this.cols - 1 : x < 0 ? 0 : x; @@ -2093,7 +2096,7 @@ Terminal.prototype.prevStop = function(x) { */ Terminal.prototype.nextStop = function(x) { if (x == null) x = this.buffer.x; - while (!this.tabs[++x] && x < this.cols); + while (!this.buffer.tabs[++x] && x < this.cols); return x >= this.cols ? this.cols - 1 : x < 0 ? 0 : x; @@ -2262,7 +2265,7 @@ Terminal.prototype.handleTitle = function(title) { */ Terminal.prototype.index = function() { this.buffer.y++; - if (this.buffer.y > this.scrollBottom) { + if (this.buffer.y > this.buffer.scrollBottom) { this.buffer.y--; this.scroll(); } @@ -2280,14 +2283,14 @@ Terminal.prototype.index = function() { */ Terminal.prototype.reverseIndex = function() { var j; - if (this.buffer.y === this.scrollTop) { + if (this.buffer.y === this.buffer.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.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); + this.updateRange(this.buffer.scrollTop); + this.updateRange(this.buffer.scrollBottom); } else { this.buffer.y--; } @@ -2314,7 +2317,7 @@ Terminal.prototype.reset = function() { * ESC H Tab Set (HTS is 0x88). */ Terminal.prototype.tabSet = function() { - this.tabs[this.buffer.x] = true; + this.buffer.tabs[this.buffer.x] = true; }; /** From 5c71356259e4333fa47d8ceec7190679e1db8261 Mon Sep 17 00:00:00 2001 From: Aleksandr Andrienko Date: Sun, 25 Jun 2017 21:42:31 +0300 Subject: [PATCH 07/26] Fix turning from alt screen to normal screen and vice versa. Fix https://github.com/sourcelair/xterm.js/issues/229 . --- src/BufferSet.ts | 12 ++---------- src/InputHandler.ts | 25 +++++++++++++------------ src/xterm.js | 15 +++++++++------ 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/BufferSet.ts b/src/BufferSet.ts index 0429c52365..c9022a9ced 100644 --- a/src/BufferSet.ts +++ b/src/BufferSet.ts @@ -30,21 +30,13 @@ export class BufferSet extends EventEmitter { return this._normal; } - private resetTerminal() { - this._terminal.reset(); - this._terminal.viewport.syncScrollArea(); - this._terminal.showCursor(); - } - public activateNormalBuffer(): void { this._activeBuffer = this._normal; - this.resetTerminal(); - this.emit('activate', this._normal); + this.emit('activate', this._normal); // todo maybe simpler this._terminal.buffer = this._terminal.buffers.normal than using EventEmitter? } public activateAltBuffer(): void { this._activeBuffer = this._alt; - this.resetTerminal(); - this.emit('activate', this._alt); + this.emit('activate', this._alt); // todo maybe simpler this._terminal.buffer = this._terminal.buffers.alt than using EventEmitter? } } diff --git a/src/InputHandler.ts b/src/InputHandler.ts index bf5b651ecf..c9b58446be 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -942,16 +942,14 @@ export class InputHandler implements IInputHandler { this._terminal.cursorHidden = false; break; case 1049: // alt screen buffer cursor - // this._terminal.saveCursor(); - ; // FALL-THROUGH + this.saveCursor(params); + // FALL-THROUGH case 47: // alt screen buffer case 1047: // alt screen buffer - if (!this._terminal.normal) { - let normal = { - scrollBottom: this._terminal.buffer.scrollBottom, - }; - this._terminal.buffers.activateAltBuffer(); - } + this._terminal.buffers.activateAltBuffer(); + this._terminal.reset(); + this._terminal.viewport.syncScrollArea(); + this._terminal.showCursor(); break; } } @@ -1114,6 +1112,9 @@ export class InputHandler implements IInputHandler { case 1047: // normal screen buffer - clearing it first // Ensure the selection manager has the correct buffer this._terminal.buffers.activateNormalBuffer(); + if (params[0] === 1049) { + this.restoreCursor(params); + } this._terminal.selectionManager.setBuffer(this._terminal.buffer.lines); this._terminal.refresh(0, this._terminal.rows - 1); this._terminal.viewport.syncScrollArea(); @@ -1446,8 +1447,8 @@ export class InputHandler implements IInputHandler { * Save cursor (ANSI.SYS). */ public saveCursor(params: number[]): void { - this._terminal.savedX = this._terminal.buffer.x; - this._terminal.savedY = this._terminal.buffer.y; + this._terminal.buffers.active.x = this._terminal.buffer.x; + this._terminal.buffers.active.y = this._terminal.buffer.y; } @@ -1456,8 +1457,8 @@ export class InputHandler implements IInputHandler { * Restore cursor (ANSI.SYS). */ public restoreCursor(params: number[]): void { - this._terminal.buffer.x = this._terminal.savedX || 0; - this._terminal.buffer.y = this._terminal.savedY || 0; + this._terminal.buffer.x = this._terminal.buffers.active.x || 0; + this._terminal.buffer.y = this._terminal.buffers.active.y || 0; } } diff --git a/src/xterm.js b/src/xterm.js index d1406ccbe1..5fb5ea743c 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -161,7 +161,6 @@ function Terminal(options) { this.originMode = false; this.insertMode = false; this.wraparoundMode = true; // defaults: xterm - true, vt100 - false - this.normal = null; // charset this.charset = null; @@ -228,10 +227,12 @@ function Terminal(options) { 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; + if (!this.buffers) { + this.buffers = new BufferSet(this); + this.buffer = this.buffers.active; // Convenience shortcut; + } this.buffers.on('activate', function (buffer) { - this.buffer = buffer; + this._terminal.buffer = buffer; }); /** @@ -2026,8 +2027,6 @@ Terminal.prototype.resize = function(x, y) { this.refresh(0, this.rows - 1); - this.normal = null; - this.geometry = [this.cols, this.rows]; this.emit('resize', {terminal: this, cols: x, rows: y}); }; @@ -2305,9 +2304,13 @@ Terminal.prototype.reset = function() { this.options.cols = this.cols; var customKeyEventHandler = this.customKeyEventHandler; var cursorBlinkInterval = this.cursorBlinkInterval; + var inputHandler = this.inputHandler; + var buf = this.buffers; Terminal.call(this, this.options); this.customKeyEventHandler = customKeyEventHandler; this.cursorBlinkInterval = cursorBlinkInterval; + this.inputHandler = inputHandler; + this.buffers = buf; this.refresh(0, this.rows - 1); this.viewport.syncScrollArea(); }; From 09ff1ac9278c2221c5cf32b1209b221bea04f78b Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Tue, 27 Jun 2017 07:42:35 +0300 Subject: [PATCH 08/26] Fix first set of existing tests --- src/test/test.js | 256 +++++++++++++++++++++++------------------------ 1 file changed, 128 insertions(+), 128 deletions(-) diff --git a/src/test/test.js b/src/test/test.js index 5e18397a9f..c5130e2130 100644 --- a/src/test/test.js +++ b/src/test/test.js @@ -64,15 +64,15 @@ describe('xterm.js', function() { describe('clear', function() { it('should clear a buffer equal to rows', function() { - var promptLine = xterm.lines.get(xterm.ybase + xterm.y); + var promptLine = xterm.buffer.lines.get(xterm.buffer.ybase + xterm.buffer.y); xterm.clear(); - assert.equal(xterm.y, 0); - assert.equal(xterm.ybase, 0); - assert.equal(xterm.ydisp, 0); - assert.equal(xterm.lines.length, xterm.rows); - assert.deepEqual(xterm.lines.get(0), promptLine); + assert.equal(xterm.buffer.y, 0); + assert.equal(xterm.buffer.ybase, 0); + assert.equal(xterm.buffer.ydisp, 0); + assert.equal(xterm.buffer.lines.length, xterm.rows); + assert.deepEqual(xterm.buffer.lines.get(0), promptLine); for (var i = 1; i < xterm.rows; i++) { - assert.deepEqual(xterm.lines.get(i), xterm.blankLine()); + assert.deepEqual(xterm.buffer.lines.get(i), xterm.blankLine()); } }); it('should clear a buffer larger than rows', function() { @@ -81,28 +81,28 @@ describe('xterm.js', function() { xterm.write('test\n'); } - var promptLine = xterm.lines.get(xterm.ybase + xterm.y); + var promptLine = xterm.buffer.lines.get(xterm.buffer.ybase + xterm.buffer.y); xterm.clear(); - assert.equal(xterm.y, 0); - assert.equal(xterm.ybase, 0); - assert.equal(xterm.ydisp, 0); - assert.equal(xterm.lines.length, xterm.rows); - assert.deepEqual(xterm.lines.get(0), promptLine); + assert.equal(xterm.buffer.y, 0); + assert.equal(xterm.buffer.ybase, 0); + assert.equal(xterm.buffer.ydisp, 0); + assert.equal(xterm.buffer.lines.length, xterm.rows); + assert.deepEqual(xterm.buffer.lines.get(0), promptLine); for (var i = 1; i < xterm.rows; i++) { - assert.deepEqual(xterm.lines.get(i), xterm.blankLine()); + assert.deepEqual(xterm.buffer.lines.get(i), xterm.blankLine()); } }); it('should not break the prompt when cleared twice', function() { - var promptLine = xterm.lines.get(xterm.ybase + xterm.y); + var promptLine = xterm.buffer.lines.get(xterm.buffer.ybase + xterm.buffer.y); xterm.clear(); xterm.clear(); - assert.equal(xterm.y, 0); - assert.equal(xterm.ybase, 0); - assert.equal(xterm.ydisp, 0); - assert.equal(xterm.lines.length, xterm.rows); - assert.deepEqual(xterm.lines.get(0), promptLine); + assert.equal(xterm.buffer.y, 0); + assert.equal(xterm.buffer.ybase, 0); + assert.equal(xterm.buffer.ydisp, 0); + assert.equal(xterm.buffer.lines.length, xterm.rows); + assert.deepEqual(xterm.buffer.lines.get(0), promptLine); for (var i = 1; i < xterm.rows; i++) { - assert.deepEqual(xterm.lines.get(i), xterm.blankLine()); + assert.deepEqual(xterm.buffer.lines.get(i), xterm.blankLine()); } }); }); @@ -117,29 +117,29 @@ describe('xterm.js', function() { startYDisp = xterm.rows + 1; }); it('should scroll a single line', function() { - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); xterm.scrollDisp(-1); - assert.equal(xterm.ydisp, startYDisp - 1); + assert.equal(xterm.buffer.ydisp, startYDisp - 1); xterm.scrollDisp(1); - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); }); it('should scroll multiple lines', function() { - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); xterm.scrollDisp(-5); - assert.equal(xterm.ydisp, startYDisp - 5); + assert.equal(xterm.buffer.ydisp, startYDisp - 5); xterm.scrollDisp(5); - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); }); it('should not scroll beyond the bounds of the buffer', function() { - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); xterm.scrollDisp(1); - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); for (var i = 0; i < startYDisp; i++) { xterm.scrollDisp(-1); } - assert.equal(xterm.ydisp, 0); + assert.equal(xterm.buffer.ydisp, 0); xterm.scrollDisp(-1); - assert.equal(xterm.ydisp, 0); + assert.equal(xterm.buffer.ydisp, 0); }); }); @@ -152,18 +152,18 @@ describe('xterm.js', function() { startYDisp = (xterm.rows * 2) + 1; }); it('should scroll a single page', function() { - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); xterm.scrollPages(-1); - assert.equal(xterm.ydisp, startYDisp - (xterm.rows - 1)); + assert.equal(xterm.buffer.ydisp, startYDisp - (xterm.rows - 1)); xterm.scrollPages(1); - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); }); it('should scroll a multiple pages', function() { - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); xterm.scrollPages(-2); - assert.equal(xterm.ydisp, startYDisp - (xterm.rows - 1) * 2); + assert.equal(xterm.buffer.ydisp, startYDisp - (xterm.rows - 1) * 2); xterm.scrollPages(2); - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); }); }); @@ -174,9 +174,9 @@ describe('xterm.js', function() { } }); it('should scroll to the top', function() { - assert.notEqual(xterm.ydisp, 0); + assert.notEqual(xterm.buffer.ydisp, 0); xterm.scrollToTop(); - assert.equal(xterm.ydisp, 0); + assert.equal(xterm.buffer.ydisp, 0); }); }); @@ -191,13 +191,13 @@ describe('xterm.js', function() { it('should scroll to the bottom', function() { xterm.scrollDisp(-1); xterm.scrollToBottom(); - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); xterm.scrollPages(-1); xterm.scrollToBottom(); - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); xterm.scrollToTop(); xterm.scrollToBottom(); - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); }); }); @@ -214,13 +214,13 @@ describe('xterm.js', function() { stopPropagation: function(){} }; - xterm.ydisp = 0; - xterm.ybase = 40; - assert.notEqual(xterm.ydisp, xterm.ybase); + xterm.buffer.ydisp = 0; + xterm.buffer.ybase = 40; + assert.notEqual(xterm.buffer.ydisp, xterm.buffer.ybase); xterm.keyDown(event); // Ensure that now the terminal is scrolled to bottom - assert.equal(xterm.ydisp, xterm.ybase); + assert.equal(xterm.buffer.ydisp, xterm.buffer.ybase); }); it('should not scroll down, when a custom keydown handler prevents the event', function () { @@ -233,11 +233,11 @@ describe('xterm.js', function() { return false; }); - assert.equal(xterm.ydisp, startYDisp); + assert.equal(xterm.buffer.ydisp, startYDisp); xterm.scrollDisp(-1); - assert.equal(xterm.ydisp, startYDisp - 1); + assert.equal(xterm.buffer.ydisp, startYDisp - 1); xterm.keyDown({ keyCode: 0 }); - assert.equal(xterm.ydisp, startYDisp - 1); + assert.equal(xterm.buffer.ydisp, startYDisp - 1); }); }); }); @@ -575,48 +575,48 @@ describe('xterm.js', function() { var high = String.fromCharCode(0xD800); for (var i=0xDC00; i<=0xDCFF; ++i) { xterm.write(high + String.fromCharCode(i)); - var tchar = xterm.lines.get(0)[0]; + var tchar = xterm.buffer.lines.get(0)[0]; expect(tchar[1]).eql(high + String.fromCharCode(i)); expect(tchar[1].length).eql(2); expect(tchar[2]).eql(1); - expect(xterm.lines.get(0)[1][1]).eql(' '); + expect(xterm.buffer.lines.get(0)[1][1]).eql(' '); xterm.reset(); } }); it('2 characters at last cell', function() { var high = String.fromCharCode(0xD800); for (var i=0xDC00; i<=0xDCFF; ++i) { - xterm.x = xterm.cols - 1; + xterm.buffer.x = xterm.cols - 1; xterm.write(high + String.fromCharCode(i)); - expect(xterm.lines.get(0)[xterm.x-1][1]).eql(high + String.fromCharCode(i)); - expect(xterm.lines.get(0)[xterm.x-1][1].length).eql(2); - expect(xterm.lines.get(1)[0][1]).eql(' '); + expect(xterm.buffer.lines.get(0)[xterm.buffer.x-1][1]).eql(high + String.fromCharCode(i)); + expect(xterm.buffer.lines.get(0)[xterm.buffer.x-1][1].length).eql(2); + expect(xterm.buffer.lines.get(1)[0][1]).eql(' '); xterm.reset(); } }); it('2 characters per cell over line end with autowrap', function() { var high = String.fromCharCode(0xD800); for (var i=0xDC00; i<=0xDCFF; ++i) { - xterm.x = xterm.cols - 1; + xterm.buffer.x = xterm.cols - 1; xterm.wraparoundMode = true; xterm.write('a' + high + String.fromCharCode(i)); - expect(xterm.lines.get(0)[xterm.cols-1][1]).eql('a'); - expect(xterm.lines.get(1)[0][1]).eql(high + String.fromCharCode(i)); - expect(xterm.lines.get(1)[0][1].length).eql(2); - expect(xterm.lines.get(1)[1][1]).eql(' '); + expect(xterm.buffer.lines.get(0)[xterm.cols-1][1]).eql('a'); + expect(xterm.buffer.lines.get(1)[0][1]).eql(high + String.fromCharCode(i)); + expect(xterm.buffer.lines.get(1)[0][1].length).eql(2); + expect(xterm.buffer.lines.get(1)[1][1]).eql(' '); xterm.reset(); } }); it('2 characters per cell over line end without autowrap', function() { var high = String.fromCharCode(0xD800); for (var i=0xDC00; i<=0xDCFF; ++i) { - xterm.x = xterm.cols - 1; + xterm.buffer.x = xterm.cols - 1; xterm.wraparoundMode = false; xterm.write('a' + high + String.fromCharCode(i)); // auto wraparound mode should cut off the rest of the line - expect(xterm.lines.get(0)[xterm.cols-1][1]).eql('a'); - expect(xterm.lines.get(0)[xterm.cols-1][1].length).eql(1); - expect(xterm.lines.get(1)[1][1]).eql(' '); + expect(xterm.buffer.lines.get(0)[xterm.cols-1][1]).eql('a'); + expect(xterm.buffer.lines.get(0)[xterm.cols-1][1].length).eql(1); + expect(xterm.buffer.lines.get(1)[1][1]).eql(' '); xterm.reset(); } }); @@ -625,11 +625,11 @@ describe('xterm.js', function() { for (var i=0xDC00; i<=0xDCFF; ++i) { xterm.write(high); xterm.write(String.fromCharCode(i)); - var tchar = xterm.lines.get(0)[0]; + var tchar = xterm.buffer.lines.get(0)[0]; expect(tchar[1]).eql(high + String.fromCharCode(i)); expect(tchar[1].length).eql(2); expect(tchar[2]).eql(1); - expect(xterm.lines.get(0)[1][1]).eql(' '); + expect(xterm.buffer.lines.get(0)[1][1]).eql(' '); xterm.reset(); } }); @@ -638,30 +638,30 @@ describe('xterm.js', function() { describe('unicode - combining characters', function() { it('café', function () { xterm.write('cafe\u0301'); - expect(xterm.lines.get(0)[3][1]).eql('e\u0301'); - expect(xterm.lines.get(0)[3][1].length).eql(2); - expect(xterm.lines.get(0)[3][2]).eql(1); + expect(xterm.buffer.lines.get(0)[3][1]).eql('e\u0301'); + expect(xterm.buffer.lines.get(0)[3][1].length).eql(2); + expect(xterm.buffer.lines.get(0)[3][2]).eql(1); }); it('café - end of line', function() { - xterm.x = xterm.cols - 1 - 3; + xterm.buffer.x = xterm.cols - 1 - 3; xterm.write('cafe\u0301'); - expect(xterm.lines.get(0)[xterm.cols-1][1]).eql('e\u0301'); - expect(xterm.lines.get(0)[xterm.cols-1][1].length).eql(2); - expect(xterm.lines.get(0)[xterm.cols-1][2]).eql(1); - expect(xterm.lines.get(0)[1][1]).eql(' '); - expect(xterm.lines.get(0)[1][1].length).eql(1); - expect(xterm.lines.get(0)[1][2]).eql(1); + expect(xterm.buffer.lines.get(0)[xterm.cols-1][1]).eql('e\u0301'); + expect(xterm.buffer.lines.get(0)[xterm.cols-1][1].length).eql(2); + expect(xterm.buffer.lines.get(0)[xterm.cols-1][2]).eql(1); + expect(xterm.buffer.lines.get(0)[1][1]).eql(' '); + expect(xterm.buffer.lines.get(0)[1][1].length).eql(1); + expect(xterm.buffer.lines.get(0)[1][2]).eql(1); }); it('multiple combined é', function() { xterm.wraparoundMode = true; xterm.write(Array(100).join('e\u0301')); for (var i=0; i Date: Fri, 30 Jun 2017 13:39:16 +0300 Subject: [PATCH 09/26] Fix forgotten merge conflict --- src/xterm.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/xterm.js b/src/xterm.js index 5fb5ea743c..db82e15226 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -146,13 +146,7 @@ function Terminal(options) { this.cursorHidden = false; this.convertEol; this.queue = ''; -<<<<<<< HEAD - this.scrollTop = 0; - this.scrollBottom = this.rows - 1; this.customKeyEventHandler = null; -======= - this.customKeydownHandler = null; ->>>>>>> Move `scrollTop` and `scrollBottom` into `Buffer` this.cursorBlinkInterval = null; // modes From ff03b758c5225dda5609833657d9e170db37662d Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Fri, 30 Jun 2017 13:51:40 +0300 Subject: [PATCH 10/26] Fix SelectionManager initializing --- src/xterm.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/xterm.js b/src/xterm.js index db82e15226..6460ca9042 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -710,7 +710,9 @@ Terminal.prototype.open = function(parent, focus) { this.viewport = new Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasure); this.renderer = new Renderer(this); - this.selectionManager = new SelectionManager(this, this.buffer.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); }); From fe254946ab23773fd69d91d6d6df7905a7f12065 Mon Sep 17 00:00:00 2001 From: Oleksandr Andriienko Date: Fri, 30 Jun 2017 13:56:37 +0300 Subject: [PATCH 11/26] Fix some tests and docs, little code fix up. Fix some tests and docs. Add ability to run one test file with help gulp task. Signed-off-by: Oleksandr Andriienko --- gulpfile.js | 17 +++++++++++++++-- package.json | 3 ++- src/Buffer.ts | 4 ++-- src/SelectionManager.test.ts | 23 +++++++++++++++++++++-- src/SelectionModel.test.ts | 5 +++++ src/Viewport.test.ts | 20 +++++++++++--------- src/Viewport.ts | 4 +--- src/xterm.js | 4 ++-- 8 files changed, 59 insertions(+), 21 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 9b0a6de73f..ef4e460998 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -14,7 +14,7 @@ const sorcery = require('sorcery'); const source = require('vinyl-source-stream'); const sourcemaps = require('gulp-sourcemaps'); const ts = require('gulp-typescript'); - +const util = require('gulp-util'); let buildDir = process.env.BUILD_DIR || 'build'; let tsProject = ts.createProject('tsconfig.json'); @@ -121,13 +121,26 @@ gulp.task('mocha', ['instrument-test'], function () { .pipe(istanbul.writeReports()); }); +/** + * Run single test file by file name(without file extension). Example of the command: + * gulp mocha-test --test InputHandler.test + */ +gulp.task('mocha-test', ['instrument-test'], function () { + let testName = util.env.test; + util.log("Run test by Name: " + testName); + return gulp.src([`${outDir}/${testName}.js`, `${outDir}/**/${testName}.js`], {read: false}) + .pipe(mocha()) + .once('error', () => process.exit(1)) + .pipe(istanbul.writeReports()); +}); + /** * Use `sorcery` to resolve the source map chain and point back to the TypeScript files. * (Without this task the source maps produced for the JavaScript bundle points into the * compiled JavaScript files in ${outDir}/). */ gulp.task('sorcery', ['browserify'], function () { - var chain = sorcery.loadSync(`${buildDir}/xterm.js`); + let chain = sorcery.loadSync(`${buildDir}/xterm.js`); chain.apply(); chain.writeSync(); }); diff --git a/package.json b/package.json index b23f4a2c50..065925b3a3 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,8 @@ "tslint": "^4.0.2", "typescript": "~2.2.0", "vinyl-buffer": "^1.0.0", - "vinyl-source-stream": "^1.1.0" + "vinyl-source-stream": "^1.1.0", + "gulp-util": "^3.0.8" }, "scripts": { "prestart": "npm run build", diff --git a/src/Buffer.ts b/src/Buffer.ts index e36ff99e6d..a3e45d25c6 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -9,7 +9,7 @@ import { CircularList } from './utils/CircularList'; * This class represents a terminal buffer (an internal state of the terminal)/ */ export class Buffer { - public lines: CircularList; + public lines: CircularList; /** * Create a new Buffer. @@ -29,7 +29,7 @@ export class Buffer { public scrollTop: number = 0, public tabs: any = {}, ) { - this.lines = new CircularList(this.terminal.scrollback); + this.lines = new CircularList(this.terminal.scrollback); this.scrollBottom = this.terminal.rows - 1; } } diff --git a/src/SelectionManager.test.ts b/src/SelectionManager.test.ts index e09a6e3d55..12784e02b0 100644 --- a/src/SelectionManager.test.ts +++ b/src/SelectionManager.test.ts @@ -8,6 +8,7 @@ import { CharMeasure } from './utils/CharMeasure'; import { CircularList } from './utils/CircularList'; import { SelectionManager } from './SelectionManager'; import { SelectionModel } from './SelectionModel'; +import {BufferSet} from './BufferSet'; class TestSelectionManager extends SelectionManager { constructor( @@ -40,13 +41,31 @@ describe('SelectionManager', () => { let rowContainer: HTMLElement; let selectionManager: TestSelectionManager; +<<<<<<< HEAD beforeEach(() => { dom = new jsdom.JSDOM(''); window = dom.window; - document = window.document; - buffer = new CircularList(100); + document = window.document terminal = { cols: 80, rows: 2 }; + terminal.scrollback = 100; + terminal.buffers = new BufferSet(terminal); + terminal.buffer = terminal.buffers.active; selectionManager = new TestSelectionManager(terminal, buffer, rowContainer, null); +======= + beforeEach(done => { + jsdom.env('', (err, w) => { + window = w; + document = window.document; + buffer = new CircularList(100); + terminal = { cols: 80, rows: 2 }; + terminal.scrollback = 10; + terminal.buffers = new BufferSet(terminal); + terminal.buffer = terminal.buffers.active; + + selectionManager = new TestSelectionManager(terminal, buffer, rowContainer, null); + done(); + }); +>>>>>>> Fix some tests and docs, little code fix up. }); function stringToRow(text: string): [number, string, number][] { diff --git a/src/SelectionModel.test.ts b/src/SelectionModel.test.ts index ab22b77cc5..6da3874bd4 100644 --- a/src/SelectionModel.test.ts +++ b/src/SelectionModel.test.ts @@ -4,6 +4,7 @@ import { assert } from 'chai'; import { ITerminal } from './Interfaces'; import { SelectionModel } from './SelectionModel'; +import {BufferSet} from './BufferSet'; class TestSelectionModel extends SelectionModel { constructor( @@ -22,6 +23,10 @@ describe('SelectionManager', () => { beforeEach(() => { terminal = { cols: 80, rows: 2, ybase: 0 }; + terminal.scrollback = 10; + terminal.buffers = new BufferSet(terminal); + terminal.buffer = terminal.buffers.active; + model = new TestSelectionModel(terminal); }); diff --git a/src/Viewport.test.ts b/src/Viewport.test.ts index 193e7969fd..6d09ea86a2 100644 --- a/src/Viewport.test.ts +++ b/src/Viewport.test.ts @@ -1,10 +1,10 @@ import { assert } from 'chai'; import { Viewport } from './Viewport'; +import {BufferSet} from './BufferSet'; describe('Viewport', () => { let terminal; let viewportElement; - let selectionContainer; let charMeasure; let viewport; let scrollAreaElement; @@ -13,7 +13,6 @@ describe('Viewport', () => { beforeEach(() => { terminal = { - lines: [], rows: 0, ydisp: 0, on: () => {}, @@ -26,8 +25,11 @@ describe('Viewport', () => { style: { height: 0 } - } + }, + scrollback: 10 }; + terminal.buffers = new BufferSet(terminal); + terminal.buffer = terminal.buffers.active; viewportElement = { addEventListener: () => {}, style: { @@ -60,14 +62,14 @@ describe('Viewport', () => { }, 0); }); it('should set the height of the viewport when the line-height changed', () => { - terminal.lines.push(''); - terminal.lines.push(''); + terminal.buffer.lines.push(''); + terminal.buffer.lines.push(''); terminal.rows = 1; viewport.refresh(); assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px'); - charMeasure.height = 20; + charMeasure.height = 2 * CHARACTER_HEIGHT; viewport.refresh(); - assert.equal(viewportElement.style.height, 20 + 'px'); + assert.equal(viewportElement.style.height, 2 * CHARACTER_HEIGHT + 'px'); }); }); @@ -75,13 +77,13 @@ describe('Viewport', () => { it('should sync the scroll area', done => { // Allow CharMeasure to be initialized setTimeout(() => { - terminal.lines.push(''); + terminal.buffer.lines.push(''); terminal.rows = 1; assert.equal(scrollAreaElement.style.height, 0 * CHARACTER_HEIGHT + 'px'); viewport.syncScrollArea(); assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px'); assert.equal(scrollAreaElement.style.height, 1 * CHARACTER_HEIGHT + 'px'); - terminal.lines.push(''); + terminal.buffer.lines.push(''); viewport.syncScrollArea(); assert.equal(viewportElement.style.height, 1 * CHARACTER_HEIGHT + 'px'); assert.equal(scrollAreaElement.style.height, 2 * CHARACTER_HEIGHT + 'px'); diff --git a/src/Viewport.ts b/src/Viewport.ts index 81ecca1b9a..fe276935bb 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -20,7 +20,7 @@ export class Viewport { * @param terminal The terminal this viewport belongs to. * @param viewportElement The DOM element acting as the viewport. * @param scrollArea The DOM element acting as the scroll area. - * @param charMeasureElement A DOM element used to measure the character size of. the terminal. + * @param charMeasure A DOM element used to measure the character size of. the terminal. */ constructor( private terminal: ITerminal, @@ -43,8 +43,6 @@ export class Viewport { /** * Refreshes row height, setting line-height, viewport height and scroll area height if * necessary. - * @param charSize A character size measurement bounding rect object, if it doesn't exist it will - * be created. */ private refresh(): void { if (this.charMeasure.height > 0) { diff --git a/src/xterm.js b/src/xterm.js index 6460ca9042..a0cd9fd223 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -415,7 +415,7 @@ Terminal.prototype.setOption = function(key, value) { } if (this.options[key] !== value) { - if (this.buffer.length > value) { + if (this.buffer.lines.length > value) { const amountToTrim = this.buffer.lines.length - value; const needsRefresh = (this.buffer.ydisp - amountToTrim < 0); this.buffer.lines.trimStart(amountToTrim); @@ -498,7 +498,7 @@ Terminal.prototype.blur = function() { */ Terminal.bindBlur = function (term) { on(term.textarea, 'blur', function (ev) { - term.refresh(term.y, term.y); + term.refresh(term.buffer.y, term.buffer.y); if (term.sendFocus) { term.send(C0.ESC + '[O'); } From 6f63705f7cd26c115014d1ff8631c0d2679fc62d Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Fri, 30 Jun 2017 14:04:03 +0300 Subject: [PATCH 12/26] Add `buffers` to the `ITerminal` --- src/Interfaces.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Interfaces.ts b/src/Interfaces.ts index 2dafd909ae..b41a7d1a69 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -33,6 +33,7 @@ export interface ITerminal { cursorState: number; defAttr: number; scrollback: number; + buffers: any; // This should be a `BufferSet` class, but it would result in circular dependency 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 From 9ead7fa65f35a4ccd8793a8f2134fb39c7c9361f Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 9 Jul 2017 10:14:55 +0300 Subject: [PATCH 13/26] Fix CircularList type and a typo --- package-lock.json | 489 +++++++++++++++++++++++++++++++++++++++++++- src/Buffer.ts | 2 +- src/InputHandler.ts | 2 +- 3 files changed, 490 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 73745a3265..274c5c54b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "xterm", - "version": "2.8.0", + "version": "2.8.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -86,6 +86,12 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "dev": true + }, "array-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", @@ -103,6 +109,12 @@ "integrity": "sha1-5zA08A3MH0CHYAj9IP6ud71LfC8=", "dev": true }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, "asn1": { "version": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", @@ -137,6 +149,12 @@ "tweetnacl": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" } }, + "beeper": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", + "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", + "dev": true + }, "boom": { "version": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", @@ -1266,6 +1284,18 @@ "supports-color": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" } }, + "clone": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", + "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=", + "dev": true + }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "dev": true + }, "combined-stream": { "version": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", @@ -1295,6 +1325,12 @@ "is-plain-object": "2.0.3" } }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, "cross-spawn-async": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz", @@ -1374,6 +1410,12 @@ } } }, + "dateformat": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.0.0.tgz", + "integrity": "sha1-J0Pjq7XD/CRi5SfcpEXgTp9N7hc=", + "dev": true + }, "deep-is": { "version": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", @@ -1390,6 +1432,15 @@ "integrity": "sha1-BcOlDYMYmYFpnuDAdtOjlQ237AA=", "dev": true }, + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "dev": true, + "requires": { + "readable-stream": "1.1.14" + } + }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -1878,6 +1929,73 @@ "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", "dev": true }, + "fancy-log": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.0.tgz", + "integrity": "sha1-Rb4X0Cu5kX1gzP/UmVyZnmyMmUg=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "time-stamp": "1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, "fast-levenshtein": { "version": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", @@ -2059,6 +2177,15 @@ } } }, + "glogg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz", + "integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=", + "dev": true, + "requires": { + "sparkles": "1.0.0" + } + }, "graceful-readlink": { "version": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", @@ -8629,6 +8756,98 @@ } } }, + "gulp-util": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", + "dev": true, + "requires": { + "array-differ": "1.0.0", + "array-uniq": "1.0.3", + "beeper": "1.1.1", + "chalk": "1.1.3", + "dateformat": "2.0.0", + "fancy-log": "1.3.0", + "gulplog": "1.0.0", + "has-gulplog": "0.1.0", + "lodash._reescape": "3.0.0", + "lodash._reevaluate": "3.0.0", + "lodash._reinterpolate": "3.0.0", + "lodash.template": "3.6.2", + "minimist": "1.2.0", + "multipipe": "0.1.2", + "object-assign": "3.0.0", + "replace-ext": "0.0.1", + "through2": "2.0.3", + "vinyl": "0.5.3" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "dev": true, + "requires": { + "glogg": "1.0.0" + } + }, "har-validator": { "version": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", @@ -8658,6 +8877,15 @@ "ansi-regex": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" } }, + "has-gulplog": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", + "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "dev": true, + "requires": { + "sparkles": "1.0.0" + } + }, "hash-base": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", @@ -8755,6 +8983,12 @@ "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", "dev": true }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, "is-my-json-valid": { "version": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz", "integrity": "sha1-k27do8o8IR/ZjzstPgjaQ/eykVs=", @@ -8793,6 +9027,12 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, "isstream": { "version": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", @@ -9073,11 +9313,130 @@ "type-check": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" } }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basetostring": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", + "dev": true + }, + "lodash._basevalues": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash._reescape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", + "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", + "dev": true + }, + "lodash._reevaluate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", + "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", + "dev": true + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", + "dev": true + }, + "lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "dev": true, + "requires": { + "lodash._root": "3.0.1" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "lodash.restparam": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "dev": true + }, "lodash.sortby": { "version": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, + "lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash._basetostring": "3.0.1", + "lodash._basevalues": "3.0.0", + "lodash._isiterateecall": "3.0.9", + "lodash._reinterpolate": "3.0.0", + "lodash.escape": "3.2.0", + "lodash.keys": "3.1.2", + "lodash.restparam": "3.6.1", + "lodash.templatesettings": "3.1.1" + } + }, + "lodash.templatesettings": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "dev": true, + "requires": { + "lodash._reinterpolate": "3.0.0", + "lodash.escape": "3.2.0" + } + }, "make-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.0.0.tgz", @@ -9171,6 +9530,12 @@ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", "dev": true }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, "mocha": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.4.2.tgz", @@ -9438,6 +9803,15 @@ } } }, + "multipipe": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", + "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "dev": true, + "requires": { + "duplexer2": "0.0.2" + } + }, "node-pty": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-0.4.1.tgz", @@ -10630,6 +11004,12 @@ "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", "dev": true }, + "object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", + "dev": true + }, "object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", @@ -10753,6 +11133,12 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -10764,12 +11150,30 @@ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, "remove-trailing-separator": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=", "dev": true }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "dev": true + }, "request": { "version": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", @@ -10964,6 +11368,12 @@ } } }, + "sparkles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz", + "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=", + "dev": true + }, "sshpk": { "version": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.2.tgz", "integrity": "sha1-1agEziJpVRVjjnmNviMnPeBwpfo=", @@ -10993,6 +11403,12 @@ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "dev": true }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, "stringstream": { "version": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", @@ -11031,6 +11447,60 @@ "execa": "0.4.0" } }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, + "requires": { + "readable-stream": "2.3.3", + "xtend": "4.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + } + } + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true + }, "tough-cookie": { "version": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", @@ -11692,6 +12162,12 @@ "crypto-random-string": "1.0.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, "verror": { "version": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", @@ -11700,6 +12176,17 @@ "extsprintf": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz" } }, + "vinyl": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", + "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "dev": true, + "requires": { + "clone": "1.0.2", + "clone-stats": "0.0.1", + "replace-ext": "0.0.1" + } + }, "vinyl-buffer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/vinyl-buffer/-/vinyl-buffer-1.0.0.tgz", diff --git a/src/Buffer.ts b/src/Buffer.ts index a3e45d25c6..65e1d99d87 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -29,7 +29,7 @@ export class Buffer { public scrollTop: number = 0, public tabs: any = {}, ) { - this.lines = new CircularList(this.terminal.scrollback); + this.lines = new CircularList<[string, number, string]>(this.terminal.scrollback); this.scrollBottom = this.terminal.rows - 1; } } diff --git a/src/InputHandler.ts b/src/InputHandler.ts index c9b58446be..3900d56e56 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -906,7 +906,7 @@ export class InputHandler implements IInputHandler { // TODO: Why are params[0] compares nested within a switch for params[0]? - this._terminal.buffer.x10Mouse = params[0] === 9; + this._terminal.x10Mouse = params[0] === 9; this._terminal.vt200Mouse = params[0] === 1000; this._terminal.normalMouse = params[0] > 1000; this._terminal.mouseEvents = true; From 5f3bed75b2689edf17921f1189b596a1e05034a7 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 9 Jul 2017 10:29:32 +0300 Subject: [PATCH 14/26] Fix SelectionManager tests --- src/SelectionManager.test.ts | 43 ++++++++++++------------------------ 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/src/SelectionManager.test.ts b/src/SelectionManager.test.ts index 12784e02b0..e9981fce74 100644 --- a/src/SelectionManager.test.ts +++ b/src/SelectionManager.test.ts @@ -37,11 +37,10 @@ describe('SelectionManager', () => { let document: Document; let terminal: ITerminal; - let buffer: CircularList; + let bufferLines: CircularList; let rowContainer: HTMLElement; let selectionManager: TestSelectionManager; -<<<<<<< HEAD beforeEach(() => { dom = new jsdom.JSDOM(''); window = dom.window; @@ -50,22 +49,8 @@ describe('SelectionManager', () => { terminal.scrollback = 100; terminal.buffers = new BufferSet(terminal); terminal.buffer = terminal.buffers.active; - selectionManager = new TestSelectionManager(terminal, buffer, rowContainer, null); -======= - beforeEach(done => { - jsdom.env('', (err, w) => { - window = w; - document = window.document; - buffer = new CircularList(100); - terminal = { cols: 80, rows: 2 }; - terminal.scrollback = 10; - terminal.buffers = new BufferSet(terminal); - terminal.buffer = terminal.buffers.active; - - selectionManager = new TestSelectionManager(terminal, buffer, rowContainer, null); - done(); - }); ->>>>>>> Fix some tests and docs, little code fix up. + bufferLines = terminal.buffer.lines + selectionManager = new TestSelectionManager(terminal, bufferLines, rowContainer, null); }); function stringToRow(text: string): [number, string, number][] { @@ -78,7 +63,7 @@ describe('SelectionManager', () => { describe('_selectWordAt', () => { it('should expand selection for normal width chars', () => { - buffer.push(stringToRow('foo bar')); + bufferLines.push(stringToRow('foo bar')); selectionManager.selectWordAt([0, 0]); assert.equal(selectionManager.selectionText, 'foo'); selectionManager.selectWordAt([1, 0]); @@ -95,7 +80,7 @@ describe('SelectionManager', () => { assert.equal(selectionManager.selectionText, 'bar'); }); it('should expand selection for whitespace', () => { - buffer.push(stringToRow('a b')); + bufferLines.push(stringToRow('a b')); selectionManager.selectWordAt([0, 0]); assert.equal(selectionManager.selectionText, 'a'); selectionManager.selectWordAt([1, 0]); @@ -109,7 +94,7 @@ describe('SelectionManager', () => { }); it('should expand selection for wide characters', () => { // Wide characters use a special format - buffer.push([ + bufferLines.push([ [null, '中', 2], [null, '', 0], [null, '文', 2], @@ -161,7 +146,7 @@ describe('SelectionManager', () => { assert.equal(selectionManager.selectionText, 'foo'); }); it('should select up to non-path characters that are commonly adjacent to paths', () => { - buffer.push(stringToRow('(cd)[ef]{gh}\'ij"')); + bufferLines.push(stringToRow('(cd)[ef]{gh}\'ij"')); selectionManager.selectWordAt([0, 0]); assert.equal(selectionManager.selectionText, '(cd'); selectionManager.selectWordAt([1, 0]); @@ -199,7 +184,7 @@ describe('SelectionManager', () => { describe('_selectLineAt', () => { it('should select the entire line', () => { - buffer.push(stringToRow('foo bar')); + bufferLines.push(stringToRow('foo bar')); selectionManager.selectLineAt(0); assert.equal(selectionManager.selectionText, 'foo bar', 'The selected text is correct'); assert.deepEqual(selectionManager.model.finalSelectionStart, [0, 0]); @@ -209,13 +194,13 @@ describe('SelectionManager', () => { describe('selectAll', () => { it('should select the entire buffer, beyond the viewport', () => { - buffer.push(stringToRow('1')); - buffer.push(stringToRow('2')); - buffer.push(stringToRow('3')); - buffer.push(stringToRow('4')); - buffer.push(stringToRow('5')); + bufferLines.push(stringToRow('1')); + bufferLines.push(stringToRow('2')); + bufferLines.push(stringToRow('3')); + bufferLines.push(stringToRow('4')); + bufferLines.push(stringToRow('5')); selectionManager.selectAll(); - terminal.buffer.ybase = buffer.length - terminal.rows; + terminal.buffer.ybase = bufferLines.length - terminal.rows; assert.equal(selectionManager.selectionText, '1\n2\n3\n4\n5'); }); }); From 20e03cd5cbbfa7237d312a03cb7bb9f7e6bef955 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 9 Jul 2017 11:06:10 +0300 Subject: [PATCH 15/26] Correct references to buffer lines --- src/Buffer.ts | 2 +- src/test/escape-sequences-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Buffer.ts b/src/Buffer.ts index 65e1d99d87..51ee0f18cd 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -9,7 +9,7 @@ import { CircularList } from './utils/CircularList'; * This class represents a terminal buffer (an internal state of the terminal)/ */ export class Buffer { - public lines: CircularList; + public lines: CircularList<[string, number, string]>; /** * Create a new Buffer. diff --git a/src/test/escape-sequences-test.js b/src/test/escape-sequences-test.js index c3831580dc..098b5c5b4e 100644 --- a/src/test/escape-sequences-test.js +++ b/src/test/escape-sequences-test.js @@ -65,7 +65,7 @@ function terminalToString(term) { for (var line = term.ybase; line < term.ybase + term.rows; line++) { line_s = ''; for (var cell=0; cell Date: Sun, 9 Jul 2017 11:16:27 +0300 Subject: [PATCH 16/26] Add semicolons --- src/SelectionManager.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SelectionManager.test.ts b/src/SelectionManager.test.ts index e9981fce74..f710ecc0e4 100644 --- a/src/SelectionManager.test.ts +++ b/src/SelectionManager.test.ts @@ -44,12 +44,12 @@ describe('SelectionManager', () => { beforeEach(() => { dom = new jsdom.JSDOM(''); window = dom.window; - document = window.document + document = window.document; terminal = { cols: 80, rows: 2 }; terminal.scrollback = 100; terminal.buffers = new BufferSet(terminal); terminal.buffer = terminal.buffers.active; - bufferLines = terminal.buffer.lines + bufferLines = terminal.buffer.lines; selectionManager = new TestSelectionManager(terminal, bufferLines, rowContainer, null); }); From e15134db516d37947f4986955cf9276c7ed3f3e9 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 9 Jul 2017 14:33:56 +0300 Subject: [PATCH 17/26] Fix reference to `terminal.buffer.lines` --- src/InputHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 3900d56e56..d8e942d365 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -61,7 +61,7 @@ export class InputHandler implements IInputHandler { } else { // The line already exists (eg. the initial viewport), mark it as a // wrapped line - this._terminal.lines.get(this._terminal.y).isWrapped = true; + this._terminal.buffer.lines.get(this._terminal.buffer.y).isWrapped = true; } } else { if (ch_width === 2) // FIXME: check for xterm behavior From f8bea9d4b664a0db56e1561aa93cdcca68868b41 Mon Sep 17 00:00:00 2001 From: Aleksandr Andriienko Date: Wed, 12 Jul 2017 18:31:09 +0300 Subject: [PATCH 18/26] Fix regression. Existing tests work again. Signed-off-by: Aleksandr Andriienko --- src/InputHandler.ts | 2 +- src/test/escape-sequences-test.js | 2 +- src/xterm.js | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/InputHandler.ts b/src/InputHandler.ts index d8e942d365..f41297fca1 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -1084,7 +1084,7 @@ export class InputHandler implements IInputHandler { case 1000: // vt200 mouse case 1002: // button event mouse case 1003: // any event mouse - this._terminal.buffer.x10Mouse = false; + this._terminal.x10Mouse = false; this._terminal.vt200Mouse = false; this._terminal.normalMouse = false; this._terminal.mouseEvents = false; diff --git a/src/test/escape-sequences-test.js b/src/test/escape-sequences-test.js index 098b5c5b4e..b4a53a17c3 100644 --- a/src/test/escape-sequences-test.js +++ b/src/test/escape-sequences-test.js @@ -62,7 +62,7 @@ function formatError(in_, out_, expected) { function terminalToString(term) { var result = ''; var line_s = ''; - for (var line = term.ybase; line < term.ybase + term.rows; line++) { + for (var line = term.buffer.ybase; line < term.buffer.ybase + term.rows; line++) { line_s = ''; for (var cell=0; cell Date: Fri, 14 Jul 2017 09:55:20 +0300 Subject: [PATCH 19/26] Fix variable name --- src/xterm.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xterm.js b/src/xterm.js index 4e87379089..469f1e0ba0 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -2299,12 +2299,12 @@ Terminal.prototype.reset = function() { var customKeyEventHandler = this.customKeyEventHandler; var cursorBlinkInterval = this.cursorBlinkInterval; var inputHandler = this.inputHandler; - var buf = this.buffers; + var buffers = this.buffers; Terminal.call(this, this.options); this.customKeyEventHandler = customKeyEventHandler; this.cursorBlinkInterval = cursorBlinkInterval; this.inputHandler = inputHandler; - this.buffers = buf; + this.buffers = buffers; this.refresh(0, this.rows - 1); this.viewport.syncScrollArea(); }; From f840997a4101dac3796f322432c1566b7ff71bfb Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Fri, 14 Jul 2017 10:07:33 +0300 Subject: [PATCH 20/26] Improve documentation of `Buffer` and `BufferSet` classes --- src/Buffer.ts | 12 ++++++++---- src/BufferSet.ts | 30 ++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/Buffer.ts b/src/Buffer.ts index 51ee0f18cd..256f6c903f 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -6,16 +6,20 @@ import { ITerminal } from './Interfaces'; import { CircularList } from './utils/CircularList'; /** - * This class represents a terminal buffer (an internal state of the terminal)/ + * This class represents a terminal buffer (an internal state of the terminal), where the + * following information is stored (in high-level): + * - text content of this particular buffer + * - cursor position + * - scroll position */ export class Buffer { public lines: CircularList<[string, number, string]>; /** * 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 {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 */ diff --git a/src/BufferSet.ts b/src/BufferSet.ts index c9022a9ced..d4a471aba2 100644 --- a/src/BufferSet.ts +++ b/src/BufferSet.ts @@ -6,11 +6,19 @@ import { ITerminal } from './Interfaces'; import { Buffer } from './Buffer'; import { EventEmitter } from './EventEmitter'; +/** + * The BufferSet represents the set of two buffers used by xterm terminals (normal and alt) and + * provides also utilities for working with them. + */ export class BufferSet extends EventEmitter { private _normal: Buffer; private _alt: Buffer; private _activeBuffer: Buffer; + /** + * Create a new BufferSet for the given terminal. + * @param {Terminal} terminal - The terminal the BufferSet will belong to + */ constructor(private _terminal: ITerminal) { super(); this._normal = new Buffer(this._terminal); @@ -18,25 +26,43 @@ export class BufferSet extends EventEmitter { this._activeBuffer = this._normal; } + /** + * Returns the alt Buffer of the BufferSet + * @returns {Buffer} + */ public get alt(): Buffer { return this._alt; } + /** + * Returns the normal Buffer of the BufferSet + * @returns {Buffer} + */ public get active(): Buffer { return this._activeBuffer; } + /** + * Returns the currently active Buffer of the BufferSet + * @returns {Buffer} + */ public get normal(): Buffer { return this._normal; } + /** + * Sets the normal Buffer of the BufferSet as its currently active Buffer + */ public activateNormalBuffer(): void { this._activeBuffer = this._normal; - this.emit('activate', this._normal); // todo maybe simpler this._terminal.buffer = this._terminal.buffers.normal than using EventEmitter? + this.emit('activate', this._normal); } + /** + * Sets the alt Buffer of the BufferSet as its currently active Buffer + */ public activateAltBuffer(): void { this._activeBuffer = this._alt; - this.emit('activate', this._alt); // todo maybe simpler this._terminal.buffer = this._terminal.buffers.alt than using EventEmitter? + this.emit('activate', this._alt); } } From 1a2e3fb9c02a4c32df3745b41e4ee71d33eb2f3b Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sat, 15 Jul 2017 11:40:20 +0300 Subject: [PATCH 21/26] Implement tests for `Buffer` and `BufferSet` --- src/Buffer.test.ts | 31 +++++++++++++++++++++++ src/BufferSet.test.ts | 49 ++++++++++++++++++++++++++++++++++++ src/SelectionManager.test.ts | 2 +- 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/Buffer.test.ts create mode 100644 src/BufferSet.test.ts diff --git a/src/Buffer.test.ts b/src/Buffer.test.ts new file mode 100644 index 0000000000..f68baa82ac --- /dev/null +++ b/src/Buffer.test.ts @@ -0,0 +1,31 @@ +/** + * @license MIT + */ +import { assert } from 'chai'; +import { ITerminal } from './Interfaces'; +import { Buffer } from './Buffer'; +import { CircularList } from './utils/CircularList'; + +describe('Buffer', () => { + let terminal: ITerminal; + let buffer: Buffer; + + beforeEach(() => { + terminal = { + cols: 80, + rows: 24, + scrollback: 1000 + }; + buffer = new Buffer(terminal); + }); + + describe('constructor', () => { + it('should create a CircularList with max length equal to scrollback, for its lines', () => { + assert.instanceOf(buffer.lines, CircularList); + assert.equal(buffer.lines.maxLength, terminal.scrollback); + }); + it('should set the Buffer\'s scrollBottom value equal to the terminal\'s rows -1', () => { + assert.equal(buffer.scrollBottom, terminal.rows - 1); + }); + }); +}); diff --git a/src/BufferSet.test.ts b/src/BufferSet.test.ts new file mode 100644 index 0000000000..2101fbc1f4 --- /dev/null +++ b/src/BufferSet.test.ts @@ -0,0 +1,49 @@ +/** + * @license MIT + */ +import { assert } from 'chai'; +import { ITerminal } from './Interfaces'; +import { BufferSet } from './BufferSet'; +import { Buffer } from './Buffer'; + +describe('BufferSet', () => { + let terminal: ITerminal; + let bufferSet: BufferSet; + + beforeEach(() => { + terminal = { + cols: 80, + rows: 24, + scrollback: 1000 + }; + bufferSet = new BufferSet(terminal); + }); + + describe('constructor', () => { + it('should create two different buffers: alt and normal', () => { + assert.instanceOf(bufferSet.normal, Buffer); + assert.instanceOf(bufferSet.alt, Buffer); + assert.notEqual(bufferSet.normal, bufferSet.alt); + }); + }); + + describe('activateNormalBuffer', () => { + beforeEach(() => { + bufferSet.activateNormalBuffer(); + }); + + it('should set the normal buffer as the currently active buffer', () => { + assert.equal(bufferSet.active, bufferSet.normal); + }); + }); + + describe('activateAltBuffer', () => { + beforeEach(() => { + bufferSet.activateAltBuffer(); + }); + + it('should set the alt buffer as the currently active buffer', () => { + assert.equal(bufferSet.active, bufferSet.alt); + }); + }); +}); diff --git a/src/SelectionManager.test.ts b/src/SelectionManager.test.ts index f710ecc0e4..66d692ddd6 100644 --- a/src/SelectionManager.test.ts +++ b/src/SelectionManager.test.ts @@ -8,7 +8,7 @@ import { CharMeasure } from './utils/CharMeasure'; import { CircularList } from './utils/CircularList'; import { SelectionManager } from './SelectionManager'; import { SelectionModel } from './SelectionModel'; -import {BufferSet} from './BufferSet'; +import { BufferSet } from './BufferSet'; class TestSelectionManager extends SelectionManager { constructor( From c27431b82d73750a920e89781d493d34d7eab527 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 15 Jul 2017 10:33:49 -0700 Subject: [PATCH 22/26] Add IBuffer, IBufferSet and fix CircularList type --- src/Buffer.ts | 4 ++-- src/BufferSet.ts | 4 ++-- src/EventEmitter.ts | 4 +++- src/Interfaces.ts | 30 ++++++++++++++++++++++++++---- src/SelectionManager.test.ts | 6 +++--- src/SelectionManager.ts | 10 +++++----- 6 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/Buffer.ts b/src/Buffer.ts index 256f6c903f..93af3c460f 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -13,7 +13,7 @@ import { CircularList } from './utils/CircularList'; * - scroll position */ export class Buffer { - public lines: CircularList<[string, number, string]>; + public lines: CircularList<[number, string, number][]>; /** * Create a new Buffer. @@ -33,7 +33,7 @@ export class Buffer { public scrollTop: number = 0, public tabs: any = {}, ) { - this.lines = new CircularList<[string, number, string]>(this.terminal.scrollback); + this.lines = new CircularList<[number, string, number][]>(this.terminal.scrollback); this.scrollBottom = this.terminal.rows - 1; } } diff --git a/src/BufferSet.ts b/src/BufferSet.ts index d4a471aba2..e86c098f5f 100644 --- a/src/BufferSet.ts +++ b/src/BufferSet.ts @@ -2,7 +2,7 @@ * @license MIT */ -import { ITerminal } from './Interfaces'; +import { ITerminal, IBufferSet } from './Interfaces'; import { Buffer } from './Buffer'; import { EventEmitter } from './EventEmitter'; @@ -10,7 +10,7 @@ import { EventEmitter } from './EventEmitter'; * The BufferSet represents the set of two buffers used by xterm terminals (normal and alt) and * provides also utilities for working with them. */ -export class BufferSet extends EventEmitter { +export class BufferSet extends EventEmitter implements IBufferSet { private _normal: Buffer; private _alt: Buffer; private _activeBuffer: Buffer; diff --git a/src/EventEmitter.ts b/src/EventEmitter.ts index a4fd4542c3..00c1094186 100644 --- a/src/EventEmitter.ts +++ b/src/EventEmitter.ts @@ -2,12 +2,14 @@ * @license MIT */ +import { IEventEmitter } from './Interfaces'; + interface ListenerType { (): void; listener?: () => void; }; -export class EventEmitter { +export class EventEmitter implements IEventEmitter { private _events: {[type: string]: ListenerType[]}; constructor() { diff --git a/src/Interfaces.ts b/src/Interfaces.ts index b41a7d1a69..f19a7f28f8 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -33,9 +33,8 @@ export interface ITerminal { cursorState: number; defAttr: number; scrollback: number; - buffers: any; // This should be a `BufferSet` class, but it would result in circular dependency - 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 + buffers: IBufferSet; + buffer: IBuffer; /** * Emit the 'data' event and populate the given data. @@ -51,6 +50,24 @@ export interface ITerminal { showCursor(): void; } +export interface IBuffer { + lines: ICircularList<[number, string, number][]>; + ydisp: number; + ybase: number; + y: number; + x: number; + tabs: any; +} + +export interface IBufferSet { + alt: IBuffer; + normal: IBuffer; + active: IBuffer; + + activateNormalBuffer(): void; + activateAltBuffer(): void; +} + export interface ISelectionManager { selectionText: string; selectionStart: [number, number]; @@ -72,7 +89,7 @@ export interface ILinkifier { deregisterLinkMatcher(matcherId: number): boolean; } -interface ICircularList { +export interface ICircularList extends IEventEmitter { length: number; maxLength: number; @@ -86,6 +103,11 @@ interface ICircularList { shiftElements(start: number, count: number, offset: number): void; } +export interface IEventEmitter { + on(type, listener): void; + off(type, listener): void; +} + export interface LinkMatcherOptions { /** * The index of the link from the regex.match(text) call. This defaults to 0 diff --git a/src/SelectionManager.test.ts b/src/SelectionManager.test.ts index 66d692ddd6..668fd92eb5 100644 --- a/src/SelectionManager.test.ts +++ b/src/SelectionManager.test.ts @@ -3,7 +3,7 @@ */ import jsdom = require('jsdom'); import { assert } from 'chai'; -import { ITerminal } from './Interfaces'; +import { ITerminal, ICircularList } from './Interfaces'; import { CharMeasure } from './utils/CharMeasure'; import { CircularList } from './utils/CircularList'; import { SelectionManager } from './SelectionManager'; @@ -13,7 +13,7 @@ import { BufferSet } from './BufferSet'; class TestSelectionManager extends SelectionManager { constructor( terminal: ITerminal, - buffer: CircularList, + buffer: ICircularList<[number, string, number][]>, rowContainer: HTMLElement, charMeasure: CharMeasure ) { @@ -37,7 +37,7 @@ describe('SelectionManager', () => { let document: Document; let terminal: ITerminal; - let bufferLines: CircularList; + let bufferLines: ICircularList<[number, string, number][]>; let rowContainer: HTMLElement; let selectionManager: TestSelectionManager; diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index 58b37b9a6e..5a86a2b9cf 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -7,7 +7,7 @@ import * as Browser from './utils/Browser'; import { CharMeasure } from './utils/CharMeasure'; import { CircularList } from './utils/CircularList'; import { EventEmitter } from './EventEmitter'; -import { ITerminal } from './Interfaces'; +import { ITerminal, ICircularList } from './Interfaces'; import { SelectionModel } from './SelectionModel'; import { translateBufferLineToString } from './utils/BufferLine'; @@ -98,7 +98,7 @@ export class SelectionManager extends EventEmitter { constructor( private _terminal: ITerminal, - private _buffer: CircularList, + private _buffer: ICircularList<[number, string, number][]>, private _rowContainer: HTMLElement, private _charMeasure: CharMeasure ) { @@ -147,7 +147,7 @@ export class SelectionManager extends EventEmitter { * switched in or out. * @param buffer The active buffer. */ - public setBuffer(buffer: CircularList): void { + public setBuffer(buffer: ICircularList<[number, string, number][]>): void { this._buffer = buffer; this.clearSelection(); } @@ -186,7 +186,7 @@ export class SelectionManager extends EventEmitter { for (let i = start[1] + 1; i <= end[1] - 1; i++) { const bufferLine = this._buffer.get(i); const lineText = translateBufferLineToString(bufferLine, true); - if (bufferLine.isWrapped) { + if ((bufferLine).isWrapped) { result[result.length - 1] += lineText; } else { result.push(lineText); @@ -197,7 +197,7 @@ export class SelectionManager extends EventEmitter { if (start[1] !== end[1]) { const bufferLine = this._buffer.get(end[1]); const lineText = translateBufferLineToString(bufferLine, true, 0, end[0]); - if (bufferLine.isWrapped) { + if ((bufferLine).isWrapped) { result[result.length - 1] += lineText; } else { result.push(lineText); From e1903c6e40191c5412142f694d76cabb92423205 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 16 Jul 2017 00:55:02 +0300 Subject: [PATCH 23/26] Remove redundant comment --- src/xterm.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/xterm.js b/src/xterm.js index 469f1e0ba0..b1f20694e1 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -227,10 +227,6 @@ function Terminal(options) { this._terminal.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. - */ var i = this.rows; while (i--) { From 6d002ca346f739c9a9f0491540f89b1207dc40f2 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 16 Jul 2017 03:17:29 +0300 Subject: [PATCH 24/26] Rearrange dependencies --- package-lock.json | 17 ----------------- package.json | 6 +++--- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 274c5c54b0..98ea098961 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11252,23 +11252,6 @@ "integrity": "sha1-/YYxojvHgmvvXYcb24c3jJVkeCg=", "dev": true }, - "sleep": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sleep/-/sleep-3.0.1.tgz", - "integrity": "sha1-vk0XxXk2DgfgTtgXK6KxCmkFTfM=", - "dev": true, - "requires": { - "nan": "2.6.2" - }, - "dependencies": { - "nan": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", - "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=", - "dev": true - } - } - }, "sntp": { "version": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", diff --git a/package.json b/package.json index 065925b3a3..917d35e4d9 100644 --- a/package.json +++ b/package.json @@ -46,13 +46,14 @@ "express-ws": "2.0.0-rc.1", "fs-extra": "^1.0.0", "glob": "^7.0.5", - "gulp": "^3.9.1", + "gulp": "3.9.1", "gulp-cli": "^1.2.2", "gulp-coveralls": "^0.1.4", "gulp-istanbul": "^1.1.1", "gulp-mocha": "^3.0.1", "gulp-sourcemaps": "1.9.1", "gulp-typescript": "^3.1.3", + "gulp-util": "3.0.8", "jsdoc": "3.4.3", "jsdom": "^11.1.0", "merge-stream": "^1.0.1", @@ -62,8 +63,7 @@ "tslint": "^4.0.2", "typescript": "~2.2.0", "vinyl-buffer": "^1.0.0", - "vinyl-source-stream": "^1.1.0", - "gulp-util": "^3.0.8" + "vinyl-source-stream": "^1.1.0" }, "scripts": { "prestart": "npm run build", From 1fca4f0f321e9da4d090814d2ee143c691946eb5 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 16 Jul 2017 03:23:18 +0300 Subject: [PATCH 25/26] Update build dir --- gulpfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gulpfile.js b/gulpfile.js index ef4e460998..afb7df4816 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -59,7 +59,7 @@ gulp.task('browserify', ['tsc'], function() { let browserifyOptions = { basedir: buildDir, debug: true, - entries: [`${outDir}/xterm.js`], + entries: [`../${outDir}/xterm.js`], standalone: 'Terminal', cache: {}, packageCache: {} From 4cefa34162652e84f86bce7e9c81b2a48ab1b4b2 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Sun, 16 Jul 2017 03:25:31 +0300 Subject: [PATCH 26/26] Install npm 5.1.0 --- .travis.yml | 1 + gulpfile.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8297ec37f5..1878c3a4d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ before_install: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq install g++-4.8 ; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export CXX=g++-4.8 ; fi + - npm install -g npm@5.1.0 env: matrix: - NPM_COMMAND=lint diff --git a/gulpfile.js b/gulpfile.js index afb7df4816..ef4e460998 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -59,7 +59,7 @@ gulp.task('browserify', ['tsc'], function() { let browserifyOptions = { basedir: buildDir, debug: true, - entries: [`../${outDir}/xterm.js`], + entries: [`${outDir}/xterm.js`], standalone: 'Terminal', cache: {}, packageCache: {}