mirror of
https://git.proxmox.com/git/mirror_xterm.js
synced 2025-10-28 00:29:51 +00:00
Merge pull request #422 from Tyriar/361_circular_list_scrollback
Use a circular list to manage buffer
This commit is contained in:
commit
e6ad8d8b50
@ -59,7 +59,7 @@ function terminalToString(term) {
|
||||
for (var line=0; line<term.rows; ++line) {
|
||||
line_s = '';
|
||||
for (var cell=0; cell<term.cols; ++cell) {
|
||||
line_s += term.lines[line][cell][1];
|
||||
line_s += term.lines.get(line)[cell][1];
|
||||
}
|
||||
// rtrim empty cells as xterm does
|
||||
line_s = line_s.replace(/\s+$/, '');
|
||||
@ -83,7 +83,6 @@ describe('xterm output comparison', function() {
|
||||
var files = glob.sync('**/escape_sequence_files/*.in');
|
||||
// only successful tests for now
|
||||
var successful = [0, 2, 6, 12, 13, 18, 20, 22, 27, 28];
|
||||
console.log(files);
|
||||
for (var a in successful) {
|
||||
var i = successful[a];
|
||||
(function(filename){
|
||||
@ -92,7 +91,7 @@ describe('xterm output comparison', function() {
|
||||
var in_file = fs.readFileSync(filename, 'utf8');
|
||||
var from_pty = pty_write_read(in_file);
|
||||
// uncomment this to get log from terminal
|
||||
console.log = function(){};
|
||||
//console.log = function(){};
|
||||
xterm.write(from_pty);
|
||||
var from_emulator = terminalToString(xterm);
|
||||
console.log = CONSOLE_LOG;
|
||||
|
||||
140
src/test/test.js
140
src/test/test.js
@ -48,15 +48,15 @@ describe('xterm.js', function() {
|
||||
|
||||
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() {
|
||||
@ -65,28 +65,28 @@ describe('xterm.js', 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());
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -543,11 +543,11 @@ 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[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();
|
||||
}
|
||||
});
|
||||
@ -556,9 +556,9 @@ describe('xterm.js', function() {
|
||||
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();
|
||||
}
|
||||
});
|
||||
@ -568,10 +568,10 @@ describe('xterm.js', function() {
|
||||
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();
|
||||
}
|
||||
});
|
||||
@ -581,9 +581,9 @@ describe('xterm.js', function() {
|
||||
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();
|
||||
}
|
||||
});
|
||||
@ -592,11 +592,11 @@ describe('xterm.js', function() {
|
||||
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();
|
||||
}
|
||||
});
|
||||
@ -605,30 +605,30 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -637,12 +637,12 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -665,7 +665,7 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -676,7 +676,7 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -686,7 +686,7 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -697,11 +697,11 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -711,7 +711,7 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -722,11 +722,11 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -735,7 +735,7 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -746,7 +746,7 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -756,7 +756,7 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -767,11 +767,11 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -780,7 +780,7 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -791,7 +791,7 @@ describe('xterm.js', function() {
|
||||
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);
|
||||
@ -805,11 +805,11 @@ describe('xterm.js', function() {
|
||||
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));
|
||||
@ -817,12 +817,12 @@ describe('xterm.js', function() {
|
||||
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('¥'));
|
||||
@ -830,15 +830,15 @@ describe('xterm.js', function() {
|
||||
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
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
255
src/utils/CircularList.test.ts
Normal file
255
src/utils/CircularList.test.ts
Normal file
@ -0,0 +1,255 @@
|
||||
import { assert } from 'chai';
|
||||
import { CircularList } from './CircularList';
|
||||
|
||||
describe('CircularList', () => {
|
||||
describe('push', () => {
|
||||
it('should push values onto the array', () => {
|
||||
const list = new CircularList<string>(5);
|
||||
list.push('1');
|
||||
list.push('2');
|
||||
list.push('3');
|
||||
list.push('4');
|
||||
list.push('5');
|
||||
assert.equal(list.get(0), '1');
|
||||
assert.equal(list.get(1), '2');
|
||||
assert.equal(list.get(2), '3');
|
||||
assert.equal(list.get(3), '4');
|
||||
assert.equal(list.get(4), '5');
|
||||
});
|
||||
|
||||
it('should push old values from the start out of the array when max length is reached', () => {
|
||||
const list = new CircularList<string>(2);
|
||||
list.push('1');
|
||||
list.push('2');
|
||||
assert.equal(list.get(0), '1');
|
||||
assert.equal(list.get(1), '2');
|
||||
list.push('3');
|
||||
assert.equal(list.get(0), '2');
|
||||
assert.equal(list.get(1), '3');
|
||||
list.push('4');
|
||||
assert.equal(list.get(0), '3');
|
||||
assert.equal(list.get(1), '4');
|
||||
});
|
||||
});
|
||||
|
||||
describe('maxLength', () => {
|
||||
it('should increase the size of the list', () => {
|
||||
const list = new CircularList<string>(2);
|
||||
list.push('1');
|
||||
list.push('2');
|
||||
assert.equal(list.get(0), '1');
|
||||
assert.equal(list.get(1), '2');
|
||||
list.maxLength = 4;
|
||||
list.push('3');
|
||||
list.push('4');
|
||||
assert.equal(list.get(0), '1');
|
||||
assert.equal(list.get(1), '2');
|
||||
assert.equal(list.get(2), '3');
|
||||
assert.equal(list.get(3), '4');
|
||||
list.push('wrapped');
|
||||
assert.equal(list.get(0), '2');
|
||||
assert.equal(list.get(1), '3');
|
||||
assert.equal(list.get(2), '4');
|
||||
assert.equal(list.get(3), 'wrapped');
|
||||
});
|
||||
|
||||
it('should return the maximum length of the list', () => {
|
||||
const list = new CircularList<string>(2);
|
||||
assert.equal(list.maxLength, 2);
|
||||
list.push('1');
|
||||
list.push('2');
|
||||
assert.equal(list.maxLength, 2);
|
||||
list.push('3');
|
||||
assert.equal(list.maxLength, 2);
|
||||
list.maxLength = 4;
|
||||
assert.equal(list.maxLength, 4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('length', () => {
|
||||
it('should return the current length of the list, capped at the maximum length', () => {
|
||||
const list = new CircularList<string>(2);
|
||||
assert.equal(list.length, 0);
|
||||
list.push('1');
|
||||
assert.equal(list.length, 1);
|
||||
list.push('2');
|
||||
assert.equal(list.length, 2);
|
||||
list.push('3');
|
||||
assert.equal(list.length, 2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('splice', () => {
|
||||
it('should delete items', () => {
|
||||
const list = new CircularList<string>(2);
|
||||
list.push('1');
|
||||
list.push('2');
|
||||
list.splice(0, 1);
|
||||
assert.equal(list.length, 1);
|
||||
assert.equal(list.get(0), '2');
|
||||
list.push('3');
|
||||
list.splice(1, 1);
|
||||
assert.equal(list.length, 1);
|
||||
assert.equal(list.get(0), '2');
|
||||
});
|
||||
|
||||
it('should insert items', () => {
|
||||
const list = new CircularList<string>(2);
|
||||
list.push('1');
|
||||
list.splice(0, 0, '2');
|
||||
assert.equal(list.length, 2);
|
||||
assert.equal(list.get(0), '2');
|
||||
assert.equal(list.get(1), '1');
|
||||
list.splice(1, 0, '3');
|
||||
assert.equal(list.length, 2);
|
||||
assert.equal(list.get(0), '3');
|
||||
assert.equal(list.get(1), '1');
|
||||
});
|
||||
|
||||
it('should delete items then insert items', () => {
|
||||
const list = new CircularList<string>(3);
|
||||
list.push('1');
|
||||
list.push('2');
|
||||
list.splice(0, 1, '3', '4');
|
||||
assert.equal(list.length, 3);
|
||||
assert.equal(list.get(0), '3');
|
||||
assert.equal(list.get(1), '4');
|
||||
assert.equal(list.get(2), '2');
|
||||
});
|
||||
|
||||
it('should wrap the array correctly when more items are inserted than deleted', () => {
|
||||
const list = new CircularList<string>(3);
|
||||
list.push('1');
|
||||
list.push('2');
|
||||
list.splice(1, 0, '3', '4');
|
||||
assert.equal(list.length, 3);
|
||||
assert.equal(list.get(0), '3');
|
||||
assert.equal(list.get(1), '4');
|
||||
assert.equal(list.get(2), '2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('trimStart', () => {
|
||||
it('should remove items from the beginning of the list', () => {
|
||||
const list = new CircularList<string>(5);
|
||||
list.push('1');
|
||||
list.push('2');
|
||||
list.push('3');
|
||||
list.push('4');
|
||||
list.push('5');
|
||||
list.trimStart(1);
|
||||
assert.equal(list.length, 4);
|
||||
assert.deepEqual(list.get(0), '2');
|
||||
assert.deepEqual(list.get(1), '3');
|
||||
assert.deepEqual(list.get(2), '4');
|
||||
assert.deepEqual(list.get(3), '5');
|
||||
list.trimStart(2);
|
||||
assert.equal(list.length, 2);
|
||||
assert.deepEqual(list.get(0), '4');
|
||||
assert.deepEqual(list.get(1), '5');
|
||||
});
|
||||
|
||||
it('should remove all items if the requested trim amount is larger than the list\'s length', () => {
|
||||
const list = new CircularList<string>(5);
|
||||
list.push('1');
|
||||
list.trimStart(2);
|
||||
assert.equal(list.length, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shiftElements', () => {
|
||||
it('should not mutate the list when count is 0', () => {
|
||||
const list = new CircularList<number>(5);
|
||||
list.push(1);
|
||||
list.push(2);
|
||||
list.shiftElements(0, 0, 1);
|
||||
assert.equal(list.length, 2);
|
||||
assert.equal(list.get(0), 1);
|
||||
assert.equal(list.get(1), 2);
|
||||
});
|
||||
|
||||
it('should throw for invalid args', () => {
|
||||
const list = new CircularList<number>(5);
|
||||
list.push(1);
|
||||
assert.throws(() => list.shiftElements(-1, 1, 1), 'start argument out of range');
|
||||
assert.throws(() => list.shiftElements(1, 1, 1), 'start argument out of range');
|
||||
assert.throws(() => list.shiftElements(0, 1, -1), 'Cannot shift elements in list beyond index 0');
|
||||
});
|
||||
|
||||
it('should shift an element forward', () => {
|
||||
const list = new CircularList<number>(5);
|
||||
list.push(1);
|
||||
list.push(2);
|
||||
list.shiftElements(0, 1, 1);
|
||||
assert.equal(list.length, 2);
|
||||
assert.equal(list.get(0), 1);
|
||||
assert.equal(list.get(1), 1);
|
||||
});
|
||||
|
||||
it('should shift elements forward', () => {
|
||||
const list = new CircularList<number>(5);
|
||||
list.push(1);
|
||||
list.push(2);
|
||||
list.push(3);
|
||||
list.push(4);
|
||||
list.shiftElements(0, 2, 2);
|
||||
assert.equal(list.length, 4);
|
||||
assert.equal(list.get(0), 1);
|
||||
assert.equal(list.get(1), 2);
|
||||
assert.equal(list.get(2), 1);
|
||||
assert.equal(list.get(3), 2);
|
||||
});
|
||||
|
||||
it('should shift elements forward, expanding the list if needed', () => {
|
||||
const list = new CircularList<number>(5);
|
||||
list.push(1);
|
||||
list.push(2);
|
||||
list.shiftElements(0, 2, 2);
|
||||
assert.equal(list.length, 4);
|
||||
assert.equal(list.get(0), 1);
|
||||
assert.equal(list.get(1), 2);
|
||||
assert.equal(list.get(2), 1);
|
||||
assert.equal(list.get(3), 2);
|
||||
});
|
||||
|
||||
it('should shift elements forward, wrapping the list if needed', () => {
|
||||
const list = new CircularList<number>(5);
|
||||
list.push(1);
|
||||
list.push(2);
|
||||
list.push(3);
|
||||
list.push(4);
|
||||
list.push(5);
|
||||
list.shiftElements(2, 2, 3);
|
||||
assert.equal(list.length, 5);
|
||||
assert.equal(list.get(0), 3);
|
||||
assert.equal(list.get(1), 4);
|
||||
assert.equal(list.get(2), 5);
|
||||
assert.equal(list.get(3), 3);
|
||||
assert.equal(list.get(4), 4);
|
||||
});
|
||||
|
||||
it('should shift an element backwards', () => {
|
||||
const list = new CircularList<number>(5);
|
||||
list.push(1);
|
||||
list.push(2);
|
||||
list.shiftElements(1, 1, -1);
|
||||
assert.equal(list.length, 2);
|
||||
assert.equal(list.get(0), 2);
|
||||
assert.equal(list.get(1), 2);
|
||||
});
|
||||
|
||||
it('should shift elements backwards', () => {
|
||||
const list = new CircularList<number>(5);
|
||||
list.push(1);
|
||||
list.push(2);
|
||||
list.push(3);
|
||||
list.push(4);
|
||||
list.shiftElements(2, 2, -2);
|
||||
assert.equal(list.length, 4);
|
||||
assert.equal(list.get(0), 3);
|
||||
assert.equal(list.get(1), 4);
|
||||
assert.equal(list.get(2), 3);
|
||||
assert.equal(list.get(3), 4);
|
||||
});
|
||||
});
|
||||
});
|
||||
183
src/utils/CircularList.ts
Normal file
183
src/utils/CircularList.ts
Normal file
@ -0,0 +1,183 @@
|
||||
/**
|
||||
* Represents a circular list; a list with a maximum size that wraps around when push is called,
|
||||
* overriding values at the start of the list.
|
||||
* @module xterm/utils/CircularList
|
||||
* @license MIT
|
||||
*/
|
||||
export class CircularList<T> {
|
||||
private _array: T[];
|
||||
private _startIndex: number;
|
||||
private _length: number;
|
||||
|
||||
constructor(maxLength: number) {
|
||||
this._array = new Array<T>(maxLength);
|
||||
this._startIndex = 0;
|
||||
this._length = 0;
|
||||
}
|
||||
|
||||
public get maxLength(): number {
|
||||
return this._array.length;
|
||||
}
|
||||
|
||||
public set maxLength(newMaxLength: number) {
|
||||
// Reconstruct array, starting at index 0. Only transfer values from the
|
||||
// indexes 0 to length.
|
||||
let newArray = new Array<T>(newMaxLength);
|
||||
for (let i = 0; i < Math.min(newMaxLength, this.length); i++) {
|
||||
newArray[i] = this._array[this._getCyclicIndex(i)];
|
||||
}
|
||||
this._array = newArray;
|
||||
this._startIndex = 0;
|
||||
}
|
||||
|
||||
public get length(): number {
|
||||
return this._length;
|
||||
}
|
||||
|
||||
public set length(newLength: number) {
|
||||
if (newLength > this._length) {
|
||||
for (let i = this._length; i < newLength; i++) {
|
||||
this._array[i] = undefined;
|
||||
}
|
||||
}
|
||||
this._length = newLength;
|
||||
}
|
||||
|
||||
public get forEach(): (callbackfn: (value: T, index: number, array: T[]) => void) => void {
|
||||
return this._array.forEach;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value at an index.
|
||||
*
|
||||
* Note that for performance reasons there is no bounds checking here, the index reference is
|
||||
* circular so this should always return a value and never throw.
|
||||
* @param index The index of the value to get.
|
||||
* @return The value corresponding to the index.
|
||||
*/
|
||||
public get(index: number): T {
|
||||
return this._array[this._getCyclicIndex(index)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value at an index.
|
||||
*
|
||||
* Note that for performance reasons there is no bounds checking here, the index reference is
|
||||
* circular so this should always return a value and never throw.
|
||||
* @param index The index to set.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
public set(index: number, value: T): void {
|
||||
this._array[this._getCyclicIndex(index)] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a new value onto the list, wrapping around to the start of the array, overriding index 0
|
||||
* if the maximum length is reached.
|
||||
* @param value The value to push onto the list.
|
||||
*/
|
||||
public push(value: T): void {
|
||||
this._array[this._getCyclicIndex(this._length)] = value;
|
||||
if (this._length === this.maxLength) {
|
||||
this._startIndex++;
|
||||
if (this._startIndex === this.maxLength) {
|
||||
this._startIndex = 0;
|
||||
}
|
||||
} else {
|
||||
this._length++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns the last value on the list.
|
||||
* @return The popped value.
|
||||
*/
|
||||
public pop(): T {
|
||||
return this._array[this._getCyclicIndex(this._length-- - 1)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes and/or inserts items at a particular index (in that order). Unlike
|
||||
* Array.prototype.splice, this operation does not return the deleted items as a new array in
|
||||
* order to save creating a new array. Note that this operation may shift all values in the list
|
||||
* in the worst case.
|
||||
* @param start The index to delete and/or insert.
|
||||
* @param deleteCount The number of elements to delete.
|
||||
* @param items The items to insert.
|
||||
*/
|
||||
public splice(start: number, deleteCount: number, ...items: T[]): void {
|
||||
if (deleteCount) {
|
||||
for (let i = start; i < this._length - deleteCount; i++) {
|
||||
this._array[this._getCyclicIndex(i)] = this._array[this._getCyclicIndex(i + deleteCount)];
|
||||
}
|
||||
this._length -= deleteCount;
|
||||
}
|
||||
if (items && items.length) {
|
||||
for (let i = this._length - 1; i >= start; i--) {
|
||||
this._array[this._getCyclicIndex(i + items.length)] = this._array[this._getCyclicIndex(i)];
|
||||
}
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
this._array[this._getCyclicIndex(start + i)] = items[i];
|
||||
}
|
||||
|
||||
if (this._length + items.length > this.maxLength) {
|
||||
this._startIndex += (this._length + items.length) - this.maxLength;
|
||||
this._length = this.maxLength;
|
||||
} else {
|
||||
this._length += items.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims a number of items from the start of the list.
|
||||
* @param count The number of items to remove.
|
||||
*/
|
||||
public trimStart(count: number): void {
|
||||
if (count > this._length) {
|
||||
count = this._length;
|
||||
}
|
||||
this._startIndex += count;
|
||||
this._length -= count;
|
||||
}
|
||||
|
||||
public shiftElements(start: number, count: number, offset: number): void {
|
||||
if (count <= 0) {
|
||||
return;
|
||||
}
|
||||
if (start < 0 || start >= this._length) {
|
||||
throw new Error('start argument out of range');
|
||||
}
|
||||
if (start + offset < 0) {
|
||||
throw new Error('Cannot shift elements in list beyond index 0');
|
||||
}
|
||||
|
||||
if (offset > 0) {
|
||||
for (let i = count - 1; i >= 0; i--) {
|
||||
this.set(start + i + offset, this.get(start + i));
|
||||
}
|
||||
const expandListBy = (start + count + offset) - this._length;
|
||||
if (expandListBy > 0) {
|
||||
this._length += expandListBy;
|
||||
while (this._length > this.maxLength) {
|
||||
this._length--;
|
||||
this._startIndex++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < count; i++) {
|
||||
this.set(start + i + offset, this.get(start + i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cyclic index for the specified regular index. The cyclic index can then be used on the
|
||||
* backing array to get the element associated with the regular index.
|
||||
* @param index The regular index.
|
||||
* @returns The cyclic index.
|
||||
*/
|
||||
private _getCyclicIndex(index: number): number {
|
||||
return (this._startIndex + index) % this.maxLength;
|
||||
}
|
||||
}
|
||||
120
src/xterm.js
120
src/xterm.js
@ -14,6 +14,7 @@ import { CompositionHelper } from './CompositionHelper.js';
|
||||
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';
|
||||
|
||||
@ -208,7 +209,7 @@ function Terminal(options) {
|
||||
* 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());
|
||||
@ -1078,7 +1079,7 @@ Terminal.prototype.refresh = function(start, end, queue) {
|
||||
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)
|
||||
@ -1228,16 +1229,14 @@ Terminal.prototype.showCursor = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Scroll the terminal
|
||||
* Scroll the terminal down 1 row, creating a blank line.
|
||||
*/
|
||||
Terminal.prototype.scroll = function() {
|
||||
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++;
|
||||
|
||||
// TODO: Why is this done twice?
|
||||
if (!this.userScrolling) {
|
||||
this.ydisp = this.ybase;
|
||||
}
|
||||
@ -1249,10 +1248,12 @@ Terminal.prototype.scroll = function() {
|
||||
row -= this.rows - 1 - this.scrollBottom;
|
||||
|
||||
if (row === this.lines.length) {
|
||||
// potential optimization:
|
||||
// pushing is faster than splicing
|
||||
// when they amount to the same
|
||||
// behavior.
|
||||
// Compensate ybase and ydisp if lines has hit the maximum buffer size
|
||||
if (this.lines.length === this.lines.maxLength) {
|
||||
this.ybase--;
|
||||
this.ydisp--;
|
||||
}
|
||||
// Optimization: pushing is faster than splicing when they amount to the same behavior
|
||||
this.lines.push(this.blankLine());
|
||||
} else {
|
||||
// add our new line
|
||||
@ -1370,7 +1371,6 @@ Terminal.prototype.write = function(data) {
|
||||
// surrogate low - already handled above
|
||||
if (0xDC00 <= code && code <= 0xDFFF)
|
||||
continue;
|
||||
|
||||
switch (this.state) {
|
||||
case normal:
|
||||
switch (ch) {
|
||||
@ -1440,17 +1440,16 @@ Terminal.prototype.write = function(data) {
|
||||
// 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);
|
||||
}
|
||||
@ -1482,24 +1481,24 @@ Terminal.prototype.write = function(data) {
|
||||
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++;
|
||||
}
|
||||
}
|
||||
@ -2866,15 +2865,15 @@ Terminal.prototype.resize = function(x, y) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3029,7 +3028,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[this.ybase + y]
|
||||
var line = this.lines.get(this.ybase + y)
|
||||
, ch = [this.eraseAttr(), ' ', 1]; // xterm
|
||||
|
||||
|
||||
@ -3048,7 +3047,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[this.ybase + y]
|
||||
var line = this.lines.get(this.ybase + y)
|
||||
, ch = [this.eraseAttr(), ' ', 1]; // xterm
|
||||
|
||||
x++;
|
||||
@ -3065,7 +3064,8 @@ Terminal.prototype.clear = function() {
|
||||
// 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;
|
||||
@ -3086,7 +3086,7 @@ Terminal.prototype.eraseLine = function(y) {
|
||||
|
||||
|
||||
/**
|
||||
* Return the data array of a blank line/
|
||||
* Return the data array of a blank line
|
||||
* @param {number} cur First bunch of data for each "blank" character.
|
||||
*/
|
||||
Terminal.prototype.blankLine = function(cur) {
|
||||
@ -3174,21 +3174,21 @@ Terminal.prototype.index = function() {
|
||||
|
||||
/**
|
||||
* ESC M Reverse Index (RI is 0x8d).
|
||||
*
|
||||
* Move the cursor up one row, inserting a new blank line if necessary.
|
||||
*/
|
||||
Terminal.prototype.reverseIndex = function() {
|
||||
var j;
|
||||
this.y--;
|
||||
if (this.y < this.scrollTop) {
|
||||
this.y++;
|
||||
if (this.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.lines.splice(this.y + this.ybase, 0, this.blankLine(true));
|
||||
j = this.rows - 1 - this.scrollBottom;
|
||||
this.lines.splice(this.rows - 1 + this.ybase - j + 1, 1);
|
||||
// this.maxRange();
|
||||
this.lines.shiftElements(this.y + this.ybase, this.rows - 1, 1);
|
||||
this.lines.set(this.y + this.ybase, this.blankLine(true));
|
||||
this.updateRange(this.scrollTop);
|
||||
this.updateRange(this.scrollBottom);
|
||||
} else {
|
||||
this.y--;
|
||||
}
|
||||
this.state = normal;
|
||||
};
|
||||
@ -3644,8 +3644,8 @@ Terminal.prototype.insertChars = function(params) {
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
@ -3705,6 +3705,14 @@ Terminal.prototype.insertLines = function(params) {
|
||||
j = this.rows - 1 + this.ybase - j + 1;
|
||||
|
||||
while (param--) {
|
||||
if (this.lines.length === this.lines.maxLength) {
|
||||
// Trim the start of lines to make room for the new line
|
||||
this.lines.trimStart(1);
|
||||
this.ybase--;
|
||||
this.ydisp--;
|
||||
row--;
|
||||
j--;
|
||||
}
|
||||
// test: echo -e '\e[44m\e[1L\e[0m'
|
||||
// blankLine(true) - xterm/linux behavior
|
||||
this.lines.splice(row, 0, this.blankLine(true));
|
||||
@ -3732,6 +3740,12 @@ Terminal.prototype.deleteLines = function(params) {
|
||||
j = this.rows - 1 + this.ybase - j;
|
||||
|
||||
while (param--) {
|
||||
if (this.lines.length === this.lines.maxLength) {
|
||||
// Trim the start of lines to make room for the new line
|
||||
this.lines.trimStart(1);
|
||||
this.ybase -= 1;
|
||||
this.ydisp -= 1;
|
||||
}
|
||||
// test: echo -e '\e[44m\e[1M\e[0m'
|
||||
// blankLine(true) - xterm/linux behavior
|
||||
this.lines.splice(j + 1, 0, this.blankLine(true));
|
||||
@ -3758,8 +3772,8 @@ Terminal.prototype.deleteChars = function(params) {
|
||||
ch = [this.eraseAttr(), ' ', 1]; // xterm
|
||||
|
||||
while (param--) {
|
||||
this.lines[row].splice(this.x, 1);
|
||||
this.lines[row].push(ch);
|
||||
this.lines.get(row).splice(this.x, 1);
|
||||
this.lines.get(row).push(ch);
|
||||
}
|
||||
};
|
||||
|
||||
@ -3778,7 +3792,7 @@ Terminal.prototype.eraseChars = function(params) {
|
||||
ch = [this.eraseAttr(), ' ', 1]; // xterm
|
||||
|
||||
while (param-- && j < this.cols) {
|
||||
this.lines[row][j++] = ch;
|
||||
this.lines.get(row)[j++] = ch;
|
||||
}
|
||||
};
|
||||
|
||||
@ -4442,7 +4456,7 @@ Terminal.prototype.cursorBackwardTab = function(params) {
|
||||
*/
|
||||
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;
|
||||
@ -4677,7 +4691,7 @@ Terminal.prototype.setAttrInRectangle = function(params) {
|
||||
, 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]];
|
||||
}
|
||||
@ -4707,7 +4721,7 @@ Terminal.prototype.fillRectangle = function(params) {
|
||||
, 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)];
|
||||
}
|
||||
@ -4759,7 +4773,7 @@ Terminal.prototype.eraseRectangle = function(params) {
|
||||
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;
|
||||
}
|
||||
@ -4784,8 +4798,8 @@ Terminal.prototype.insertColumns = function() {
|
||||
|
||||
while (param--) {
|
||||
for (i = this.ybase; i < l; i++) {
|
||||
this.lines[i].splice(this.x + 1, 0, ch);
|
||||
this.lines[i].pop();
|
||||
this.lines.get(i).splice(this.x + 1, 0, ch);
|
||||
this.lines.get(i).pop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -4806,8 +4820,8 @@ Terminal.prototype.deleteColumns = function() {
|
||||
|
||||
while (param--) {
|
||||
for (i = this.ybase; i < l; i++) {
|
||||
this.lines[i].splice(this.x, 1);
|
||||
this.lines[i].push(ch);
|
||||
this.lines.get(i).splice(this.x, 1);
|
||||
this.lines.get(i).push(ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user