Skip to content

Commit

Permalink
Merge 22e4a2d into 70981c7
Browse files Browse the repository at this point in the history
  • Loading branch information
jerch committed Nov 8, 2018
2 parents 70981c7 + 22e4a2d commit b50ba78
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 23 deletions.
7 changes: 2 additions & 5 deletions src/BufferLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,8 @@ export class BufferLine implements IBufferLine {
}
}

public copyFrom(line: IBufferLine): void {
this._data = [];
for (let i = 0; i < line.length; ++i) {
this._push(line.get(i));
}
public copyFrom(line: BufferLine): void {
this._data = line._data.slice(0);
this.length = line.length;
this.isWrapped = line.isWrapped;
}
Expand Down
43 changes: 34 additions & 9 deletions src/Terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
* http://linux.die.net/man/7/urxvt
*/

import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminalOptions, ITerminal, IBrowser, ILinkifier, ILinkMatcherOptions, CustomKeyEventHandler, LinkMatcherHandler, CharData, CharacterJoinerHandler } from './Types';
import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminalOptions, ITerminal, IBrowser, ILinkifier, ILinkMatcherOptions, CustomKeyEventHandler, LinkMatcherHandler, CharData, CharacterJoinerHandler, IBufferLine } from './Types';
import { IMouseZoneManager } from './ui/Types';
import { IRenderer } from './renderer/Types';
import { BufferSet } from './BufferSet';
import { Buffer, MAX_BUFFER_SIZE, DEFAULT_ATTR, NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR } from './Buffer';
import { Buffer, MAX_BUFFER_SIZE, DEFAULT_ATTR, NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, CHAR_DATA_ATTR_INDEX } from './Buffer';
import { CompositionHelper } from './CompositionHelper';
import { EventEmitter } from './common/EventEmitter';
import { Viewport } from './Viewport';
Expand Down Expand Up @@ -106,7 +106,8 @@ const DEFAULT_OPTIONS: ITerminalOptions = {
theme: null,
rightClickSelectsWord: Browser.isMac,
rendererType: 'canvas',
experimentalBufferLineImpl: 'JsArray'
experimentalBufferLineImpl: 'JsArray',
experimentalBufferLineRecycling: false
};

export class Terminal extends EventEmitter implements ITerminal, IDisposable, IInputHandlingTerminal {
Expand Down Expand Up @@ -208,6 +209,9 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
private _screenDprMonitor: ScreenDprMonitor;
private _theme: ITheme;

// bufferline to clone/copy from for new blank lines
private _blankLine: IBufferLine = null;

public cols: number;
public rows: number;

Expand Down Expand Up @@ -497,6 +501,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
case 'experimentalBufferLineImpl':
this.buffers.normal.setBufferLineFactory(value);
this.buffers.alt.setBufferLineFactory(value);
this._blankLine = null;
break;
}
// Inform renderer of changes
Expand Down Expand Up @@ -1174,20 +1179,40 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
* Scroll the terminal down 1 row, creating a blank line.
* @param isWrapped Whether the new line is wrapped from the previous line.
*/
public scroll(isWrapped?: boolean): void {
const newLine = this.buffer.getBlankLine(this.eraseAttr(), isWrapped);
public scroll(isWrapped: boolean = false): void {
let newLine: IBufferLine;
const useRecycling = this.options.experimentalBufferLineRecycling;
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.buffer.getBlankLine(this.eraseAttr(), isWrapped);
}

const topRow = this.buffer.ybase + this.buffer.scrollTop;
const bottomRow = this.buffer.ybase + this.buffer.scrollBottom;

if (this.buffer.scrollTop === 0) {
// Determine whether the buffer is going to be trimmed after insertion.
const willBufferBeTrimmed = this.buffer.lines.length === this.buffer.lines.maxLength;
const willBufferBeTrimmed = this.buffer.lines.isFull();

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

// Only adjust ybase and ydisp when the buffer is not trimmed
Expand All @@ -1209,7 +1234,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, newLine);
this.buffer.lines.set(bottomRow, (useRecycling) ? newLine.clone() : newLine);
}

// Move the viewport to the bottom of the buffer unless the user is
Expand Down
37 changes: 28 additions & 9 deletions src/common/CircularList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,33 @@ export class CircularList<T> extends EventEmitter implements ICircularList<T> {
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;
}
this._startIndex = ++this._startIndex % this._maxLength;
this.emit('trim', 1);
} else {
this._length++;
}
}

/**
* Advance ringbuffer index and return current element for recycling.
* Note: If the ringbuffer is not full this method will return undefined,
* Either precheck with isFull() or handle the undefined return value accordingly.
*/
public recycle(): T | undefined {
if (this._length === this._maxLength) {
this._startIndex = ++this._startIndex % this._maxLength;
this.emit('trim', 1);
} else {
this._length++;
}
return this._array[this._getCyclicIndex(this._length - 1)];
}

/**
* Ringbuffer is at max length.
*/
public isFull(): boolean {
return this._length === this._maxLength;
}

/**
Expand Down Expand Up @@ -136,10 +155,10 @@ export class CircularList<T> extends EventEmitter implements ICircularList<T> {
}

// Adjust length as needed
if (this._length + items.length > this.maxLength) {
const countToTrim = (this._length + items.length) - this.maxLength;
if (this._length + items.length > this._maxLength) {
const countToTrim = (this._length + items.length) - this._maxLength;
this._startIndex += countToTrim;
this._length = this.maxLength;
this._length = this._maxLength;
this.emit('trim', countToTrim);
} else {
this._length += items.length;
Expand Down Expand Up @@ -178,7 +197,7 @@ export class CircularList<T> extends EventEmitter implements ICircularList<T> {
const expandListBy = (start + count + offset) - this._length;
if (expandListBy > 0) {
this._length += expandListBy;
while (this._length > this.maxLength) {
while (this._length > this._maxLength) {
this._length--;
this._startIndex++;
this.emit('trim', 1);
Expand All @@ -198,6 +217,6 @@ export class CircularList<T> extends EventEmitter implements ICircularList<T> {
* @returns The cyclic index.
*/
private _getCyclicIndex(index: number): number {
return (this._startIndex + index) % this.maxLength;
return (this._startIndex + index) % this._maxLength;
}
}
2 changes: 2 additions & 0 deletions src/common/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export interface ICircularList<T> extends IEventEmitter {
get(index: number): T | undefined;
set(index: number, value: T): void;
push(value: T): void;
recycle(): T | undefined;
isFull(): boolean;
pop(): T | undefined;
splice(start: number, deleteCount: number, ...items: T[]): void;
trimStart(count: number): void;
Expand Down
7 changes: 7 additions & 0 deletions typings/xterm.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ declare module 'xterm' {
*/
experimentalBufferLineImpl?: 'JsArray' | 'TypedArray';

/**
* (EXPERIMENTAL) Enable recycling of buffer lines.
*
* This option will be removed in the future.
*/
experimentalBufferLineRecycling?: boolean;

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

0 comments on commit b50ba78

Please sign in to comment.