mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
typed array based BufferLine
This commit is contained in:
+6
-2
@@ -155,8 +155,12 @@ describe('Buffer', () => {
|
||||
assert.equal(buffer.lines.maxLength, INIT_ROWS);
|
||||
buffer.y = INIT_ROWS - 1;
|
||||
buffer.fillViewportRows();
|
||||
buffer.lines.get(5).get(0)[1] = 'a';
|
||||
buffer.lines.get(INIT_ROWS - 1).get(0)[1] = 'b';
|
||||
let chData = buffer.lines.get(5).get(0);
|
||||
chData[1] = 'a';
|
||||
buffer.lines.get(5).set(0, chData);
|
||||
chData = buffer.lines.get(INIT_ROWS - 1).get(0);
|
||||
chData[1] = 'b';
|
||||
buffer.lines.get(INIT_ROWS - 1).set(0, chData);
|
||||
buffer.resize(INIT_COLS, INIT_ROWS - 5);
|
||||
assert.equal(buffer.lines.get(0).get(0)[1], 'a');
|
||||
assert.equal(buffer.lines.get(INIT_ROWS - 1 - 5).get(0)[1], 'b');
|
||||
|
||||
+42
-22
@@ -10,7 +10,11 @@ import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, CHAR_DATA_ATTR_INDEX,
|
||||
|
||||
class TestBufferLine extends BufferLine {
|
||||
public toArray(): CharData[] {
|
||||
return this._data;
|
||||
const result = [];
|
||||
for (let i = 0; i < this.length; ++i) {
|
||||
result.push(this.get(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +31,9 @@ describe('BufferLine', function(): void {
|
||||
chai.expect(line.length).equals(10);
|
||||
chai.expect(line.get(0)).eql([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
|
||||
chai.expect(line.isWrapped).equals(true);
|
||||
line = new TestBufferLine(10, [123, 'a', 456, 789], true);
|
||||
line = new TestBufferLine(10, [123, 'a', 456, 'a'.charCodeAt(0)], true);
|
||||
chai.expect(line.length).equals(10);
|
||||
chai.expect(line.get(0)).eql([123, 'a', 456, 789]);
|
||||
chai.expect(line.get(0)).eql([123, 'a', 456, 'a'.charCodeAt(0)]);
|
||||
chai.expect(line.isWrapped).equals(true);
|
||||
});
|
||||
it('TerminalLine.blankLine', function(): void {
|
||||
@@ -44,30 +48,46 @@ describe('BufferLine', function(): void {
|
||||
});
|
||||
it('insertCells', function(): void {
|
||||
const line = new TestBufferLine(3);
|
||||
line.set(0, [1, 'a', 0, 0]);
|
||||
line.set(1, [2, 'b', 0, 0]);
|
||||
line.set(2, [3, 'c', 0, 0]);
|
||||
line.insertCells(1, 3, [4, 'd', 0, 0]);
|
||||
chai.expect(line.toArray()).eql([[1, 'a', 0, 0], [4, 'd', 0, 0], [4, 'd', 0, 0]]);
|
||||
line.set(0, [1, 'a', 0, 'a'.charCodeAt(0)]);
|
||||
line.set(1, [2, 'b', 0, 'b'.charCodeAt(0)]);
|
||||
line.set(2, [3, 'c', 0, 'c'.charCodeAt(0)]);
|
||||
line.insertCells(1, 3, [4, 'd', 0, 'd'.charCodeAt(0)]);
|
||||
chai.expect(line.toArray()).eql([
|
||||
[1, 'a', 0, 'a'.charCodeAt(0)],
|
||||
[4, 'd', 0, 'd'.charCodeAt(0)],
|
||||
[4, 'd', 0, 'd'.charCodeAt(0)]
|
||||
]);
|
||||
});
|
||||
it('deleteCells', function(): void {
|
||||
const line = new TestBufferLine(5);
|
||||
line.set(0, [1, 'a', 0, 0]);
|
||||
line.set(1, [2, 'b', 0, 0]);
|
||||
line.set(2, [3, 'c', 0, 0]);
|
||||
line.set(3, [4, 'd', 0, 0]);
|
||||
line.set(4, [5, 'e', 0, 0]);
|
||||
line.deleteCells(1, 2, [6, 'f', 0, 0]);
|
||||
chai.expect(line.toArray()).eql([[1, 'a', 0, 0], [4, 'd', 0, 0], [5, 'e', 0, 0], [6, 'f', 0, 0], [6, 'f', 0, 0]]);
|
||||
line.set(0, [1, 'a', 0, 'a'.charCodeAt(0)]);
|
||||
line.set(1, [2, 'b', 0, 'b'.charCodeAt(0)]);
|
||||
line.set(2, [3, 'c', 0, 'c'.charCodeAt(0)]);
|
||||
line.set(3, [4, 'd', 0, 'd'.charCodeAt(0)]);
|
||||
line.set(4, [5, 'e', 0, 'e'.charCodeAt(0)]);
|
||||
line.deleteCells(1, 2, [6, 'f', 0, 'f'.charCodeAt(0)]);
|
||||
chai.expect(line.toArray()).eql([
|
||||
[1, 'a', 0, 'a'.charCodeAt(0)],
|
||||
[4, 'd', 0, 'd'.charCodeAt(0)],
|
||||
[5, 'e', 0, 'e'.charCodeAt(0)],
|
||||
[6, 'f', 0, 'f'.charCodeAt(0)],
|
||||
[6, 'f', 0, 'f'.charCodeAt(0)]
|
||||
]);
|
||||
});
|
||||
it('replaceCells', function(): void {
|
||||
const line = new TestBufferLine(5);
|
||||
line.set(0, [1, 'a', 0, 0]);
|
||||
line.set(1, [2, 'b', 0, 0]);
|
||||
line.set(2, [3, 'c', 0, 0]);
|
||||
line.set(3, [4, 'd', 0, 0]);
|
||||
line.set(4, [5, 'e', 0, 0]);
|
||||
line.replaceCells(2, 4, [6, 'f', 0, 0]);
|
||||
chai.expect(line.toArray()).eql([[1, 'a', 0, 0], [2, 'b', 0, 0], [6, 'f', 0, 0], [6, 'f', 0, 0], [5, 'e', 0, 0]]);
|
||||
line.set(0, [1, 'a', 0, 'a'.charCodeAt(0)]);
|
||||
line.set(1, [2, 'b', 0, 'b'.charCodeAt(0)]);
|
||||
line.set(2, [3, 'c', 0, 'c'.charCodeAt(0)]);
|
||||
line.set(3, [4, 'd', 0, 'd'.charCodeAt(0)]);
|
||||
line.set(4, [5, 'e', 0, 'e'.charCodeAt(0)]);
|
||||
line.replaceCells(2, 4, [6, 'f', 0, 'f'.charCodeAt(0)]);
|
||||
chai.expect(line.toArray()).eql([
|
||||
[1, 'a', 0, 'a'.charCodeAt(0)],
|
||||
[2, 'b', 0, 'b'.charCodeAt(0)],
|
||||
[6, 'f', 0, 'f'.charCodeAt(0)],
|
||||
[6, 'f', 0, 'f'.charCodeAt(0)],
|
||||
[5, 'e', 0, 'e'.charCodeAt(0)]
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
+118
-2
@@ -8,10 +8,10 @@ import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR } from './Buffer';
|
||||
/**
|
||||
* Class representing a terminal line.
|
||||
*/
|
||||
export class BufferLine implements IBufferLine {
|
||||
export class BufferLineOld implements IBufferLine {
|
||||
static blankLine(cols: number, attr: number, isWrapped?: boolean): IBufferLine {
|
||||
const ch: CharData = [attr, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE];
|
||||
return new BufferLine(cols, ch, isWrapped);
|
||||
return new BufferLineOld(cols, ch, isWrapped);
|
||||
}
|
||||
protected _data: CharData[];
|
||||
public isWrapped = false;
|
||||
@@ -107,3 +107,119 @@ export class BufferLine implements IBufferLine {
|
||||
this.length = cols;
|
||||
}
|
||||
}
|
||||
|
||||
const enum Cell {
|
||||
FLAGS = 0,
|
||||
STRING = 1,
|
||||
WIDTH = 2,
|
||||
SIZE = 3
|
||||
}
|
||||
|
||||
export class BufferLine implements IBufferLine {
|
||||
static blankLine(cols: number, attr: number, isWrapped?: boolean): IBufferLine {
|
||||
const ch: CharData = [attr, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE];
|
||||
return new BufferLine(cols, ch, isWrapped);
|
||||
}
|
||||
protected _data: Uint32Array | null = null;
|
||||
protected _combined: {[index: number]: string} = {};
|
||||
public length: number;
|
||||
|
||||
constructor(cols?: number, ch?: CharData, public isWrapped: boolean = false) {
|
||||
this.length = cols || 0;
|
||||
if (cols) {
|
||||
if (!ch) {
|
||||
ch = [0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE];
|
||||
}
|
||||
this._data = new Uint32Array(cols * Cell.SIZE);
|
||||
for (let i = 0; i < cols; ++i) {
|
||||
this.set(i, ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get(index: number): CharData {
|
||||
const stringData = this._data[index * Cell.SIZE + Cell.STRING];
|
||||
return [
|
||||
this._data[index * Cell.SIZE + Cell.FLAGS],
|
||||
(stringData & 0x80000000)
|
||||
? this._combined[index]
|
||||
: (stringData) ? String.fromCharCode(stringData) : '',
|
||||
this._data[index * Cell.SIZE + Cell.WIDTH],
|
||||
stringData & ~0x80000000
|
||||
];
|
||||
}
|
||||
|
||||
public set(index: number, value: CharData): void {
|
||||
this._data[index * Cell.SIZE + Cell.FLAGS] = value[0];
|
||||
if (value[1].length > 1) {
|
||||
this._combined[index] = value[1];
|
||||
this._data[index * Cell.SIZE + Cell.STRING] = index | 0x80000000;
|
||||
} else {
|
||||
this._data[index * Cell.SIZE + Cell.STRING] = value[1].charCodeAt(0);
|
||||
}
|
||||
this._data[index * Cell.SIZE + Cell.WIDTH] = value[2];
|
||||
}
|
||||
|
||||
public insertCells(pos: number, n: number, fill: CharData): void {
|
||||
pos %= this.length;
|
||||
if (n < this.length - pos) {
|
||||
for (let i = this.length - pos - n - 1; i >= 0; --i) {
|
||||
this.set(pos + n + i, this.get(pos + i));
|
||||
}
|
||||
for (let i = 0; i < n; ++i) {
|
||||
this.set(pos + i, fill);
|
||||
}
|
||||
} else {
|
||||
for (let i = pos; i < this.length; ++i) {
|
||||
this.set(i, fill);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public deleteCells(pos: number, n: number, fill: CharData): void {
|
||||
pos %= this.length;
|
||||
if (n < this.length - pos) {
|
||||
for (let i = 0; i < this.length - pos - n; ++i) {
|
||||
this.set(pos + i, this.get(pos + n + i));
|
||||
}
|
||||
for (let i = this.length - n; i < this.length; ++i) {
|
||||
this.set(i, fill);
|
||||
}
|
||||
} else {
|
||||
for (let i = pos; i < this.length; ++i) {
|
||||
this.set(i, fill);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public replaceCells(start: number, end: number, fill: CharData): void {
|
||||
while (start < end && start < this.length) {
|
||||
this.set(start++, fill);
|
||||
}
|
||||
}
|
||||
|
||||
public resize(cols: number, fill: CharData, shrink: boolean = false): void {
|
||||
if (cols === this.length) {
|
||||
return;
|
||||
}
|
||||
if (cols > this.length) {
|
||||
const data = new Uint32Array(cols * Cell.SIZE);
|
||||
if (this._data) {
|
||||
data.set(this._data);
|
||||
}
|
||||
this._data = data;
|
||||
for (let i = this.length; i < cols; ++i) {
|
||||
this.set(i, fill);
|
||||
}
|
||||
} else if (shrink) {
|
||||
if (cols) {
|
||||
const data = new Uint32Array(cols * Cell.SIZE);
|
||||
data.set(this._data.subarray(0, this.length));
|
||||
this._data = data;
|
||||
} else {
|
||||
this._data = null;
|
||||
}
|
||||
}
|
||||
this.length = cols;
|
||||
}
|
||||
}
|
||||
|
||||
+31
-31
@@ -338,8 +338,8 @@ describe('term.js addons', () => {
|
||||
describe('scroll() function', () => {
|
||||
describe('when scrollback > 0', () => {
|
||||
it('should create a new line and scroll', () => {
|
||||
term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX] = 'a';
|
||||
term.buffer.lines.get(INIT_ROWS - 1).get(0)[CHAR_DATA_CHAR_INDEX] = 'b';
|
||||
term.buffer.lines.get(0).set(0, [0, 'a', 0, 'a'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(INIT_ROWS - 1).set(0, [0, 'b', 0, 'b'.charCodeAt(0)]);
|
||||
term.buffer.y = INIT_ROWS - 1; // Move cursor to last line
|
||||
term.scroll();
|
||||
assert.equal(term.buffer.lines.length, INIT_ROWS + 1);
|
||||
@@ -349,9 +349,9 @@ describe('term.js addons', () => {
|
||||
});
|
||||
|
||||
it('should properly scroll inside a scroll region (scrollTop set)', () => {
|
||||
term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX] = 'a';
|
||||
term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX] = 'b';
|
||||
term.buffer.lines.get(2).get(0)[CHAR_DATA_CHAR_INDEX] = 'c';
|
||||
term.buffer.lines.get(0).set(0, [0, 'a', 0, 'a'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(1).set(0, [0, 'b', 0, 'b'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(2).set(0, [0, 'c', 0, 'c'.charCodeAt(0)]);
|
||||
term.buffer.y = INIT_ROWS - 1; // Move cursor to last line
|
||||
term.buffer.scrollTop = 1;
|
||||
term.scroll();
|
||||
@@ -361,11 +361,11 @@ describe('term.js addons', () => {
|
||||
});
|
||||
|
||||
it('should properly scroll inside a scroll region (scrollBottom set)', () => {
|
||||
term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX] = 'a';
|
||||
term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX] = 'b';
|
||||
term.buffer.lines.get(2).get(0)[CHAR_DATA_CHAR_INDEX] = 'c';
|
||||
term.buffer.lines.get(3).get(0)[CHAR_DATA_CHAR_INDEX] = 'd';
|
||||
term.buffer.lines.get(4).get(0)[CHAR_DATA_CHAR_INDEX] = 'e';
|
||||
term.buffer.lines.get(0).set(0, [0, 'a', 0, 'a'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(1).set(0, [0, 'b', 0, 'b'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(2).set(0, [0, 'c', 0, 'c'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(3).set(0, [0, 'd', 0, 'd'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(4).set(0, [0, 'e', 0, 'e'.charCodeAt(0)]);
|
||||
term.buffer.y = 3;
|
||||
term.buffer.scrollBottom = 3;
|
||||
term.scroll();
|
||||
@@ -379,11 +379,11 @@ describe('term.js addons', () => {
|
||||
});
|
||||
|
||||
it('should properly scroll inside a scroll region (scrollTop and scrollBottom set)', () => {
|
||||
term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX] = 'a';
|
||||
term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX] = 'b';
|
||||
term.buffer.lines.get(2).get(0)[CHAR_DATA_CHAR_INDEX] = 'c';
|
||||
term.buffer.lines.get(3).get(0)[CHAR_DATA_CHAR_INDEX] = 'd';
|
||||
term.buffer.lines.get(4).get(0)[CHAR_DATA_CHAR_INDEX] = 'e';
|
||||
term.buffer.lines.get(0).set(0, [0, 'a', 0, 'a'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(1).set(0, [0, 'b', 0, 'b'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(2).set(0, [0, 'c', 0, 'c'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(3).set(0, [0, 'd', 0, 'd'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(4).set(0, [0, 'e', 0, 'e'.charCodeAt(0)]);
|
||||
term.buffer.y = INIT_ROWS - 1; // Move cursor to last line
|
||||
term.buffer.scrollTop = 1;
|
||||
term.buffer.scrollBottom = 3;
|
||||
@@ -404,9 +404,9 @@ describe('term.js addons', () => {
|
||||
});
|
||||
|
||||
it('should create a new line and shift everything up', () => {
|
||||
term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX] = 'a';
|
||||
term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX] = 'b';
|
||||
term.buffer.lines.get(INIT_ROWS - 1).get(0)[CHAR_DATA_CHAR_INDEX] = 'c';
|
||||
term.buffer.lines.get(0).set(0, [0, 'a', 0, 'a'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(1).set(0, [0, 'b', 0, 'b'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(INIT_ROWS - 1).set(0, [0, 'c', 0, 'c'.charCodeAt(0)]);
|
||||
term.buffer.y = INIT_ROWS - 1; // Move cursor to last line
|
||||
assert.equal(term.buffer.lines.length, INIT_ROWS);
|
||||
term.scroll();
|
||||
@@ -419,9 +419,9 @@ describe('term.js addons', () => {
|
||||
});
|
||||
|
||||
it('should properly scroll inside a scroll region (scrollTop set)', () => {
|
||||
term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX] = 'a';
|
||||
term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX] = 'b';
|
||||
term.buffer.lines.get(2).get(0)[CHAR_DATA_CHAR_INDEX] = 'c';
|
||||
term.buffer.lines.get(0).set(0, [0, 'a', 0, 'a'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(1).set(0, [0, 'b', 0, 'b'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(2).set(0, [0, 'c', 0, 'c'.charCodeAt(0)]);
|
||||
term.buffer.y = INIT_ROWS - 1; // Move cursor to last line
|
||||
term.buffer.scrollTop = 1;
|
||||
term.scroll();
|
||||
@@ -431,11 +431,11 @@ describe('term.js addons', () => {
|
||||
});
|
||||
|
||||
it('should properly scroll inside a scroll region (scrollBottom set)', () => {
|
||||
term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX] = 'a';
|
||||
term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX] = 'b';
|
||||
term.buffer.lines.get(2).get(0)[CHAR_DATA_CHAR_INDEX] = 'c';
|
||||
term.buffer.lines.get(3).get(0)[CHAR_DATA_CHAR_INDEX] = 'd';
|
||||
term.buffer.lines.get(4).get(0)[CHAR_DATA_CHAR_INDEX] = 'e';
|
||||
term.buffer.lines.get(0).set(0, [0, 'a', 0, 'a'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(1).set(0, [0, 'b', 0, 'b'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(2).set(0, [0, 'c', 0, 'c'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(3).set(0, [0, 'd', 0, 'd'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(4).set(0, [0, 'e', 0, 'e'.charCodeAt(0)]);
|
||||
term.buffer.y = 3;
|
||||
term.buffer.scrollBottom = 3;
|
||||
term.scroll();
|
||||
@@ -448,11 +448,11 @@ describe('term.js addons', () => {
|
||||
});
|
||||
|
||||
it('should properly scroll inside a scroll region (scrollTop and scrollBottom set)', () => {
|
||||
term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX] = 'a';
|
||||
term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX] = 'b';
|
||||
term.buffer.lines.get(2).get(0)[CHAR_DATA_CHAR_INDEX] = 'c';
|
||||
term.buffer.lines.get(3).get(0)[CHAR_DATA_CHAR_INDEX] = 'd';
|
||||
term.buffer.lines.get(4).get(0)[CHAR_DATA_CHAR_INDEX] = 'e';
|
||||
term.buffer.lines.get(0).set(0, [0, 'a', 0, 'a'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(1).set(0, [0, 'b', 0, 'b'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(2).set(0, [0, 'c', 0, 'c'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(3).set(0, [0, 'd', 0, 'd'.charCodeAt(0)]);
|
||||
term.buffer.lines.get(4).set(0, [0, 'e', 0, 'e'.charCodeAt(0)]);
|
||||
term.buffer.y = INIT_ROWS - 1; // Move cursor to last line
|
||||
term.buffer.scrollTop = 1;
|
||||
term.buffer.scrollBottom = 3;
|
||||
|
||||
Reference in New Issue
Block a user