IBufferLine interface

This commit is contained in:
Jörg Breitbart
2018-08-30 17:52:45 +02:00
parent 9a54cf639b
commit 59fc4af9a0
19 changed files with 116 additions and 108 deletions
+10 -10
View File
@@ -8,7 +8,7 @@ import { ITerminal } from './Types';
import { Buffer, DEFAULT_ATTR } from './Buffer';
import { CircularList } from './common/CircularList';
import { MockTerminal } from './utils/TestUtils.test';
import { TerminalLine } from './TerminalLine';
import { BufferLine } from './TerminalLine';
const INIT_COLS = 80;
const INIT_ROWS = 24;
@@ -37,7 +37,7 @@ describe('Buffer', () => {
describe('fillViewportRows', () => {
it('should fill the buffer with blank lines based on the size of the viewport', () => {
const blankLineChar = TerminalLine.blankLine(terminal.cols, DEFAULT_ATTR).get(0);
const blankLineChar = BufferLine.blankLine(terminal.cols, DEFAULT_ATTR).get(0);
buffer.fillViewportRows();
assert.equal(buffer.lines.length, INIT_ROWS);
for (let y = 0; y < INIT_ROWS; y++) {
@@ -180,7 +180,7 @@ describe('Buffer', () => {
buffer.fillViewportRows();
// Create 10 extra blank lines
for (let i = 0; i < 10; i++) {
buffer.lines.push(TerminalLine.blankLine(terminal.cols, DEFAULT_ATTR));
buffer.lines.push(BufferLine.blankLine(terminal.cols, DEFAULT_ATTR));
}
// Set cursor to the bottom of the buffer
buffer.y = INIT_ROWS - 1;
@@ -200,7 +200,7 @@ describe('Buffer', () => {
buffer.fillViewportRows();
// Create 10 extra blank lines
for (let i = 0; i < 10; i++) {
buffer.lines.push(TerminalLine.blankLine(terminal.cols, DEFAULT_ATTR));
buffer.lines.push(BufferLine.blankLine(terminal.cols, DEFAULT_ATTR));
}
// Set cursor to the bottom of the buffer
buffer.y = INIT_ROWS - 1;
@@ -273,7 +273,7 @@ describe('Buffer', () => {
describe ('translateBufferLineToString', () => {
it('should handle selecting a section of ascii text', () => {
const line = new TerminalLine();
const line = new BufferLine();
line.push([ null, 'a', 1, 'a'.charCodeAt(0)]);
line.push([ null, 'b', 1, 'b'.charCodeAt(0)]);
line.push([ null, 'c', 1, 'c'.charCodeAt(0)]);
@@ -285,7 +285,7 @@ describe('Buffer', () => {
});
it('should handle a cut-off double width character by including it', () => {
const line = new TerminalLine();
const line = new BufferLine();
line.push([ null, '語', 2, 35486 ]);
line.push([ null, '', 0, null]);
line.push([ null, 'a', 1, 'a'.charCodeAt(0)]);
@@ -296,7 +296,7 @@ describe('Buffer', () => {
});
it('should handle a zero width character in the middle of the string by not including it', () => {
const line = new TerminalLine();
const line = new BufferLine();
line.push([ null, '語', 2, '語'.charCodeAt(0) ]);
line.push([ null, '', 0, null]);
line.push([ null, 'a', 1, 'a'.charCodeAt(0)]);
@@ -313,7 +313,7 @@ describe('Buffer', () => {
});
it('should handle single width emojis', () => {
const line = new TerminalLine();
const line = new BufferLine();
line.push([ null, '😁', 1, '😁'.charCodeAt(0) ]);
line.push([ null, 'a', 1, 'a'.charCodeAt(0)]);
buffer.lines.set(0, line);
@@ -326,7 +326,7 @@ describe('Buffer', () => {
});
it('should handle double width emojis', () => {
const line = new TerminalLine();
const line = new BufferLine();
line.push([ null, '😁', 2, '😁'.charCodeAt(0) ]);
line.push([ null, '', 0, null]);
buffer.lines.set(0, line);
@@ -337,7 +337,7 @@ describe('Buffer', () => {
const str2 = buffer.translateBufferLineToString(0, true, 0, 2);
assert.equal(str2, '😁');
const line2 = new TerminalLine();
const line2 = new BufferLine();
line2.push([ null, '😁', 2, '😁'.charCodeAt(0) ]);
line2.push([ null, '', 0, null]);
line2.push([ null, 'a', 1, 'a'.charCodeAt(0)]);
+6 -6
View File
@@ -4,10 +4,10 @@
*/
import { CircularList } from './common/CircularList';
import { CharData, ITerminal, IBuffer } from './Types';
import { CharData, ITerminal, IBuffer, IBufferLine } from './Types';
import { EventEmitter } from './EventEmitter';
import { IMarker } from 'xterm';
import { TerminalLine } from './TerminalLine';
import { BufferLine } from './TerminalLine';
export const DEFAULT_ATTR = (0 << 18) | (257 << 9) | (256 << 0);
export const CHAR_DATA_ATTR_INDEX = 0;
@@ -28,7 +28,7 @@ export const NULL_CELL_CODE = 32;
* - scroll position
*/
export class Buffer implements IBuffer {
public lines: CircularList<TerminalLine>;
public lines: CircularList<IBufferLine>;
public ydisp: number;
public ybase: number;
public y: number;
@@ -85,7 +85,7 @@ export class Buffer implements IBuffer {
if (this.lines.length === 0) {
let i = this._terminal.rows;
while (i--) {
this.lines.push(TerminalLine.blankLine(this._terminal.cols, DEFAULT_ATTR));
this.lines.push(BufferLine.blankLine(this._terminal.cols, DEFAULT_ATTR));
}
}
}
@@ -98,7 +98,7 @@ export class Buffer implements IBuffer {
this.ybase = 0;
this.y = 0;
this.x = 0;
this.lines = new CircularList<TerminalLine>(this._getCorrectBufferLength(this._terminal.rows));
this.lines = new CircularList<IBufferLine>(this._getCorrectBufferLength(this._terminal.rows));
this.scrollTop = 0;
this.scrollBottom = this._terminal.rows - 1;
this.setupTabStops();
@@ -147,7 +147,7 @@ export class Buffer implements IBuffer {
} 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(TerminalLine.blankLine(newCols, DEFAULT_ATTR));
this.lines.push(BufferLine.blankLine(newCols, DEFAULT_ATTR));
}
}
}
+6 -6
View File
@@ -7,8 +7,8 @@ import { assert, expect } from 'chai';
import { InputHandler } from './InputHandler';
import { MockInputHandlingTerminal } from './utils/TestUtils.test';
import { NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, CHAR_DATA_CHAR_INDEX } from './Buffer';
import { TerminalLine } from './TerminalLine';
import { Terminal } from './Terminal';
import { IBufferLine } from './Types';
describe('InputHandler', () => {
describe('save and restore cursor', () => {
@@ -90,7 +90,7 @@ describe('InputHandler', () => {
describe('regression tests', function(): void {
type CharData = [number, string, number, number];
function lineContent(line: TerminalLine): string {
function lineContent(line: IBufferLine): string {
let content = '';
for (let i = 0; i < line.length; ++i) content += line.get(i)[CHAR_DATA_CHAR_INDEX];
return content;
@@ -128,8 +128,8 @@ describe('InputHandler', () => {
inputHandler.parse('1234567890');
inputHandler.parse(Array(term.cols - 9).join('a'));
inputHandler.parse('1234567890');
const line1: TerminalLine = term.buffer.lines.get(0); // line for old variant
const line2: TerminalLine = term.buffer.lines.get(1); // line for new variant
const line1: IBufferLine = term.buffer.lines.get(0); // line for old variant
const line2: IBufferLine = term.buffer.lines.get(1); // line for new variant
expect(lineContent(line1)).equals(Array(term.cols - 9).join('a') + '1234567890');
expect(lineContent(line2)).equals(Array(term.cols - 9).join('a') + '1234567890');
@@ -205,8 +205,8 @@ describe('InputHandler', () => {
inputHandler.parse('1234567890');
inputHandler.parse(Array(term.cols - 9).join('a'));
inputHandler.parse('1234567890');
const line1: TerminalLine = term.buffer.lines.get(0); // line for old variant
const line2: TerminalLine = term.buffer.lines.get(1); // line for new variant
const line1: IBufferLine = term.buffer.lines.get(0); // line for old variant
const line2: IBufferLine = term.buffer.lines.get(1); // line for new variant
expect(lineContent(line1)).equals(Array(term.cols - 9).join('a') + '1234567890');
expect(lineContent(line2)).equals(Array(term.cols - 9).join('a') + '1234567890');
+5 -5
View File
@@ -13,7 +13,7 @@ import { wcwidth } from './CharWidth';
import { EscapeSequenceParser } from './EscapeSequenceParser';
import { ICharset } from './core/Types';
import { Disposable } from './common/Lifecycle';
import { TerminalLine } from './TerminalLine';
import { BufferLine } from './TerminalLine';
/**
* Map collect to glevel. Used in `selectCharset`.
@@ -832,7 +832,7 @@ export class InputHandler extends Disposable implements IInputHandler {
// test: echo -e '\e[44m\e[1L\e[0m'
// blankLine(true) - xterm/linux behavior
buffer.lines.splice(scrollBottomAbsolute - 1, 1);
buffer.lines.splice(row, 0, TerminalLine.blankLine(this._terminal.cols, this._terminal.eraseAttr()));
buffer.lines.splice(row, 0, BufferLine.blankLine(this._terminal.cols, this._terminal.eraseAttr()));
}
// this.maxRange();
@@ -862,7 +862,7 @@ export class InputHandler extends Disposable implements IInputHandler {
// test: echo -e '\e[44m\e[1M\e[0m'
// blankLine(true) - xterm/linux behavior
buffer.lines.splice(row, 1);
buffer.lines.splice(j, 0, TerminalLine.blankLine(this._terminal.cols, this._terminal.eraseAttr()));
buffer.lines.splice(j, 0, BufferLine.blankLine(this._terminal.cols, this._terminal.eraseAttr()));
}
// this.maxRange();
@@ -894,7 +894,7 @@ export class InputHandler extends Disposable implements IInputHandler {
while (param--) {
buffer.lines.splice(buffer.ybase + buffer.scrollTop, 1);
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, TerminalLine.blankLine(this._terminal.cols, DEFAULT_ATTR));
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, BufferLine.blankLine(this._terminal.cols, DEFAULT_ATTR));
}
// this.maxRange();
this._terminal.updateRange(buffer.scrollTop);
@@ -913,7 +913,7 @@ export class InputHandler extends Disposable implements IInputHandler {
while (param--) {
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 1);
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, TerminalLine.blankLine(this._terminal.cols, DEFAULT_ATTR));
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, BufferLine.blankLine(this._terminal.cols, DEFAULT_ATTR));
}
// this.maxRange();
this._terminal.updateRange(buffer.scrollTop);
+5 -5
View File
@@ -5,11 +5,11 @@
import { assert } from 'chai';
import { IMouseZoneManager, IMouseZone } from './ui/Types';
import { ILinkMatcher, ITerminal } from './Types';
import { ILinkMatcher, ITerminal, IBufferLine } from './Types';
import { Linkifier } from './Linkifier';
import { MockBuffer, MockTerminal } from './utils/TestUtils.test';
import { CircularList } from './common/CircularList';
import { TerminalLine } from './TerminalLine';
import { BufferLine } from './TerminalLine';
class TestLinkifier extends Linkifier {
constructor(terminal: ITerminal) {
@@ -43,14 +43,14 @@ describe('Linkifier', () => {
terminal = new MockTerminal();
terminal.cols = 100;
terminal.buffer = new MockBuffer();
(<MockBuffer>terminal.buffer).setLines(new CircularList<TerminalLine>(20));
(<MockBuffer>terminal.buffer).setLines(new CircularList<IBufferLine>(20));
terminal.buffer.ydisp = 0;
linkifier = new TestLinkifier(terminal);
mouseZoneManager = new TestMouseZoneManager();
});
function stringToRow(text: string): TerminalLine {
const result = new TerminalLine();
function stringToRow(text: string): IBufferLine {
const result = new BufferLine();
for (let i = 0; i < text.length; i++) {
result.push([0, text.charAt(i), 1, text.charCodeAt(i)]);
}
+2 -3
View File
@@ -4,10 +4,9 @@
*/
import { IMouseZoneManager } from './ui/Types';
import { ILinkHoverEvent, ILinkMatcher, LinkMatcherHandler, LinkHoverEventTypes, ILinkMatcherOptions, ILinkifier, ITerminal } from './Types';
import { ILinkHoverEvent, ILinkMatcher, LinkMatcherHandler, LinkHoverEventTypes, ILinkMatcherOptions, ILinkifier, ITerminal, IBufferLine } from './Types';
import { MouseZone } from './ui/MouseZoneManager';
import { EventEmitter } from './EventEmitter';
import { TerminalLine } from './TerminalLine';
import { CHAR_DATA_ATTR_INDEX } from './Buffer';
/**
@@ -171,7 +170,7 @@ export class Linkifier extends EventEmitter implements ILinkifier {
return;
}
// If the first row is wrapped, backtrack to find the origin row and linkify that
let line: TerminalLine;
let line: IBufferLine;
do {
rowIndex--;
+7 -7
View File
@@ -8,9 +8,9 @@ import { CharMeasure } from './ui/CharMeasure';
import { SelectionManager, SelectionMode } from './SelectionManager';
import { SelectionModel } from './SelectionModel';
import { BufferSet } from './BufferSet';
import { ITerminal, IBuffer } from './Types';
import { ITerminal, IBuffer, IBufferLine } from './Types';
import { MockTerminal } from './utils/TestUtils.test';
import { TerminalLine } from './TerminalLine';
import { BufferLine } from './TerminalLine';
class TestMockTerminal extends MockTerminal {
emit(event: string, data: any): void {}
@@ -53,16 +53,16 @@ describe('SelectionManager', () => {
selectionManager = new TestSelectionManager(terminal, null);
});
function stringToRow(text: string): TerminalLine {
const result = new TerminalLine();
function stringToRow(text: string): IBufferLine {
const result = new BufferLine();
for (let i = 0; i < text.length; i++) {
result.push([0, text.charAt(i), 1, text.charCodeAt(i)]);
}
return result;
}
function stringArrayToRow(chars: string[]): TerminalLine {
const line = new TerminalLine();
function stringArrayToRow(chars: string[]): IBufferLine {
const line = new BufferLine();
chars.map(c => line.push([0, c, 1, c.charCodeAt(0)]));
return line;
}
@@ -100,7 +100,7 @@ describe('SelectionManager', () => {
});
it('should expand selection for wide characters', () => {
// Wide characters use a special format
const line = new TerminalLine();
const line = new BufferLine();
const data: [number, string, number, number][] = [
[null, '中', 2, '中'.charCodeAt(0)],
[null, '', 0, null],
+2 -3
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { ITerminal, ISelectionManager, IBuffer, CharData, XtermListener } from './Types';
import { ITerminal, ISelectionManager, IBuffer, CharData, XtermListener, IBufferLine } from './Types';
import { MouseHelper } from './utils/MouseHelper';
import * as Browser from './shared/utils/Browser';
import { CharMeasure } from './ui/CharMeasure';
@@ -11,7 +11,6 @@ import { EventEmitter } from './EventEmitter';
import { SelectionModel } from './SelectionModel';
import { CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_CODE_INDEX } from './Buffer';
import { AltClickHandler } from './handlers/AltClickHandler';
import { TerminalLine } from './TerminalLine';
/**
* The number of pixels the mouse needs to be above or below the viewport in
@@ -662,7 +661,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
* latter takes into account wide characters.
* @param coords The coordinates to find the 2 index for.
*/
private _convertViewportColToCharacterIndex(bufferLine: TerminalLine, coords: [number, number]): number {
private _convertViewportColToCharacterIndex(bufferLine: IBufferLine, coords: [number, number]): number {
let charIndex = coords[0];
for (let i = 0; coords[0] >= i; i++) {
const char = bufferLine.get(i);
+4 -4
View File
@@ -7,7 +7,7 @@ import { assert, expect } from 'chai';
import { Terminal } from './Terminal';
import { MockViewport, MockCompositionHelper, MockRenderer } from './utils/TestUtils.test';
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, DEFAULT_ATTR } from './Buffer';
import { TerminalLine } from './TerminalLine';
import { BufferLine } from './TerminalLine';
const INIT_COLS = 80;
const INIT_ROWS = 24;
@@ -142,7 +142,7 @@ describe('term.js addons', () => {
assert.equal(term.buffer.lines.length, term.rows);
assert.deepEqual(term.buffer.lines.get(0), promptLine);
for (let i = 1; i < term.rows; i++) {
assert.deepEqual(term.buffer.lines.get(i), TerminalLine.blankLine(term.cols, DEFAULT_ATTR));
assert.deepEqual(term.buffer.lines.get(i), BufferLine.blankLine(term.cols, DEFAULT_ATTR));
}
});
it('should clear a buffer larger than rows', () => {
@@ -159,7 +159,7 @@ describe('term.js addons', () => {
assert.equal(term.buffer.lines.length, term.rows);
assert.deepEqual(term.buffer.lines.get(0), promptLine);
for (let i = 1; i < term.rows; i++) {
assert.deepEqual(term.buffer.lines.get(i), TerminalLine.blankLine(term.cols, DEFAULT_ATTR));
assert.deepEqual(term.buffer.lines.get(i), BufferLine.blankLine(term.cols, DEFAULT_ATTR));
}
});
it('should not break the prompt when cleared twice', () => {
@@ -172,7 +172,7 @@ describe('term.js addons', () => {
assert.equal(term.buffer.lines.length, term.rows);
assert.deepEqual(term.buffer.lines.get(0), promptLine);
for (let i = 1; i < term.rows; i++) {
assert.deepEqual(term.buffer.lines.get(i), TerminalLine.blankLine(term.cols, DEFAULT_ATTR));
assert.deepEqual(term.buffer.lines.get(i), BufferLine.blankLine(term.cols, DEFAULT_ATTR));
}
});
});
+4 -4
View File
@@ -52,7 +52,7 @@ import { DomRenderer } from './renderer/dom/DomRenderer';
import { IKeyboardEvent } from './common/Types';
import { evaluateKeyboardEvent } from './core/input/Keyboard';
import { KeyboardResultType, ICharset } from './core/Types';
import { TerminalLine } from './TerminalLine';
import { BufferLine } from './TerminalLine';
// Let it work inside Node.js for automated testing purposes.
const document = (typeof window !== 'undefined') ? window.document : null;
@@ -1171,7 +1171,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
* @param isWrapped Whether the new line is wrapped from the previous line.
*/
public scroll(isWrapped?: boolean): void {
const newLine = TerminalLine.blankLine(this.cols, DEFAULT_ATTR, isWrapped);
const newLine = BufferLine.blankLine(this.cols, DEFAULT_ATTR, isWrapped);
const topRow = this.buffer.ybase + this.buffer.scrollTop;
const bottomRow = this.buffer.ybase + this.buffer.scrollBottom;
@@ -1753,7 +1753,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
this.buffer.ybase = 0;
this.buffer.y = 0;
for (let i = 1; i < this.rows; i++) {
this.buffer.lines.push(TerminalLine.blankLine(this.cols, DEFAULT_ATTR));
this.buffer.lines.push(BufferLine.blankLine(this.cols, DEFAULT_ATTR));
}
this.refresh(0, this.rows - 1);
this.emit('scroll', this.buffer.ydisp);
@@ -1854,7 +1854,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
// blankLine(true) is xterm/linux behavior
const scrollRegionHeight = this.buffer.scrollBottom - this.buffer.scrollTop;
this.buffer.lines.shiftElements(this.buffer.y + this.buffer.ybase, scrollRegionHeight, 1);
this.buffer.lines.set(this.buffer.y + this.buffer.ybase, TerminalLine.blankLine(this.cols, this.eraseAttr()));
this.buffer.lines.set(this.buffer.y + this.buffer.ybase, BufferLine.blankLine(this.cols, this.eraseAttr()));
this.updateRange(this.buffer.scrollTop);
this.updateRange(this.buffer.scrollBottom);
} else {
+21 -14
View File
@@ -3,31 +3,38 @@
* @license MIT
*/
import * as chai from 'chai';
import { TerminalLine } from './TerminalLine';
import { CharData } from './Types';
import { BufferLine } from './TerminalLine';
import { CharData, IBufferLine } from './Types';
import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, CHAR_DATA_ATTR_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CODE_INDEX } from './Buffer';
describe('TerminalLine', function(): void {
class TestBufferLine extends BufferLine {
public toArray(): CharData[] {
return this._data;
}
}
describe('BufferLine', function(): void {
it('ctor', function(): void {
let line = new TerminalLine();
let line: IBufferLine = new TestBufferLine();
chai.expect(line.length).equals(0);
chai.expect(line.pop()).equals(undefined);
chai.expect(line.isWrapped).equals(false);
line = new TerminalLine(10);
line = new TestBufferLine(10);
chai.expect(line.length).equals(10);
chai.expect(line.pop()).eql(TerminalLine.defaultCell);
chai.expect(line.pop()).eql(TestBufferLine.defaultCell);
chai.expect(line.isWrapped).equals(false);
line = new TerminalLine(10, null, true);
line = new TestBufferLine(10, null, true);
chai.expect(line.length).equals(10);
chai.expect(line.pop()).eql(TerminalLine.defaultCell);
chai.expect(line.pop()).eql(TestBufferLine.defaultCell);
chai.expect(line.isWrapped).equals(true);
line = new TerminalLine(10, [123, 'a', 456, 789], true);
line = new TestBufferLine(10, [123, 'a', 456, 789], true);
chai.expect(line.length).equals(10);
chai.expect(line.pop()).eql([123, 'a', 456, 789]);
chai.expect(line.isWrapped).equals(true);
});
it('splice', function(): void {
const line = new TerminalLine();
const line = new TestBufferLine();
const data: CharData[] = [
[1, 'a', 0, 0],
[2, 'b', 0, 0],
@@ -41,7 +48,7 @@ describe('TerminalLine', function(): void {
chai.expect(line.toArray()).eql(data);
});
it('TerminalLine.blankLine', function(): void {
const line = TerminalLine.blankLine(5, 123);
const line = TestBufferLine.blankLine(5, 123);
chai.expect(line.length).equals(5);
chai.expect(line.isWrapped).equals(false);
const ch = line.get(0);
@@ -51,7 +58,7 @@ describe('TerminalLine', function(): void {
chai.expect(ch[CHAR_DATA_CODE_INDEX]).equals(NULL_CELL_CODE);
});
it('insertCells', function(): void {
const line = new TerminalLine();
const line = new TestBufferLine();
const data: CharData[] = [
[1, 'a', 0, 0],
[2, 'b', 0, 0],
@@ -62,7 +69,7 @@ describe('TerminalLine', function(): void {
chai.expect(line.toArray()).eql([[1, 'a', 0, 0], [4, 'd', 0, 0], [4, 'd', 0, 0]]);
});
it('deleteCells', function(): void {
const line = new TerminalLine();
const line = new TestBufferLine();
const data: CharData[] = [
[1, 'a', 0, 0],
[2, 'b', 0, 0],
@@ -75,7 +82,7 @@ describe('TerminalLine', function(): void {
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]]);
});
it('replaceCells', function(): void {
const line = new TerminalLine();
const line = new TestBufferLine();
const data: CharData[] = [
[1, 'a', 0, 0],
[2, 'b', 0, 0],
+6 -17
View File
@@ -2,7 +2,7 @@
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { CharData } from './Types';
import { CharData, IBufferLine } from './Types';
import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR } from './Buffer';
/**
@@ -20,13 +20,13 @@ import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR } from './Buffer';
* - remove push/pop/splice
* - implement typed array alternative once string is removed from CharData
*/
export class TerminalLine {
export class BufferLine implements IBufferLine {
static defaultCell: CharData = [0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE];
static blankLine(cols: number, attr: number, isWrapped?: boolean): TerminalLine {
static blankLine(cols: number, attr: number, isWrapped?: boolean): BufferLine {
const ch: CharData = [attr, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE];
return new TerminalLine(cols, ch, isWrapped);
return new BufferLine(cols, ch, isWrapped);
}
private _data: CharData[];
protected _data: CharData[];
public isWrapped = false;
public length: number;
@@ -35,7 +35,7 @@ export class TerminalLine {
this.length = this._data.length;
if (cols) {
if (!ch) {
ch = TerminalLine.defaultCell;
ch = BufferLine.defaultCell;
}
for (let i = 0; i < cols; i++) {
this.push(ch); // Note: the ctor ch is not cloned
@@ -57,7 +57,6 @@ export class TerminalLine {
// to be removed for typed array
public pop(): CharData | undefined {
// TODO: unref here, change CharData to [typeof Attributes, ...]
const data = this._data.pop();
this.length = this._data.length;
return data;
@@ -67,25 +66,15 @@ export class TerminalLine {
public push(data: CharData): void {
this._data.push(data);
this.length = this._data.length;
// TODO: ref here
}
// to be removed for typed array
public splice(start: number, deleteCount: number, ...items: CharData[]): CharData[] {
const removed = this._data.splice(start, deleteCount, ...items);
this.length = this._data.length;
// TODO: ref new, unref old
return removed;
}
/** to be called when a line gets removed */
public release(): void {
// TODO: unref here
}
public toArray(): CharData[] {
return this._data;
}
/** insert n cells ch at pos, right cells are lost (stable length) */
public insertCells(pos: number, n: number, ch: CharData): void {
while (n--) {
+17 -2
View File
@@ -7,7 +7,6 @@ import { Terminal as PublicTerminal, ITerminalOptions as IPublicTerminalOptions,
import { IColorSet, IRenderer } from './renderer/Types';
import { IMouseZoneManager } from './ui/Types';
import { ICharset } from './core/Types';
import { TerminalLine } from './TerminalLine';
export type CustomKeyEventHandler = (event: KeyboardEvent) => boolean;
@@ -272,7 +271,7 @@ export interface ITerminalOptions extends IPublicTerminalOptions {
}
export interface IBuffer {
readonly lines: ICircularList<TerminalLine>;
readonly lines: ICircularList<IBufferLine>;
ydisp: number;
ybase: number;
y: number;
@@ -511,3 +510,19 @@ export interface IEscapeSequenceParser extends IDisposable {
setErrorHandler(callback: (state: IParsingState) => IParsingState): void;
clearErrorHandler(): void;
}
/**
* Interface for a line in the terminal buffer.
*/
export interface IBufferLine {
length: number;
isWrapped: boolean;
get(index: number): CharData;
set(index: number, value: CharData): void;
pop(): CharData | undefined;
push(data: CharData): void;
splice(start: number, deleteCount: number, ...items: CharData[]): CharData[];
insertCells(pos: number, n: number, ch: CharData): void;
deleteCells(pos: number, n: number, fill: CharData): void;
replaceCells(start: number, end: number, fill: CharData): void;
}
+2 -3
View File
@@ -3,9 +3,8 @@
* @license MIT
*/
import { ITerminal, ICircularList } from '../Types';
import { ITerminal, ICircularList, IBufferLine } from '../Types';
import { C0 } from '../common/data/EscapeSequences';
import { TerminalLine } from '../TerminalLine';
const enum Direction {
UP = 'A',
@@ -19,7 +18,7 @@ export class AltClickHandler {
private _startCol: number;
private _endRow: number;
private _endCol: number;
private _lines: ICircularList<TerminalLine>;
private _lines: ICircularList<IBufferLine>;
constructor(
private _mouseEvent: MouseEvent,
+6 -5
View File
@@ -5,7 +5,8 @@ import { CircularList } from '../common/CircularList';
import { ICharacterJoinerRegistry } from './Types';
import { CharacterJoinerRegistry } from './CharacterJoinerRegistry';
import { TerminalLine } from '../TerminalLine';
import { BufferLine } from '../TerminalLine';
import { IBufferLine } from '../Types';
describe('CharacterJoinerRegistry', () => {
let registry: ICharacterJoinerRegistry;
@@ -14,13 +15,13 @@ describe('CharacterJoinerRegistry', () => {
const terminal = new MockTerminal();
terminal.cols = 16;
terminal.buffer = new MockBuffer();
const lines = new CircularList<TerminalLine>(7);
const lines = new CircularList<IBufferLine>(7);
lines.set(0, lineData([['a -> b -> c -> d']]));
lines.set(1, lineData([['a -> b => c -> d']]));
lines.set(2, lineData([['a -> b -', 0xFFFFFFFF], ['> c -> d', 0]]));
lines.set(3, lineData([['no joined ranges']]));
lines.set(4, new TerminalLine());
lines.set(4, new BufferLine());
lines.set(5, lineData([['a', 0x11111111], [' -> b -> c -> '], ['d', 0x22222222]]));
const line6 = lineData([['wi']]);
line6.push([0, '¥', 2, '¥'.charCodeAt(0)]);
@@ -262,8 +263,8 @@ describe('CharacterJoinerRegistry', () => {
type IPartialLineData = ([string] | [string, number]);
function lineData(data: IPartialLineData[]): TerminalLine {
const tline = new TerminalLine();
function lineData(data: IPartialLineData[]): IBufferLine {
const tline = new BufferLine();
for (let i = 0; i < data.length; ++i) {
const line = data[i][0];
const attr = <number>(data[i][1] || 0);
+3 -4
View File
@@ -1,7 +1,6 @@
import { CHAR_DATA_ATTR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX } from '../Buffer';
import { ITerminal } from '../Types';
import { ITerminal, IBufferLine } from '../Types';
import { ICharacterJoinerRegistry, ICharacterJoiner } from './Types';
import { TerminalLine } from '../TerminalLine';
export class CharacterJoinerRegistry implements ICharacterJoinerRegistry {
@@ -116,7 +115,7 @@ export class CharacterJoinerRegistry implements ICharacterJoinerRegistry {
* @param startIndex Start position of the range to search in the string (inclusive)
* @param endIndex End position of the range to search in the string (exclusive)
*/
private _getJoinedRanges(line: string, startIndex: number, endIndex: number, lineData: TerminalLine, startCol: number): [number, number][] {
private _getJoinedRanges(line: string, startIndex: number, endIndex: number, lineData: IBufferLine, startCol: number): [number, number][] {
const text = line.substring(startIndex, endIndex);
// At this point we already know that there is at least one joiner so
// we can just pull its value and assign it directly rather than
@@ -141,7 +140,7 @@ export class CharacterJoinerRegistry implements ICharacterJoinerRegistry {
* @param line Cell data for the relevant line in the terminal
* @param startCol Offset within the line to start from
*/
private _stringRangesToCellRanges(ranges: [number, number][], line: TerminalLine, startCol: number): void {
private _stringRangesToCellRanges(ranges: [number, number][], line: IBufferLine, startCol: number): void {
let currentRangeIndex = 0;
let currentRangeStarted = false;
let currentStringIndex = 0;
@@ -8,12 +8,13 @@ import { assert } from 'chai';
import { DomRendererRowFactory } from './DomRendererRowFactory';
import { DEFAULT_ATTR, NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR } from '../../Buffer';
import { FLAGS } from '../Types';
import { TerminalLine } from '../../TerminalLine';
import { BufferLine } from '../../TerminalLine';
import { IBufferLine } from '../../Types';
describe('DomRendererRowFactory', () => {
let dom: jsdom.JSDOM;
let rowFactory: DomRendererRowFactory;
let lineData: TerminalLine;
let lineData: IBufferLine;
beforeEach(() => {
dom = new jsdom.JSDOM('');
@@ -146,8 +147,8 @@ describe('DomRendererRowFactory', () => {
return element.innerHTML;
}
function createEmptyLineData(cols: number): TerminalLine {
const lineData = new TerminalLine();
function createEmptyLineData(cols: number): IBufferLine {
const lineData = new BufferLine();
for (let i = 0; i < cols; i++) {
lineData.push([DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
}
+2 -2
View File
@@ -5,7 +5,7 @@
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_ATTR_INDEX, CHAR_DATA_WIDTH_INDEX } from '../../Buffer';
import { FLAGS } from '../Types';
import { TerminalLine } from '../../TerminalLine';
import { IBufferLine } from '../../Types';
export const BOLD_CLASS = 'xterm-bold';
export const ITALIC_CLASS = 'xterm-italic';
@@ -17,7 +17,7 @@ export class DomRendererRowFactory {
) {
}
public createRow(lineData: TerminalLine, isCursorRow: boolean, cursorX: number, cellWidth: number, cols: number): DocumentFragment {
public createRow(lineData: IBufferLine, isCursorRow: boolean, cursorX: number, cellWidth: number, cols: number): DocumentFragment {
const fragment = this._document.createDocumentFragment();
let colCount = 0;
+3 -4
View File
@@ -4,11 +4,10 @@
*/
import { IColorSet, IRenderer, IRenderDimensions, IColorManager } from '../renderer/Types';
import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminal, IBuffer, IBufferSet, IBrowser, ICharMeasure, ISelectionManager, ITerminalOptions, ICircularList, ILinkifier, IMouseHelper, ILinkMatcherOptions, XtermListener, CharacterJoinerHandler } from '../Types';
import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminal, IBuffer, IBufferSet, IBrowser, ICharMeasure, ISelectionManager, ITerminalOptions, ICircularList, ILinkifier, IMouseHelper, ILinkMatcherOptions, XtermListener, CharacterJoinerHandler, IBufferLine } from '../Types';
import { Buffer } from '../Buffer';
import * as Browser from '../shared/utils/Browser';
import { ITheme, IDisposable, IMarker } from 'xterm';
import { TerminalLine } from '../TerminalLine';
export class MockTerminal implements ITerminal {
markers: IMarker[];
@@ -285,7 +284,7 @@ export class MockInputHandlingTerminal implements IInputHandlingTerminal {
export class MockBuffer implements IBuffer {
isCursorInViewport: boolean;
lines: ICircularList<TerminalLine>;
lines: ICircularList<IBufferLine>;
ydisp: number;
ybase: number;
hasScrollback: boolean;
@@ -308,7 +307,7 @@ export class MockBuffer implements IBuffer {
prevStop(x?: number): number {
throw new Error('Method not implemented.');
}
setLines(lines: ICircularList<TerminalLine>): void {
setLines(lines: ICircularList<IBufferLine>): void {
this.lines = lines;
}
}