Comparing version 2.9.0 to 2.9.1
{ | ||
"name": "xterm.js", | ||
"version": "2.9.0", | ||
"version": "2.9.1", | ||
"ignore": ["demo", "test", ".gitignore"], | ||
@@ -5,0 +5,0 @@ "main": [ |
@@ -9,4 +9,3 @@ "use strict"; | ||
else if (typeof exports === 'object' && typeof module === 'object') { | ||
var xterm = '../../xterm'; | ||
module.exports = addon(require(xterm)); | ||
module.exports = addon(require('../../xterm')); | ||
} | ||
@@ -13,0 +12,0 @@ else if (typeof define == 'function') { |
@@ -5,21 +5,89 @@ "use strict"; | ||
var Buffer = (function () { | ||
function Buffer(terminal, ydisp, ybase, y, x, scrollBottom, scrollTop, tabs) { | ||
if (ydisp === void 0) { ydisp = 0; } | ||
if (ybase === void 0) { ybase = 0; } | ||
if (y === void 0) { y = 0; } | ||
if (x === void 0) { x = 0; } | ||
if (scrollBottom === void 0) { scrollBottom = 0; } | ||
if (scrollTop === void 0) { scrollTop = 0; } | ||
if (tabs === void 0) { tabs = {}; } | ||
this.terminal = terminal; | ||
this.ydisp = ydisp; | ||
this.ybase = ybase; | ||
this.y = y; | ||
this.x = x; | ||
this.scrollBottom = scrollBottom; | ||
this.scrollTop = scrollTop; | ||
this.tabs = tabs; | ||
this.lines = new CircularList_1.CircularList(this.terminal.scrollback); | ||
this.scrollBottom = this.terminal.rows - 1; | ||
function Buffer(_terminal) { | ||
this._terminal = _terminal; | ||
this.clear(); | ||
} | ||
Object.defineProperty(Buffer.prototype, "lines", { | ||
get: function () { | ||
return this._lines; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Buffer.prototype.fillViewportRows = function () { | ||
if (this._lines.length === 0) { | ||
var i = this._terminal.rows; | ||
while (i--) { | ||
this.lines.push(this._terminal.blankLine()); | ||
} | ||
} | ||
}; | ||
Buffer.prototype.clear = function () { | ||
this.ydisp = 0; | ||
this.ybase = 0; | ||
this.y = 0; | ||
this.x = 0; | ||
this.scrollBottom = 0; | ||
this.scrollTop = 0; | ||
this.tabs = {}; | ||
this._lines = new CircularList_1.CircularList(this._terminal.scrollback); | ||
this.scrollBottom = this._terminal.rows - 1; | ||
}; | ||
Buffer.prototype.resize = function (newCols, newRows) { | ||
if (this._lines.length === 0) { | ||
return; | ||
} | ||
if (this._terminal.cols < newCols) { | ||
var ch = [this._terminal.defAttr, ' ', 1]; | ||
for (var i = 0; i < this._lines.length; i++) { | ||
if (this._lines.get(i) === undefined) { | ||
this._lines.set(i, this._terminal.blankLine()); | ||
} | ||
while (this._lines.get(i).length < newCols) { | ||
this._lines.get(i).push(ch); | ||
} | ||
} | ||
} | ||
var addToY = 0; | ||
if (this._terminal.rows < newRows) { | ||
for (var y = this._terminal.rows; y < newRows; y++) { | ||
if (this._lines.length < newRows + this.ybase) { | ||
if (this.ybase > 0 && this._lines.length <= this.ybase + this.y + addToY + 1) { | ||
this.ybase--; | ||
addToY++; | ||
if (this.ydisp > 0) { | ||
this.ydisp--; | ||
} | ||
} | ||
else { | ||
this._lines.push(this._terminal.blankLine()); | ||
} | ||
} | ||
} | ||
} | ||
else { | ||
for (var y = this._terminal.rows; y > newRows; y--) { | ||
if (this._lines.length > newRows + this.ybase) { | ||
if (this._lines.length > this.ybase + this.y + 1) { | ||
this._lines.pop(); | ||
} | ||
else { | ||
this.ybase++; | ||
this.ydisp++; | ||
} | ||
} | ||
} | ||
} | ||
if (this.y >= newRows) { | ||
this.y = newRows - 1; | ||
} | ||
if (addToY) { | ||
this.y += addToY; | ||
} | ||
if (this.x >= newCols) { | ||
this.x = newCols - 1; | ||
} | ||
this.scrollTop = 0; | ||
this.scrollBottom = newRows - 1; | ||
}; | ||
return Buffer; | ||
@@ -26,0 +94,0 @@ }()); |
@@ -6,2 +6,5 @@ "use strict"; | ||
var CircularList_1 = require("./utils/CircularList"); | ||
var TestUtils_1 = require("./utils/TestUtils"); | ||
var INIT_COLS = 80; | ||
var INIT_ROWS = 24; | ||
describe('Buffer', function () { | ||
@@ -11,7 +14,6 @@ var terminal; | ||
beforeEach(function () { | ||
terminal = { | ||
cols: 80, | ||
rows: 24, | ||
scrollback: 1000 | ||
}; | ||
terminal = new TestUtils_1.MockTerminal(); | ||
terminal.cols = INIT_COLS; | ||
terminal.rows = INIT_ROWS; | ||
terminal.scrollback = 1000; | ||
buffer = new Buffer_1.Buffer(terminal); | ||
@@ -28,4 +30,95 @@ }); | ||
}); | ||
describe('fillViewportRows', function () { | ||
it('should fill the buffer with blank lines based on the size of the viewport', function () { | ||
var blankLineChar = terminal.blankLine()[0]; | ||
buffer.fillViewportRows(); | ||
chai_1.assert.equal(buffer.lines.length, INIT_ROWS); | ||
for (var y = 0; y < INIT_ROWS; y++) { | ||
chai_1.assert.equal(buffer.lines.get(y).length, INIT_COLS); | ||
for (var x = 0; x < INIT_COLS; x++) { | ||
chai_1.assert.deepEqual(buffer.lines.get(y)[x], blankLineChar); | ||
} | ||
} | ||
}); | ||
}); | ||
describe('resize', function () { | ||
describe('column size is reduced', function () { | ||
it('should not trim the data in the buffer', function () { | ||
buffer.fillViewportRows(); | ||
buffer.resize(INIT_COLS / 2, INIT_ROWS); | ||
chai_1.assert.equal(buffer.lines.length, INIT_ROWS); | ||
for (var i = 0; i < INIT_ROWS; i++) { | ||
chai_1.assert.equal(buffer.lines.get(i).length, INIT_COLS); | ||
} | ||
}); | ||
}); | ||
describe('column size is increased', function () { | ||
it('should add pad columns', function () { | ||
buffer.fillViewportRows(); | ||
buffer.resize(INIT_COLS + 10, INIT_ROWS); | ||
chai_1.assert.equal(buffer.lines.length, INIT_ROWS); | ||
for (var i = 0; i < INIT_ROWS; i++) { | ||
chai_1.assert.equal(buffer.lines.get(i).length, INIT_COLS + 10); | ||
} | ||
}); | ||
}); | ||
describe('row size reduced', function () { | ||
it('should trim blank lines from the end', function () { | ||
buffer.fillViewportRows(); | ||
buffer.resize(INIT_COLS, INIT_ROWS - 10); | ||
chai_1.assert.equal(buffer.lines.length, INIT_ROWS - 10); | ||
}); | ||
it('should move the viewport down when it\'s at the end', function () { | ||
buffer.fillViewportRows(); | ||
buffer.y = INIT_ROWS - 5 - 1; | ||
buffer.resize(INIT_COLS, INIT_ROWS - 10); | ||
chai_1.assert.equal(buffer.lines.length, INIT_ROWS - 5); | ||
chai_1.assert.equal(buffer.ydisp, 5); | ||
chai_1.assert.equal(buffer.ybase, 5); | ||
}); | ||
}); | ||
describe('row size increased', function () { | ||
describe('empty buffer', function () { | ||
it('should add blank lines to end', function () { | ||
buffer.fillViewportRows(); | ||
chai_1.assert.equal(buffer.ydisp, 0); | ||
buffer.resize(INIT_COLS, INIT_ROWS + 10); | ||
chai_1.assert.equal(buffer.ydisp, 0); | ||
chai_1.assert.equal(buffer.lines.length, INIT_ROWS + 10); | ||
}); | ||
}); | ||
describe('filled buffer', function () { | ||
it('should show more of the buffer above', function () { | ||
buffer.fillViewportRows(); | ||
for (var i = 0; i < 10; i++) { | ||
buffer.lines.push(terminal.blankLine()); | ||
} | ||
buffer.y = INIT_ROWS - 1; | ||
buffer.ybase = 10; | ||
buffer.ydisp = 10; | ||
chai_1.assert.equal(buffer.lines.length, INIT_ROWS + 10); | ||
buffer.resize(INIT_COLS, INIT_ROWS + 5); | ||
chai_1.assert.equal(buffer.ydisp, 5); | ||
chai_1.assert.equal(buffer.ybase, 5); | ||
chai_1.assert.equal(buffer.lines.length, INIT_ROWS + 10); | ||
}); | ||
it('should show more of the buffer below when the viewport is at the top of the buffer', function () { | ||
buffer.fillViewportRows(); | ||
for (var i = 0; i < 10; i++) { | ||
buffer.lines.push(terminal.blankLine()); | ||
} | ||
buffer.y = INIT_ROWS - 1; | ||
buffer.ybase = 10; | ||
buffer.ydisp = 0; | ||
chai_1.assert.equal(buffer.lines.length, INIT_ROWS + 10); | ||
buffer.resize(INIT_COLS, INIT_ROWS + 5); | ||
chai_1.assert.equal(buffer.ydisp, 0); | ||
chai_1.assert.equal(buffer.ybase, 5); | ||
chai_1.assert.equal(buffer.lines.length, INIT_ROWS + 10); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
//# sourceMappingURL=Buffer.test.js.map |
@@ -21,2 +21,3 @@ "use strict"; | ||
_this._normal = new Buffer_1.Buffer(_this._terminal); | ||
_this._normal.fillViewportRows(); | ||
_this._alt = new Buffer_1.Buffer(_this._terminal); | ||
@@ -48,2 +49,3 @@ _this._activeBuffer = _this._normal; | ||
BufferSet.prototype.activateNormalBuffer = function () { | ||
this._alt.clear(); | ||
this._activeBuffer = this._normal; | ||
@@ -53,5 +55,10 @@ this.emit('activate', this._normal); | ||
BufferSet.prototype.activateAltBuffer = function () { | ||
this._alt.fillViewportRows(); | ||
this._activeBuffer = this._alt; | ||
this.emit('activate', this._alt); | ||
}; | ||
BufferSet.prototype.resize = function (newCols, newRows) { | ||
this._normal.resize(newCols, newRows); | ||
this._alt.resize(newCols, newRows); | ||
}; | ||
return BufferSet; | ||
@@ -58,0 +65,0 @@ }(EventEmitter_1.EventEmitter)); |
@@ -6,2 +6,3 @@ "use strict"; | ||
var Buffer_1 = require("./Buffer"); | ||
var TestUtils_1 = require("./utils/TestUtils"); | ||
describe('BufferSet', function () { | ||
@@ -11,7 +12,6 @@ var terminal; | ||
beforeEach(function () { | ||
terminal = { | ||
cols: 80, | ||
rows: 24, | ||
scrollback: 1000 | ||
}; | ||
terminal = new TestUtils_1.MockTerminal(); | ||
terminal.cols = 80; | ||
terminal.rows = 24; | ||
terminal.scrollback = 1000; | ||
bufferSet = new BufferSet_1.BufferSet(terminal); | ||
@@ -18,0 +18,0 @@ }); |
@@ -541,3 +541,2 @@ "use strict"; | ||
this._terminal.buffers.activateAltBuffer(); | ||
this._terminal.reset(); | ||
this._terminal.viewport.syncScrollArea(); | ||
@@ -544,0 +543,0 @@ this._terminal.showCursor(); |
@@ -17,2 +17,3 @@ "use strict"; | ||
var BufferSet_1 = require("./BufferSet"); | ||
var TestUtils_1 = require("./utils/TestUtils"); | ||
var TestSelectionManager = (function (_super) { | ||
@@ -48,3 +49,5 @@ __extends(TestSelectionManager, _super); | ||
rowContainer = document.createElement('div'); | ||
terminal = { cols: 80, rows: 2 }; | ||
terminal = new TestUtils_1.MockTerminal(); | ||
terminal.cols = 80; | ||
terminal.rows = 2; | ||
terminal.scrollback = 100; | ||
@@ -65,3 +68,3 @@ terminal.buffers = new BufferSet_1.BufferSet(terminal); | ||
it('should expand selection for normal width chars', function () { | ||
bufferLines.push(stringToRow('foo bar')); | ||
bufferLines.set(0, stringToRow('foo bar')); | ||
selectionManager.selectWordAt([0, 0]); | ||
@@ -83,3 +86,3 @@ chai_1.assert.equal(selectionManager.selectionText, 'foo'); | ||
it('should expand selection for whitespace', function () { | ||
bufferLines.push(stringToRow('a b')); | ||
bufferLines.set(0, stringToRow('a b')); | ||
selectionManager.selectWordAt([0, 0]); | ||
@@ -97,3 +100,3 @@ chai_1.assert.equal(selectionManager.selectionText, 'a'); | ||
it('should expand selection for wide characters', function () { | ||
bufferLines.push([ | ||
bufferLines.set(0, [ | ||
[null, '中', 2], | ||
@@ -147,3 +150,3 @@ [null, '', 0], | ||
it('should select up to non-path characters that are commonly adjacent to paths', function () { | ||
bufferLines.push(stringToRow('(cd)[ef]{gh}\'ij"')); | ||
bufferLines.set(0, stringToRow('(cd)[ef]{gh}\'ij"')); | ||
selectionManager.selectWordAt([0, 0]); | ||
@@ -185,3 +188,3 @@ chai_1.assert.equal(selectionManager.selectionText, '(cd'); | ||
it('should select the entire line', function () { | ||
bufferLines.push(stringToRow('foo bar')); | ||
bufferLines.set(0, stringToRow('foo bar')); | ||
selectionManager.selectLineAt(0); | ||
@@ -195,7 +198,8 @@ chai_1.assert.equal(selectionManager.selectionText, 'foo bar', 'The selected text is correct'); | ||
it('should select the entire buffer, beyond the viewport', function () { | ||
bufferLines.push(stringToRow('1')); | ||
bufferLines.push(stringToRow('2')); | ||
bufferLines.push(stringToRow('3')); | ||
bufferLines.push(stringToRow('4')); | ||
bufferLines.push(stringToRow('5')); | ||
bufferLines.length = 5; | ||
bufferLines.set(0, stringToRow('1')); | ||
bufferLines.set(1, stringToRow('2')); | ||
bufferLines.set(2, stringToRow('3')); | ||
bufferLines.set(3, stringToRow('4')); | ||
bufferLines.set(4, stringToRow('5')); | ||
selectionManager.selectAll(); | ||
@@ -202,0 +206,0 @@ terminal.buffer.ybase = bufferLines.length - terminal.rows; |
@@ -16,2 +16,3 @@ "use strict"; | ||
var BufferSet_1 = require("./BufferSet"); | ||
var TestUtils_1 = require("./utils/TestUtils"); | ||
var TestSelectionModel = (function (_super) { | ||
@@ -30,3 +31,5 @@ __extends(TestSelectionModel, _super); | ||
beforeEach(function () { | ||
terminal = { cols: 80, rows: 2, ybase: 0 }; | ||
terminal = new TestUtils_1.MockTerminal(); | ||
terminal.cols = 80; | ||
terminal.rows = 2; | ||
terminal.scrollback = 10; | ||
@@ -33,0 +36,0 @@ terminal.buffers = new BufferSet_1.BufferSet(terminal); |
@@ -123,6 +123,2 @@ "use strict"; | ||
}); | ||
var i = this.rows; | ||
while (i--) { | ||
this.buffer.lines.push(this.blankLine()); | ||
} | ||
if (this.selectionManager) { | ||
@@ -1303,70 +1299,15 @@ this.selectionManager.setBuffer(this.buffer.lines); | ||
y = 1; | ||
j = this.cols; | ||
if (j < x) { | ||
ch = [this.defAttr, ' ', 1]; | ||
i = this.buffer.lines.length; | ||
while (i--) { | ||
if (this.buffer.lines.get(i) === undefined) { | ||
this.buffer.lines.set(i, this.blankLine()); | ||
} | ||
while (this.buffer.lines.get(i).length < x) { | ||
this.buffer.lines.get(i).push(ch); | ||
} | ||
} | ||
this.buffers.resize(x, y); | ||
while (this.children.length < y) { | ||
this.insertRow(); | ||
} | ||
while (this.children.length > y) { | ||
el = this.children.shift(); | ||
if (!el) | ||
continue; | ||
el.parentNode.removeChild(el); | ||
} | ||
this.cols = x; | ||
this.rows = y; | ||
this.setupStops(this.cols); | ||
j = this.rows; | ||
addToY = 0; | ||
if (j < y) { | ||
el = this.element; | ||
while (j++ < 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) { | ||
this.buffer.ybase--; | ||
addToY++; | ||
if (this.buffer.ydisp > 0) { | ||
this.buffer.ydisp--; | ||
} | ||
} | ||
else { | ||
this.buffer.lines.push(this.blankLine()); | ||
} | ||
} | ||
if (this.children.length < y) { | ||
this.insertRow(); | ||
} | ||
} | ||
} | ||
else { | ||
while (j-- > y) { | ||
if (this.buffer.lines.length > y + this.buffer.ybase) { | ||
if (this.buffer.lines.length > this.buffer.ybase + this.buffer.y + 1) { | ||
this.buffer.lines.pop(); | ||
} | ||
else { | ||
this.buffer.ybase++; | ||
this.buffer.ydisp++; | ||
} | ||
} | ||
if (this.children.length > y) { | ||
el = this.children.shift(); | ||
if (!el) | ||
continue; | ||
el.parentNode.removeChild(el); | ||
} | ||
} | ||
} | ||
this.rows = y; | ||
if (this.buffer.y >= y) { | ||
this.buffer.y = y - 1; | ||
} | ||
if (addToY) { | ||
this.buffer.y += addToY; | ||
} | ||
if (this.buffer.x >= x) { | ||
this.buffer.x = x - 1; | ||
} | ||
this.buffer.scrollTop = 0; | ||
this.buffer.scrollBottom = y - 1; | ||
this.charMeasure.measure(); | ||
@@ -1525,3 +1466,2 @@ this.refresh(0, this.rows - 1); | ||
var inputHandler = this.inputHandler; | ||
var buffers = this.buffers; | ||
Terminal.call(this, this.options); | ||
@@ -1531,3 +1471,2 @@ this.customKeyEventHandler = customKeyEventHandler; | ||
this.inputHandler = inputHandler; | ||
this.buffers = buffers; | ||
this.refresh(0, this.rows - 1); | ||
@@ -1534,0 +1473,0 @@ this.viewport.syncScrollArea(); |
{ | ||
"name": "xterm", | ||
"description": "Full xterm terminal, in your browser", | ||
"version": "2.9.0", | ||
"version": "2.9.1", | ||
"ignore": [ | ||
@@ -6,0 +6,0 @@ "demo", |
@@ -23,4 +23,3 @@ /** | ||
*/ | ||
const xterm = '../../xterm'; | ||
module.exports = addon(require(xterm)); | ||
module.exports = addon(require('../../xterm')); | ||
} else if (typeof define == 'function') { | ||
@@ -27,0 +26,0 @@ /** |
@@ -8,3 +8,7 @@ /** | ||
import { CircularList } from './utils/CircularList'; | ||
import { MockTerminal } from './utils/TestUtils'; | ||
const INIT_COLS = 80; | ||
const INIT_ROWS = 24; | ||
describe('Buffer', () => { | ||
@@ -15,7 +19,6 @@ let terminal: ITerminal; | ||
beforeEach(() => { | ||
terminal = <any>{ | ||
cols: 80, | ||
rows: 24, | ||
scrollback: 1000 | ||
}; | ||
terminal = new MockTerminal(); | ||
terminal.cols = INIT_COLS; | ||
terminal.rows = INIT_ROWS; | ||
terminal.scrollback = 1000; | ||
buffer = new Buffer(terminal); | ||
@@ -33,2 +36,115 @@ }); | ||
}); | ||
describe('fillViewportRows', () => { | ||
it('should fill the buffer with blank lines based on the size of the viewport', () => { | ||
const blankLineChar = terminal.blankLine()[0]; | ||
buffer.fillViewportRows(); | ||
assert.equal(buffer.lines.length, INIT_ROWS); | ||
for (let y = 0; y < INIT_ROWS; y++) { | ||
assert.equal(buffer.lines.get(y).length, INIT_COLS); | ||
for (let x = 0; x < INIT_COLS; x++) { | ||
assert.deepEqual(buffer.lines.get(y)[x], blankLineChar); | ||
} | ||
} | ||
}); | ||
}); | ||
describe('resize', () => { | ||
describe('column size is reduced', () => { | ||
it('should not trim the data in the buffer', () => { | ||
buffer.fillViewportRows(); | ||
buffer.resize(INIT_COLS / 2, INIT_ROWS); | ||
assert.equal(buffer.lines.length, INIT_ROWS); | ||
for (let i = 0; i < INIT_ROWS; i++) { | ||
assert.equal(buffer.lines.get(i).length, INIT_COLS); | ||
} | ||
}); | ||
}); | ||
describe('column size is increased', () => { | ||
it('should add pad columns', () => { | ||
buffer.fillViewportRows(); | ||
buffer.resize(INIT_COLS + 10, INIT_ROWS); | ||
assert.equal(buffer.lines.length, INIT_ROWS); | ||
for (let i = 0; i < INIT_ROWS; i++) { | ||
assert.equal(buffer.lines.get(i).length, INIT_COLS + 10); | ||
} | ||
}); | ||
}); | ||
describe('row size reduced', () => { | ||
it('should trim blank lines from the end', () => { | ||
buffer.fillViewportRows(); | ||
buffer.resize(INIT_COLS, INIT_ROWS - 10); | ||
assert.equal(buffer.lines.length, INIT_ROWS - 10); | ||
}); | ||
it('should move the viewport down when it\'s at the end', () => { | ||
buffer.fillViewportRows(); | ||
// Set cursor y to have 5 blank lines below it | ||
buffer.y = INIT_ROWS - 5 - 1; | ||
buffer.resize(INIT_COLS, INIT_ROWS - 10); | ||
// Trim 5 rows | ||
assert.equal(buffer.lines.length, INIT_ROWS - 5); | ||
// Shift the viewport down 5 rows | ||
assert.equal(buffer.ydisp, 5); | ||
assert.equal(buffer.ybase, 5); | ||
}); | ||
}); | ||
describe('row size increased', () => { | ||
describe('empty buffer', () => { | ||
it('should add blank lines to end', () => { | ||
buffer.fillViewportRows(); | ||
assert.equal(buffer.ydisp, 0); | ||
buffer.resize(INIT_COLS, INIT_ROWS + 10); | ||
assert.equal(buffer.ydisp, 0); | ||
assert.equal(buffer.lines.length, INIT_ROWS + 10); | ||
}); | ||
}); | ||
describe('filled buffer', () => { | ||
it('should show more of the buffer above', () => { | ||
buffer.fillViewportRows(); | ||
// Create 10 extra blank lines | ||
for (let i = 0; i < 10; i++) { | ||
buffer.lines.push(terminal.blankLine()); | ||
} | ||
// Set cursor to the bottom of the buffer | ||
buffer.y = INIT_ROWS - 1; | ||
// Scroll down 10 lines | ||
buffer.ybase = 10; | ||
buffer.ydisp = 10; | ||
assert.equal(buffer.lines.length, INIT_ROWS + 10); | ||
buffer.resize(INIT_COLS, INIT_ROWS + 5); | ||
// Should be should 5 more lines | ||
assert.equal(buffer.ydisp, 5); | ||
assert.equal(buffer.ybase, 5); | ||
// Should not trim the buffer | ||
assert.equal(buffer.lines.length, INIT_ROWS + 10); | ||
}); | ||
it('should show more of the buffer below when the viewport is at the top of the buffer', () => { | ||
buffer.fillViewportRows(); | ||
// Create 10 extra blank lines | ||
for (let i = 0; i < 10; i++) { | ||
buffer.lines.push(terminal.blankLine()); | ||
} | ||
// Set cursor to the bottom of the buffer | ||
buffer.y = INIT_ROWS - 1; | ||
// Scroll down 10 lines | ||
buffer.ybase = 10; | ||
buffer.ydisp = 0; | ||
assert.equal(buffer.lines.length, INIT_ROWS + 10); | ||
buffer.resize(INIT_COLS, INIT_ROWS + 5); | ||
// The viewport should remain at the top | ||
assert.equal(buffer.ydisp, 0); | ||
// The buffer ybase should move up 5 lines | ||
assert.equal(buffer.ybase, 5); | ||
// Should not trim the buffer | ||
assert.equal(buffer.lines.length, INIT_ROWS + 10); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -5,3 +5,3 @@ /** | ||
import { ITerminal } from './Interfaces'; | ||
import { ITerminal, IBuffer } from './Interfaces'; | ||
import { CircularList } from './utils/CircularList'; | ||
@@ -16,5 +16,12 @@ | ||
*/ | ||
export class Buffer { | ||
public lines: CircularList<[number, string, number][]>; | ||
export class Buffer implements IBuffer { | ||
private _lines: CircularList<[number, string, number][]>; | ||
public ydisp: number; | ||
public ybase: number; | ||
public y: number; | ||
public x: number; | ||
public scrollBottom: number; | ||
public scrollTop: number; | ||
public tabs: any; | ||
public savedY: number; | ||
@@ -25,3 +32,3 @@ public savedX: number; | ||
* Create a new Buffer. | ||
* @param {Terminal} terminal - The terminal the Buffer will belong to | ||
* @param {Terminal} _terminal - The terminal the Buffer will belong to | ||
* @param {number} ydisp - The scroll position of the Buffer in the viewport | ||
@@ -33,14 +40,113 @@ * @param {number} ybase - The scroll position of the y cursor (ybase + y = the y position within the Buffer) | ||
constructor( | ||
private terminal: ITerminal, | ||
public ydisp: number = 0, | ||
public ybase: number = 0, | ||
public y: number = 0, | ||
public x: number = 0, | ||
public scrollBottom: number = 0, | ||
public scrollTop: number = 0, | ||
public tabs: any = {}, | ||
private _terminal: ITerminal | ||
) { | ||
this.lines = new CircularList<[number, string, number][]>(this.terminal.scrollback); | ||
this.scrollBottom = this.terminal.rows - 1; | ||
this.clear(); | ||
} | ||
public get lines(): CircularList<[number, string, number][]> { | ||
return this._lines; | ||
} | ||
/** | ||
* Fills the buffer's viewport with blank lines. | ||
*/ | ||
public fillViewportRows(): void { | ||
if (this._lines.length === 0) { | ||
let i = this._terminal.rows; | ||
while (i--) { | ||
this.lines.push(this._terminal.blankLine()); | ||
} | ||
} | ||
} | ||
/** | ||
* Clears the buffer to it's initial state, discarding all previous data. | ||
*/ | ||
public clear(): void { | ||
this.ydisp = 0; | ||
this.ybase = 0; | ||
this.y = 0; | ||
this.x = 0; | ||
this.scrollBottom = 0; | ||
this.scrollTop = 0; | ||
this.tabs = {}; | ||
this._lines = new CircularList<[number, string, number][]>(this._terminal.scrollback); | ||
this.scrollBottom = this._terminal.rows - 1; | ||
} | ||
/** | ||
* Resizes the buffer, adjusting its data accordingly. | ||
* @param newCols The new number of columns. | ||
* @param newRows The new number of rows. | ||
*/ | ||
public resize(newCols: number, newRows: number): void { | ||
// Don't resize the buffer if it's empty and hasn't been used yet. | ||
if (this._lines.length === 0) { | ||
return; | ||
} | ||
// Deal with columns increasing (we don't do anything when columns reduce) | ||
if (this._terminal.cols < newCols) { | ||
const ch: [number, string, number] = [this._terminal.defAttr, ' ', 1]; // does xterm use the default attr? | ||
for (let i = 0; i < this._lines.length; i++) { | ||
if (this._lines.get(i) === undefined) { | ||
this._lines.set(i, this._terminal.blankLine()); | ||
} | ||
while (this._lines.get(i).length < newCols) { | ||
this._lines.get(i).push(ch); | ||
} | ||
} | ||
} | ||
// Resize rows in both directions as needed | ||
let addToY = 0; | ||
if (this._terminal.rows < newRows) { | ||
for (let y = this._terminal.rows; y < newRows; y++) { | ||
if (this._lines.length < newRows + this.ybase) { | ||
if (this.ybase > 0 && this._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--; | ||
addToY++; | ||
if (this.ydisp > 0) { | ||
// Viewport is at the top of the buffer, must increase downwards | ||
this.ydisp--; | ||
} | ||
} 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._terminal.blankLine()); | ||
} | ||
} | ||
} | ||
} else { // (this._terminal.rows >= newRows) | ||
for (let y = this._terminal.rows; y > newRows; y--) { | ||
if (this._lines.length > newRows + this.ybase) { | ||
if (this._lines.length > this.ybase + this.y + 1) { | ||
// The line is a blank line below the cursor, remove it | ||
this._lines.pop(); | ||
} else { | ||
// The line is the cursor, scroll down | ||
this.ybase++; | ||
this.ydisp++; | ||
} | ||
} | ||
} | ||
} | ||
// Make sure that the cursor stays on screen | ||
if (this.y >= newRows) { | ||
this.y = newRows - 1; | ||
} | ||
if (addToY) { | ||
this.y += addToY; | ||
} | ||
if (this.x >= newCols) { | ||
this.x = newCols - 1; | ||
} | ||
this.scrollTop = 0; | ||
this.scrollBottom = newRows - 1; | ||
} | ||
} |
@@ -8,2 +8,3 @@ /** | ||
import { Buffer } from './Buffer'; | ||
import { MockTerminal } from './utils/TestUtils'; | ||
@@ -15,7 +16,6 @@ describe('BufferSet', () => { | ||
beforeEach(() => { | ||
terminal = <any>{ | ||
cols: 80, | ||
rows: 24, | ||
scrollback: 1000 | ||
}; | ||
terminal = new MockTerminal(); | ||
terminal.cols = 80; | ||
terminal.rows = 24; | ||
terminal.scrollback = 1000; | ||
bufferSet = new BufferSet(terminal); | ||
@@ -22,0 +22,0 @@ }); |
@@ -25,2 +25,3 @@ /** | ||
this._normal = new Buffer(this._terminal); | ||
this._normal.fillViewportRows(); | ||
this._alt = new Buffer(this._terminal); | ||
@@ -58,2 +59,7 @@ this._activeBuffer = this._normal; | ||
public activateNormalBuffer(): void { | ||
// The alt buffer should always be cleared when we switch to the normal | ||
// buffer. This frees up memory since the alt buffer should always be new | ||
// when activated. | ||
this._alt.clear(); | ||
this._activeBuffer = this._normal; | ||
@@ -67,5 +73,19 @@ this.emit('activate', this._normal); | ||
public activateAltBuffer(): void { | ||
// Since the alt buffer is always cleared when the normal buffer is | ||
// activated, we want to fill it when switching to it. | ||
this._alt.fillViewportRows(); | ||
this._activeBuffer = this._alt; | ||
this.emit('activate', this._alt); | ||
} | ||
/** | ||
* Resizes both normal and alt buffers, adjusting their data accordingly. | ||
* @param newCols The new number of columns. | ||
* @param newRows The new number of rows. | ||
*/ | ||
public resize(newCols: number, newRows: number): void { | ||
this._normal.resize(newCols, newRows); | ||
this._alt.resize(newCols, newRows); | ||
} | ||
} |
@@ -957,3 +957,2 @@ /** | ||
this._terminal.buffers.activateAltBuffer(); | ||
this._terminal.reset(); | ||
this._terminal.viewport.syncScrollArea(); | ||
@@ -960,0 +959,0 @@ this._terminal.showCursor(); |
@@ -51,2 +51,3 @@ /** | ||
showCursor(): void; | ||
blankLine(cur?: boolean, isWrapped?: boolean); | ||
} | ||
@@ -96,4 +97,4 @@ | ||
maxLength: number; | ||
forEach: (callbackfn: (value: T, index: number) => void) => void; | ||
forEach(callbackfn: (value: T, index: number, array: T[]) => void): void; | ||
get(index: number): T; | ||
@@ -100,0 +101,0 @@ set(index: number, value: T): void; |
@@ -12,2 +12,3 @@ /** | ||
import { BufferSet } from './BufferSet'; | ||
import { MockTerminal } from './utils/TestUtils'; | ||
@@ -50,3 +51,5 @@ class TestSelectionManager extends SelectionManager { | ||
rowContainer = document.createElement('div'); | ||
terminal = <any>{ cols: 80, rows: 2 }; | ||
terminal = new MockTerminal(); | ||
terminal.cols = 80; | ||
terminal.rows = 2; | ||
terminal.scrollback = 100; | ||
@@ -69,3 +72,3 @@ terminal.buffers = new BufferSet(terminal); | ||
it('should expand selection for normal width chars', () => { | ||
bufferLines.push(stringToRow('foo bar')); | ||
bufferLines.set(0, stringToRow('foo bar')); | ||
selectionManager.selectWordAt([0, 0]); | ||
@@ -87,3 +90,3 @@ assert.equal(selectionManager.selectionText, 'foo'); | ||
it('should expand selection for whitespace', () => { | ||
bufferLines.push(stringToRow('a b')); | ||
bufferLines.set(0, stringToRow('a b')); | ||
selectionManager.selectWordAt([0, 0]); | ||
@@ -102,3 +105,3 @@ assert.equal(selectionManager.selectionText, 'a'); | ||
// Wide characters use a special format | ||
bufferLines.push([ | ||
bufferLines.set(0, [ | ||
[null, '中', 2], | ||
@@ -155,3 +158,3 @@ [null, '', 0], | ||
it('should select up to non-path characters that are commonly adjacent to paths', () => { | ||
bufferLines.push(stringToRow('(cd)[ef]{gh}\'ij"')); | ||
bufferLines.set(0, stringToRow('(cd)[ef]{gh}\'ij"')); | ||
selectionManager.selectWordAt([0, 0]); | ||
@@ -194,3 +197,3 @@ assert.equal(selectionManager.selectionText, '(cd'); | ||
it('should select the entire line', () => { | ||
bufferLines.push(stringToRow('foo bar')); | ||
bufferLines.set(0, stringToRow('foo bar')); | ||
selectionManager.selectLineAt(0); | ||
@@ -205,7 +208,8 @@ assert.equal(selectionManager.selectionText, 'foo bar', 'The selected text is correct'); | ||
it('should select the entire buffer, beyond the viewport', () => { | ||
bufferLines.push(stringToRow('1')); | ||
bufferLines.push(stringToRow('2')); | ||
bufferLines.push(stringToRow('3')); | ||
bufferLines.push(stringToRow('4')); | ||
bufferLines.push(stringToRow('5')); | ||
bufferLines.length = 5; | ||
bufferLines.set(0, stringToRow('1')); | ||
bufferLines.set(1, stringToRow('2')); | ||
bufferLines.set(2, stringToRow('3')); | ||
bufferLines.set(3, stringToRow('4')); | ||
bufferLines.set(4, stringToRow('5')); | ||
selectionManager.selectAll(); | ||
@@ -212,0 +216,0 @@ terminal.buffer.ybase = bufferLines.length - terminal.rows; |
@@ -8,2 +8,3 @@ /** | ||
import {BufferSet} from './BufferSet'; | ||
import { MockTerminal } from './utils/TestUtils'; | ||
@@ -26,3 +27,5 @@ class TestSelectionModel extends SelectionModel { | ||
beforeEach(() => { | ||
terminal = <any>{ cols: 80, rows: 2, ybase: 0 }; | ||
terminal = new MockTerminal(); | ||
terminal.cols = 80; | ||
terminal.rows = 2; | ||
terminal.scrollback = 10; | ||
@@ -29,0 +32,0 @@ terminal.buffers = new BufferSet(terminal); |
@@ -8,4 +8,5 @@ /** | ||
import { EventEmitter } from '../EventEmitter'; | ||
import { ICircularList } from '../Interfaces'; | ||
export class CircularList<T> extends EventEmitter { | ||
export class CircularList<T> extends EventEmitter implements ICircularList<T> { | ||
private _array: T[]; | ||
@@ -12,0 +13,0 @@ private _startIndex: number; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
2135808
174
34729