describe('clear', function() {
it('should clear a buffer equal to rows', function() {
- var promptLine = xterm.lines[xterm.ybase + xterm.y];
+ var promptLine = xterm.lines.get(xterm.ybase + xterm.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[0], promptLine);
+ assert.deepEqual(xterm.lines.get(0), promptLine);
for (var i = 1; i < xterm.rows; i++) {
- assert.deepEqual(xterm.lines[0], xterm.blankLine());
+ assert.deepEqual(xterm.lines.get(i), xterm.blankLine());
}
});
it('should clear a buffer larger than rows', function() {
xterm.write('test\n');
}
- var promptLine = xterm.lines[xterm.ybase + xterm.y];
+ var promptLine = xterm.lines.get(xterm.ybase + xterm.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[0], promptLine);
+ assert.deepEqual(xterm.lines.get(0), promptLine);
for (var i = 1; i < xterm.rows; i++) {
- assert.deepEqual(xterm.lines[i], xterm.blankLine());
+ assert.deepEqual(xterm.lines.get(i), xterm.blankLine());
}
});
it('should not break the prompt when cleared twice', function() {
- var promptLine = xterm.lines[xterm.ybase + xterm.y];
+ var promptLine = xterm.lines.get(xterm.ybase + xterm.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[0], promptLine);
+ assert.deepEqual(xterm.lines.get(0), promptLine);
for (var i = 1; i < xterm.rows; i++) {
- assert.deepEqual(xterm.lines[i], xterm.blankLine());
+ assert.deepEqual(xterm.lines.get(i), xterm.blankLine());
}
});
});
var high = String.fromCharCode(0xD800);
for (var i=0xDC00; i<=0xDCFF; ++i) {
xterm.write(high + String.fromCharCode(i));
- var tchar = xterm.lines[0][0];
+ var tchar = xterm.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[0][1][1]).eql(' ');
+ expect(xterm.lines.get(0)[1][1]).eql(' ');
xterm.reset();
}
});
for (var i=0xDC00; i<=0xDCFF; ++i) {
xterm.x = xterm.cols - 1;
xterm.write(high + String.fromCharCode(i));
- expect(xterm.lines[0][xterm.x-1][1]).eql(high + String.fromCharCode(i));
- expect(xterm.lines[0][xterm.x-1][1].length).eql(2);
- expect(xterm.lines[1][0][1]).eql(' ');
+ 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(' ');
xterm.reset();
}
});
xterm.x = xterm.cols - 1;
xterm.wraparoundMode = true;
xterm.write('a' + high + String.fromCharCode(i));
- expect(xterm.lines[0][xterm.cols-1][1]).eql('a');
- expect(xterm.lines[1][0][1]).eql(high + String.fromCharCode(i));
- expect(xterm.lines[1][0][1].length).eql(2);
- expect(xterm.lines[1][1][1]).eql(' ');
+ 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(' ');
xterm.reset();
}
});
xterm.x = xterm.cols - 1;
xterm.wraparoundMode = false;
xterm.write('a' + high + String.fromCharCode(i));
- expect(xterm.lines[0][xterm.cols-1][1]).eql(high + String.fromCharCode(i));
- expect(xterm.lines[0][xterm.cols-1][1].length).eql(2);
- expect(xterm.lines[1][1][1]).eql(' ');
+ expect(xterm.lines.get(0)[xterm.cols-1][1]).eql(high + String.fromCharCode(i));
+ expect(xterm.lines.get(0)[xterm.cols-1][1].length).eql(2);
+ expect(xterm.lines.get(1)[1][1]).eql(' ');
xterm.reset();
}
});
for (var i=0xDC00; i<=0xDCFF; ++i) {
xterm.write(high);
xterm.write(String.fromCharCode(i));
- var tchar = xterm.lines[0][0];
+ var tchar = xterm.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[0][1][1]).eql(' ');
+ expect(xterm.lines.get(0)[1][1]).eql(' ');
xterm.reset();
}
});
describe('unicode - combining characters', function() {
it('café', function () {
xterm.write('cafe\u0301');
- expect(xterm.lines[0][3][1]).eql('e\u0301');
- expect(xterm.lines[0][3][1].length).eql(2);
- expect(xterm.lines[0][3][2]).eql(1);
+ 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);
});
it('café - end of line', function() {
xterm.x = xterm.cols - 1 - 3;
xterm.write('cafe\u0301');
- expect(xterm.lines[0][xterm.cols-1][1]).eql('e\u0301');
- expect(xterm.lines[0][xterm.cols-1][1].length).eql(2);
- expect(xterm.lines[0][xterm.cols-1][2]).eql(1);
- expect(xterm.lines[0][1][1]).eql(' ');
- expect(xterm.lines[0][1][1].length).eql(1);
- expect(xterm.lines[0][1][2]).eql(1);
+ 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);
});
it('multiple combined é', function() {
xterm.wraparoundMode = true;
xterm.write(Array(100).join('e\u0301'));
for (var i=0; i<xterm.cols; ++i) {
- var tchar = xterm.lines[0][i];
+ var tchar = xterm.lines.get(0)[i];
expect(tchar[1]).eql('e\u0301');
expect(tchar[1].length).eql(2);
expect(tchar[2]).eql(1);
}
- tchar = xterm.lines[1][0];
+ tchar = xterm.lines.get(1)[0];
expect(tchar[1]).eql('e\u0301');
expect(tchar[1].length).eql(2);
expect(tchar[2]).eql(1);
xterm.wraparoundMode = true;
xterm.write(Array(100).join('\uD800\uDC00\u0301'));
for (var i=0; i<xterm.cols; ++i) {
- var tchar = xterm.lines[0][i];
+ var tchar = xterm.lines.get(0)[i];
expect(tchar[1]).eql('\uD800\uDC00\u0301');
expect(tchar[1].length).eql(3);
expect(tchar[2]).eql(1);
}
- tchar = xterm.lines[1][0];
+ tchar = xterm.lines.get(1)[0];
expect(tchar[1]).eql('\uD800\uDC00\u0301');
expect(tchar[1].length).eql(3);
expect(tchar[2]).eql(1);
xterm.wraparoundMode = true;
xterm.write(Array(50).join('¥'));
for (var i=0; i<xterm.cols; ++i) {
- var tchar = xterm.lines[0][i];
+ var tchar = xterm.lines.get(0)[i];
if (i % 2) {
expect(tchar[1]).eql('');
expect(tchar[1].length).eql(0);
expect(tchar[2]).eql(2);
}
}
- tchar = xterm.lines[1][0];
+ tchar = xterm.lines.get(1)[0];
expect(tchar[1]).eql('¥');
expect(tchar[1].length).eql(1);
expect(tchar[2]).eql(2);
xterm.x = 1;
xterm.write(Array(50).join('¥'));
for (var i=1; i<xterm.cols-1; ++i) {
- var tchar = xterm.lines[0][i];
+ var tchar = xterm.lines.get(0)[i];
if (!(i % 2)) {
expect(tchar[1]).eql('');
expect(tchar[1].length).eql(0);
expect(tchar[2]).eql(2);
}
}
- tchar = xterm.lines[0][xterm.cols-1];
+ tchar = xterm.lines.get(0)[xterm.cols-1];
expect(tchar[1]).eql(' ');
expect(tchar[1].length).eql(1);
expect(tchar[2]).eql(1);
- tchar = xterm.lines[1][0];
+ tchar = xterm.lines.get(1)[0];
expect(tchar[1]).eql('¥');
expect(tchar[1].length).eql(1);
expect(tchar[2]).eql(2);
xterm.x = 1;
xterm.write(Array(50).join('¥\u0301'));
for (var i=1; i<xterm.cols-1; ++i) {
- var tchar = xterm.lines[0][i];
+ var tchar = xterm.lines.get(0)[i];
if (!(i % 2)) {
expect(tchar[1]).eql('');
expect(tchar[1].length).eql(0);
expect(tchar[2]).eql(2);
}
}
- tchar = xterm.lines[0][xterm.cols-1];
+ tchar = xterm.lines.get(0)[xterm.cols-1];
expect(tchar[1]).eql(' ');
expect(tchar[1].length).eql(1);
expect(tchar[2]).eql(1);
- tchar = xterm.lines[1][0];
+ tchar = xterm.lines.get(1)[0];
expect(tchar[1]).eql('¥\u0301');
expect(tchar[1].length).eql(2);
expect(tchar[2]).eql(2);
xterm.wraparoundMode = true;
xterm.write(Array(50).join('¥\u0301'));
for (var i=0; i<xterm.cols; ++i) {
- var tchar = xterm.lines[0][i];
+ var tchar = xterm.lines.get(0)[i];
if (i % 2) {
expect(tchar[1]).eql('');
expect(tchar[1].length).eql(0);
expect(tchar[2]).eql(2);
}
}
- tchar = xterm.lines[1][0];
+ tchar = xterm.lines.get(1)[0];
expect(tchar[1]).eql('¥\u0301');
expect(tchar[1].length).eql(2);
expect(tchar[2]).eql(2);
xterm.x = 1;
xterm.write(Array(50).join('\ud843\ude6d\u0301'));
for (var i=1; i<xterm.cols-1; ++i) {
- var tchar = xterm.lines[0][i];
+ var tchar = xterm.lines.get(0)[i];
if (!(i % 2)) {
expect(tchar[1]).eql('');
expect(tchar[1].length).eql(0);
expect(tchar[2]).eql(2);
}
}
- tchar = xterm.lines[0][xterm.cols-1];
+ tchar = xterm.lines.get(0)[xterm.cols-1];
expect(tchar[1]).eql(' ');
expect(tchar[1].length).eql(1);
expect(tchar[2]).eql(1);
- tchar = xterm.lines[1][0];
+ tchar = xterm.lines.get(1)[0];
expect(tchar[1]).eql('\ud843\ude6d\u0301');
expect(tchar[1].length).eql(3);
expect(tchar[2]).eql(2);
xterm.wraparoundMode = true;
xterm.write(Array(50).join('\ud843\ude6d\u0301'));
for (var i=0; i<xterm.cols; ++i) {
- var tchar = xterm.lines[0][i];
+ var tchar = xterm.lines.get(0)[i];
if (i % 2) {
expect(tchar[1]).eql('');
expect(tchar[1].length).eql(0);
expect(tchar[2]).eql(2);
}
}
- tchar = xterm.lines[1][0];
+ tchar = xterm.lines.get(1)[0];
expect(tchar[1]).eql('\ud843\ude6d\u0301');
expect(tchar[1].length).eql(3);
expect(tchar[2]).eql(2);
xterm.y = 0;
xterm.insertMode = true;
xterm.write('abcde');
- expect(xterm.lines[0].length).eql(xterm.cols);
- expect(xterm.lines[0][10][1]).eql('a');
- expect(xterm.lines[0][14][1]).eql('e');
- expect(xterm.lines[0][15][1]).eql('0');
- expect(xterm.lines[0][79][1]).eql('4');
+ expect(xterm.lines.get(0).length).eql(xterm.cols);
+ expect(xterm.lines.get(0)[10][1]).eql('a');
+ expect(xterm.lines.get(0)[14][1]).eql('e');
+ expect(xterm.lines.get(0)[15][1]).eql('0');
+ expect(xterm.lines.get(0)[79][1]).eql('4');
});
it('fullwidth - insert', function() {
xterm.write(Array(9).join('0123456789').slice(-80));
xterm.y = 0;
xterm.insertMode = true;
xterm.write('¥¥¥');
- expect(xterm.lines[0].length).eql(xterm.cols);
- expect(xterm.lines[0][10][1]).eql('¥');
- expect(xterm.lines[0][11][1]).eql('');
- expect(xterm.lines[0][14][1]).eql('¥');
- expect(xterm.lines[0][15][1]).eql('');
- expect(xterm.lines[0][79][1]).eql('3');
+ expect(xterm.lines.get(0).length).eql(xterm.cols);
+ expect(xterm.lines.get(0)[10][1]).eql('¥');
+ expect(xterm.lines.get(0)[11][1]).eql('');
+ expect(xterm.lines.get(0)[14][1]).eql('¥');
+ expect(xterm.lines.get(0)[15][1]).eql('');
+ expect(xterm.lines.get(0)[79][1]).eql('3');
});
it('fullwidth - right border', function() {
xterm.write(Array(41).join('¥'));
xterm.y = 0;
xterm.insertMode = true;
xterm.write('a');
- expect(xterm.lines[0].length).eql(xterm.cols);
- expect(xterm.lines[0][10][1]).eql('a');
- expect(xterm.lines[0][11][1]).eql('¥');
- expect(xterm.lines[0][79][1]).eql(' '); // fullwidth char got replaced
+ expect(xterm.lines.get(0).length).eql(xterm.cols);
+ expect(xterm.lines.get(0)[10][1]).eql('a');
+ expect(xterm.lines.get(0)[11][1]).eql('¥');
+ expect(xterm.lines.get(0)[79][1]).eql(' '); // fullwidth char got replaced
xterm.write('b');
- expect(xterm.lines[0].length).eql(xterm.cols);
- expect(xterm.lines[0][11][1]).eql('b');
- expect(xterm.lines[0][12][1]).eql('¥');
- expect(xterm.lines[0][79][1]).eql(''); // empty cell after fullwidth
+ expect(xterm.lines.get(0).length).eql(xterm.cols);
+ expect(xterm.lines.get(0)[11][1]).eql('b');
+ expect(xterm.lines.get(0)[12][1]).eql('¥');
+ expect(xterm.lines.get(0)[79][1]).eql(''); // empty cell after fullwidth
});
});
});
import { EventEmitter } from './EventEmitter.js';
import { Viewport } from './Viewport.js';
import { rightClickHandler, pasteHandler, copyHandler } from './handlers/Clipboard.js';
+import { CircularList } from './utils/CircularList.js';
import * as Browser from './utils/Browser';
import * as Keyboard from './utils/Keyboard';
* 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 = [];
+ this.lines = new CircularList(this.scrollback);
var i = this.rows;
while (i--) {
this.lines.push(this.blankLine());
for (; y <= end; y++) {
row = y + this.ydisp;
- line = this.lines[row];
+ line = this.lines.get(row);
out = '';
if (this.y === y - (this.ybase - this.ydisp)
var row;
if (++this.ybase === this.scrollback) {
- this.ybase = this.ybase / 2 | 0;
- this.lines = this.lines.slice(-(this.ybase + this.rows) + 1);
+ this.ybase = this.ybase / 2;
+ // TODO: Rely on the circular list instead of cutting it in half
+ this.lines.removeItemsFromStart(this.ybase + this.rows - 1);
}
if (!this.userScrolling) {
// surrogate low - already handled above
if (0xDC00 <= code && code <= 0xDFFF)
continue;
-
switch (this.state) {
case normal:
switch (ch) {
// insert combining char in last cell
// FIXME: needs handling after cursor jumps
if (!ch_width && this.x) {
-
// dont overflow left
- if (this.lines[row][this.x-1]) {
- if (!this.lines[row][this.x-1][2]) {
+ if (this.lines.get(row)[this.x-1]) {
+ if (!this.lines.get(row)[this.x-1][2]) {
// found empty cell after fullwidth, need to go 2 cells back
- if (this.lines[row][this.x-2])
- this.lines[row][this.x-2][1] += ch;
+ if (this.lines.get(row)[this.x-2])
+ this.lines.get(row)[this.x-2][1] += ch;
} else {
- this.lines[row][this.x-1][1] += ch;
+ this.lines.get(row)[this.x-1][1] += ch;
}
this.updateRange(this.y);
}
for (var 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
- var removed = this.lines[this.y + this.ybase].pop();
+ var removed = this.lines.get(this.y + this.ybase).pop();
if (removed[2]===0
- && this.lines[row][this.cols-2]
- && this.lines[row][this.cols-2][2]===2)
- this.lines[row][this.cols-2] = [this.curAttr, ' ', 1];
+ && this.lines.get(row)[this.cols-2]
+ && this.lines.get(row)[this.cols-2][2]===2)
+ this.lines.get(row)[this.cols-2] = [this.curAttr, ' ', 1];
// insert empty cell at cursor
- this.lines[row].splice(this.x, 0, [this.curAttr, ' ', 1]);
+ this.lines.get(row).splice(this.x, 0, [this.curAttr, ' ', 1]);
}
}
- this.lines[row][this.x] = [this.curAttr, ch, ch_width];
+ this.lines.get(row)[this.x] = [this.curAttr, ch, ch_width];
this.x++;
this.updateRange(this.y);
// fullwidth char - set next cell width to zero and advance cursor
if (ch_width===2) {
- this.lines[row][this.x] = [this.curAttr, '', 0];
+ this.lines.get(row)[this.x] = [this.curAttr, '', 0];
this.x++;
}
}
ch = [this.defAttr, ' ', 1]; // does xterm use the default attr?
i = this.lines.length;
while (i--) {
- while (this.lines[i].length < x) {
- this.lines[i].push(ch);
+ while (this.lines.get(i).length < x) {
+ this.lines.get(i).push(ch);
}
}
} else { // (j > x)
i = this.lines.length;
while (i--) {
- while (this.lines[i].length > x) {
- this.lines[i].pop();
+ while (this.lines.get(i).length > x) {
+ this.lines.get(i).pop();
}
}
}
* @param {number} y The line in which to operate.
*/
Terminal.prototype.eraseRight = function(x, y) {
- var line = this.lines[this.ybase + y]
+ var line = this.lines.get(this.ybase + y)
, ch = [this.eraseAttr(), ' ', 1]; // xterm
* @param {number} y The line in which to operate.
*/
Terminal.prototype.eraseLeft = function(x, y) {
- var line = this.lines[this.ybase + y]
+ var line = this.lines.get(this.ybase + y)
, ch = [this.eraseAttr(), ' ', 1]; // xterm
x++;
// Don't clear if it's already clear
return;
}
- this.lines = [this.lines[this.ybase + this.y]];
+ this.lines.set(0, this.lines.get(this.ybase + this.y));
+ this.lines.length = 1;
this.ydisp = 0;
this.ybase = 0;
this.y = 0;
ch = [this.eraseAttr(), ' ', 1]; // xterm
while (param-- && j < this.cols) {
- this.lines[row].splice(j++, 0, ch);
- this.lines[row].pop();
+ this.lines.get(row).splice(j++, 0, ch);
+ this.lines.get(row).pop();
}
};
ch = [this.eraseAttr(), ' ', 1]; // xterm
while (param-- && j < this.cols) {
- this.lines[row][j++] = ch;
+ this.lines.get(row)[j++] = ch;
}
};
*/
Terminal.prototype.repeatPrecedingCharacter = function(params) {
var param = params[0] || 1
- , line = this.lines[this.ybase + this.y]
+ , line = this.lines.get(this.ybase + this.y)
, ch = line[this.x - 1] || [this.defAttr, ' ', 1];
while (param--) line[this.x++] = ch;
, i;
for (; t < b + 1; t++) {
- line = this.lines[this.ybase + t];
+ line = this.lines.get(this.ybase + t);
for (i = l; i < r; i++) {
line[i] = [attr, line[i][1]];
}
, i;
for (; t < b + 1; t++) {
- line = this.lines[this.ybase + t];
+ line = this.lines.get(this.ybase + t);
for (i = l; i < r; i++) {
line[i] = [line[i][0], String.fromCharCode(ch)];
}
ch = [this.eraseAttr(), ' ', 1]; // xterm?
for (; t < b + 1; t++) {
- line = this.lines[this.ybase + t];
+ line = this.lines.get(this.ybase + t);
for (i = l; i < r; i++) {
line[i] = ch;
}