Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove js array based buffer line #1877

Merged
merged 1 commit into from
Jan 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions demo/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,7 @@ function initOptions(term: TerminalType): void {
fontFamily: null,
fontWeight: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
fontWeightBold: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
rendererType: ['dom', 'canvas'],
experimentalBufferLineImpl: ['JsArray', 'TypedArray']
rendererType: ['dom', 'canvas']
};
const options = Object.keys((<any>term)._core.options);
const booleanOptions = [];
Expand Down
36 changes: 4 additions & 32 deletions src/Buffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
*/

import { CircularList } from './common/CircularList';
import { CharData, ITerminal, IBuffer, IBufferLine, BufferIndex, IBufferStringIterator, IBufferStringIteratorResult, IBufferLineConstructor } from './Types';
import { CharData, ITerminal, IBuffer, IBufferLine, BufferIndex, IBufferStringIterator, IBufferStringIteratorResult } from './Types';
import { EventEmitter } from './common/EventEmitter';
import { IMarker } from 'xterm';
import { BufferLine, BufferLineJSArray } from './BufferLine';
import { BufferLine } from './BufferLine';
import { DEFAULT_COLOR } from './renderer/atlas/Types';

export const DEFAULT_ATTR = (0 << 18) | (DEFAULT_COLOR << 9) | (256 << 0);
Expand Down Expand Up @@ -45,7 +45,6 @@ export class Buffer implements IBuffer {
public savedX: number;
public savedCurAttr: number;
public markers: Marker[] = [];
private _bufferLineConstructor: IBufferLineConstructor;

/**
* Create a new Buffer.
Expand All @@ -60,35 +59,9 @@ export class Buffer implements IBuffer {
this.clear();
}

public setBufferLineFactory(type: string): void {
if (type === 'JsArray') {
if (this._bufferLineConstructor !== BufferLineJSArray) {
this._bufferLineConstructor = BufferLineJSArray;
this._recreateLines();
}
} else {
if (this._bufferLineConstructor !== BufferLine) {
this._bufferLineConstructor = BufferLine;
this._recreateLines();
}
}
}

private _recreateLines(): void {
if (!this.lines) return;
for (let i = 0; i < this.lines.length; ++i) {
const oldLine = this.lines.get(i);
const newLine = new this._bufferLineConstructor(oldLine.length);
for (let j = 0; j < oldLine.length; ++j) {
newLine.set(j, oldLine.get(j));
}
this.lines.set(i, newLine);
}
}

public getBlankLine(attr: number, isWrapped?: boolean): IBufferLine {
const fillCharData: CharData = [attr, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE];
return new this._bufferLineConstructor(this._terminal.cols, fillCharData, isWrapped);
return new BufferLine(this._terminal.cols, fillCharData, isWrapped);
}

public get hasScrollback(): boolean {
Expand Down Expand Up @@ -135,7 +108,6 @@ export class Buffer implements IBuffer {
* Clears the buffer to it's initial state, discarding all previous data.
*/
public clear(): void {
this.setBufferLineFactory(this._terminal.options.experimentalBufferLineImpl);
this.ydisp = 0;
this.ybase = 0;
this.y = 0;
Expand Down Expand Up @@ -188,7 +160,7 @@ export class Buffer implements IBuffer {
// 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
const fillCharData: CharData = [DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE];
this.lines.push(new this._bufferLineConstructor(newCols, fillCharData));
this.lines.push(new BufferLine(newCols, fillCharData));
}
}
}
Expand Down
127 changes: 1 addition & 126 deletions src/BufferLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,133 +3,8 @@
* @license MIT
*/
import { CharData, IBufferLine } from './Types';
import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, WHITESPACE_CELL_CHAR } from './Buffer';
import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, WHITESPACE_CELL_CHAR } from './Buffer';

/**
* Class representing a terminal line.
*
* @deprecated to be removed with one of the next releases
*/
export class BufferLineJSArray implements IBufferLine {
protected _data: CharData[];
public isWrapped = false;
public length: number;

constructor(cols: number, fillCharData?: CharData, isWrapped?: boolean) {
this._data = [];
if (!fillCharData) {
fillCharData = [0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE];
}
for (let i = 0; i < cols; i++) {
this._push(fillCharData); // Note: the ctor ch is not cloned (resembles old behavior)
}
if (isWrapped) {
this.isWrapped = true;
}
this.length = this._data.length;
}

private _pop(): CharData | undefined {
const data = this._data.pop();
this.length = this._data.length;
return data;
}

private _push(data: CharData): void {
this._data.push(data);
this.length = this._data.length;
}

private _splice(start: number, deleteCount: number, ...items: CharData[]): CharData[] {
const removed = this._data.splice(start, deleteCount, ...items);
this.length = this._data.length;
return removed;
}

public get(index: number): CharData {
return this._data[index];
}

public set(index: number, data: CharData): void {
this._data[index] = data;
}

/** insert n cells ch at pos, right cells are lost (stable length) */
public insertCells(pos: number, n: number, ch: CharData): void {
while (n--) {
this._splice(pos, 0, ch);
this._pop();
}
}

/** delete n cells at pos, right side is filled with fill (stable length) */
public deleteCells(pos: number, n: number, fillCharData: CharData): void {
while (n--) {
this._splice(pos, 1);
this._push(fillCharData);
}
}

/** replace cells from pos to pos + n - 1 with fill */
public replaceCells(start: number, end: number, fillCharData: CharData): void {
while (start < end && start < this.length) {
this.set(start++, fillCharData); // Note: fill is not cloned (resembles old behavior)
}
}

/** resize line to cols filling new cells with fill */
public resize(cols: number, fillCharData: CharData, shrink: boolean = false): void {
while (this._data.length < cols) {
this._data.push(fillCharData);
}
if (shrink) {
while (this._data.length > cols) {
this._data.pop();
}
}
this.length = this._data.length;
}

public fill(fillCharData: CharData): void {
for (let i = 0; i < this.length; ++i) {
this.set(i, fillCharData);
}
}

public copyFrom(line: BufferLineJSArray): void {
this._data = line._data.slice(0);
this.length = line.length;
this.isWrapped = line.isWrapped;
}

public clone(): IBufferLine {
const newLine = new BufferLineJSArray(0);
newLine.copyFrom(this);
return newLine;
}

public getTrimmedLength(): number {
for (let i = this.length - 1; i >= 0; --i) {
const ch = this.get(i);
if (ch[CHAR_DATA_CHAR_INDEX] !== '') {
return i + ch[CHAR_DATA_WIDTH_INDEX];
}
}
return 0;
}

public translateToString(trimRight: boolean = false, startCol: number = 0, endCol: number = this.length): string {
if (trimRight) {
endCol = Math.min(endCol, this.getTrimmedLength());
}
let result = '';
while (startCol < endCol) {
result += this.get(startCol)[CHAR_DATA_CHAR_INDEX] || WHITESPACE_CELL_CHAR;
startCol += this.get(startCol)[CHAR_DATA_WIDTH_INDEX] || 1;
}
return result;
}
}

/** typed array slots taken by one cell */
const CELL_SIZE = 3;
Expand Down
35 changes: 10 additions & 25 deletions src/Terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ const DEFAULT_OPTIONS: ITerminalOptions = {
tabStopWidth: 8,
theme: null,
rightClickSelectsWord: Browser.isMac,
rendererType: 'canvas',
experimentalBufferLineImpl: 'TypedArray'
rendererType: 'canvas'
};

export class Terminal extends EventEmitter implements ITerminal, IDisposable, IInputHandlingTerminal {
Expand Down Expand Up @@ -497,11 +496,6 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
}
break;
case 'tabStopWidth': this.buffers.setupTabStops(); break;
case 'experimentalBufferLineImpl':
this.buffers.normal.setBufferLineFactory(value);
this.buffers.alt.setBufferLineFactory(value);
this._blankLine = null;
break;
}
// Inform renderer of changes
if (this.renderer) {
Expand Down Expand Up @@ -1180,17 +1174,12 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
*/
public scroll(isWrapped: boolean = false): void {
let newLine: IBufferLine;
const useRecycling = this.options.experimentalBufferLineImpl !== 'JsArray';
if (useRecycling) {
newLine = this._blankLine;
if (!newLine || newLine.length !== this.cols || newLine.get(0)[CHAR_DATA_ATTR_INDEX] !== this.eraseAttr()) {
newLine = this.buffer.getBlankLine(this.eraseAttr(), isWrapped);
this._blankLine = newLine;
}
newLine.isWrapped = isWrapped;
} else {
newLine = this._blankLine;
if (!newLine || newLine.length !== this.cols || newLine.get(0)[CHAR_DATA_ATTR_INDEX] !== this.eraseAttr()) {
newLine = this.buffer.getBlankLine(this.eraseAttr(), isWrapped);
this._blankLine = newLine;
}
newLine.isWrapped = isWrapped;

const topRow = this.buffer.ybase + this.buffer.scrollTop;
const bottomRow = this.buffer.ybase + this.buffer.scrollBottom;
Expand All @@ -1201,17 +1190,13 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II

// Insert the line using the fastest method
if (bottomRow === this.buffer.lines.length - 1) {
if (useRecycling) {
if (willBufferBeTrimmed) {
this.buffer.lines.recycle().copyFrom(newLine);
} else {
this.buffer.lines.push(newLine.clone());
}
if (willBufferBeTrimmed) {
this.buffer.lines.recycle().copyFrom(newLine);
} else {
this.buffer.lines.push(newLine);
this.buffer.lines.push(newLine.clone());
}
} else {
this.buffer.lines.splice(bottomRow + 1, 0, (useRecycling) ? newLine.clone() : newLine);
this.buffer.lines.splice(bottomRow + 1, 0, newLine.clone());
}

// Only adjust ybase and ydisp when the buffer is not trimmed
Expand All @@ -1233,7 +1218,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
// scrollback, instead we can just shift them in-place.
const scrollRegionHeight = bottomRow - topRow + 1/*as it's zero-based*/;
this.buffer.lines.shiftElements(topRow + 1, scrollRegionHeight - 1, -1);
this.buffer.lines.set(bottomRow, (useRecycling) ? newLine.clone() : newLine);
this.buffer.lines.set(bottomRow, newLine.clone());
}

// Move the viewport to the bottom of the buffer unless the user is
Expand Down
4 changes: 0 additions & 4 deletions src/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,3 @@ export interface IBufferLine {
getTrimmedLength(): number;
translateToString(trimRight?: boolean, startCol?: number, endCol?: number): string;
}

export interface IBufferLineConstructor {
new(cols: number, fillCharData?: CharData, isWrapped?: boolean): IBufferLine;
}
11 changes: 0 additions & 11 deletions typings/xterm.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,6 @@ declare module 'xterm' {
*/
experimentalCharAtlas?: 'none' | 'static' | 'dynamic';

/**
* (EXPERIMENTAL) Defines which implementation to use for buffer lines.
*
* - 'JsArray': The default/stable implementation.
* - 'TypedArray': The new experimental implementation based on TypedArrays that is expected to
* significantly boost performance and memory consumption. Use at your own risk.
*
* @deprecated This option will be removed in the future.
*/
experimentalBufferLineImpl?: 'JsArray' | 'TypedArray';

/**
* The font size used to render text.
*/
Expand Down