Merge pull request #2208 from Tyriar/buffer_common

Move buffer to common
This commit is contained in:
Daniel Imms
2019-06-08 19:08:43 -07:00
committed by GitHub
24 changed files with 1659 additions and 1567 deletions
+2 -1
View File
@@ -4,7 +4,8 @@
*/
import * as Strings from './Strings';
import { ITerminal, IBuffer } from './Types';
import { ITerminal } from './Types';
import { IBuffer } from 'common/buffer/Types';
import { isMac } from 'common/Platform';
import { RenderDebouncer } from 'browser/RenderDebouncer';
import { addDisposableDomListener } from 'browser/Lifecycle';
-1403
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -7,7 +7,7 @@
import { IInputHandler, IInputHandlingTerminal } from './Types';
import { C0, C1 } from 'common/data/EscapeSequences';
import { CHARSETS, DEFAULT_CHARSET } from 'common/data/Charsets';
import { wcwidth } from './common/CharWidth';
import { wcwidth } from 'common/CharWidth';
import { EscapeSequenceParser } from 'common/parser/EscapeSequenceParser';
import { IDisposable } from 'xterm';
import { Disposable } from 'common/Lifecycle';
+2 -1
View File
@@ -3,7 +3,8 @@
* @license MIT
*/
import { ILinkifierEvent, ILinkMatcher, LinkMatcherHandler, ILinkMatcherOptions, ILinkifier, ITerminal, IBufferStringIteratorResult, IMouseZoneManager } from './Types';
import { ILinkifierEvent, ILinkMatcher, LinkMatcherHandler, ILinkMatcherOptions, ILinkifier, ITerminal, IMouseZoneManager } from './Types';
import { IBufferStringIteratorResult } from 'common/buffer/Types';
import { MouseZone } from './MouseZoneManager';
import { getStringCellWidth } from 'common/CharWidth';
import { EventEmitter2, IEvent } from 'common/EventEmitter2';
+37 -29
View File
@@ -6,11 +6,14 @@
import { assert } from 'chai';
import { SelectionManager, SelectionMode } from './SelectionManager';
import { SelectionModel } from './SelectionModel';
import { BufferSet } from './BufferSet';
import { ITerminal, IBuffer } from './Types';
import { BufferSet } from 'common/buffer/BufferSet';
import { ITerminal } from './Types';
import { IBuffer } from 'common/buffer/Types';
import { IBufferLine } from 'common/Types';
import { MockTerminal, MockCharSizeService } from './TestUtils.test';
import { MockOptionsService, MockBufferService } from 'common/TestUtils.test';
import { BufferLine, CellData } from 'common/buffer/BufferLine';
import { IBufferService } from 'common/services/Services';
class TestMockTerminal extends MockTerminal {
emit(event: string, data: any): void {}
@@ -18,9 +21,10 @@ class TestMockTerminal extends MockTerminal {
class TestSelectionManager extends SelectionManager {
constructor(
terminal: ITerminal
terminal: ITerminal,
bufferService: IBufferService
) {
super(terminal, new MockCharSizeService(10, 10));
super(terminal, new MockCharSizeService(10, 10), bufferService);
}
public get model(): SelectionModel { return this._model; }
@@ -40,17 +44,21 @@ class TestSelectionManager extends SelectionManager {
describe('SelectionManager', () => {
let terminal: ITerminal;
let buffer: IBuffer;
let bufferService: IBufferService;
let selectionManager: TestSelectionManager;
beforeEach(() => {
terminal = new TestMockTerminal();
(terminal as any).cols = 80;
(terminal as any).rows = 2;
terminal.options.scrollback = 100;
terminal.buffers = new BufferSet(terminal);
bufferService = new MockBufferService(20, 20);
terminal.buffers = new BufferSet(
new MockOptionsService({ scrollback: 100 }),
bufferService
);
terminal.cols = 20;
terminal.rows = 20;
terminal.buffer = terminal.buffers.active;
buffer = terminal.buffer;
selectionManager = new TestSelectionManager(terminal);
selectionManager = new TestSelectionManager(terminal, bufferService);
});
function stringToRow(text: string): IBufferLine {
@@ -190,36 +198,36 @@ describe('SelectionManager', () => {
assert.equal(selectionManager.selectionText, 'ij"');
});
it('should expand upwards or downards for wrapped lines', () => {
buffer.lines.set(0, stringToRow(' foo'));
buffer.lines.set(1, stringToRow('bar '));
buffer.lines.set(0, stringToRow(' foo'));
buffer.lines.set(1, stringToRow('bar '));
buffer.lines.get(1).isWrapped = true;
selectionManager.selectWordAt([1, 1]);
assert.equal(selectionManager.selectionText, 'foobar');
selectionManager.model.clearSelection();
selectionManager.selectWordAt([78, 0]);
selectionManager.selectWordAt([18, 0]);
assert.equal(selectionManager.selectionText, 'foobar');
});
it('should expand both upwards and downwards for word wrapped over many lines', () => {
const expectedText = 'fooaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbar';
buffer.lines.set(0, stringToRow(' foo'));
buffer.lines.set(1, stringToRow('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'));
buffer.lines.set(2, stringToRow('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'));
buffer.lines.set(3, stringToRow('cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'));
buffer.lines.set(4, stringToRow('bar '));
const expectedText = 'fooaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbccccccccccccccccccccbar';
buffer.lines.set(0, stringToRow(' foo'));
buffer.lines.set(1, stringToRow('aaaaaaaaaaaaaaaaaaaa'));
buffer.lines.set(2, stringToRow('bbbbbbbbbbbbbbbbbbbb'));
buffer.lines.set(3, stringToRow('cccccccccccccccccccc'));
buffer.lines.set(4, stringToRow('bar '));
buffer.lines.get(1).isWrapped = true;
buffer.lines.get(2).isWrapped = true;
buffer.lines.get(3).isWrapped = true;
buffer.lines.get(4).isWrapped = true;
selectionManager.selectWordAt([78, 0]);
selectionManager.selectWordAt([18, 0]);
assert.equal(selectionManager.selectionText, expectedText);
selectionManager.model.clearSelection();
selectionManager.selectWordAt([40, 1]);
selectionManager.selectWordAt([10, 1]);
assert.equal(selectionManager.selectionText, expectedText);
selectionManager.model.clearSelection();
selectionManager.selectWordAt([40, 2]);
selectionManager.selectWordAt([10, 2]);
assert.equal(selectionManager.selectionText, expectedText);
selectionManager.model.clearSelection();
selectionManager.selectWordAt([40, 3]);
selectionManager.selectWordAt([10, 3]);
assert.equal(selectionManager.selectionText, expectedText);
selectionManager.model.clearSelection();
selectionManager.selectWordAt([1, 4]);
@@ -340,7 +348,7 @@ describe('SelectionManager', () => {
selectionManager.selectLineAt(0);
assert.equal(selectionManager.selectionText, 'foo bar', 'The selected text is correct');
assert.deepEqual(selectionManager.model.finalSelectionStart, [0, 0]);
assert.deepEqual(selectionManager.model.finalSelectionEnd, [terminal.cols, 0], 'The actual selection spans the entire column');
assert.deepEqual(selectionManager.model.finalSelectionEnd, [bufferService.cols, 0], 'The actual selection spans the entire column');
});
it('should select the entire wrapped line', () => {
buffer.lines.set(0, stringToRow('foo'));
@@ -350,7 +358,7 @@ describe('SelectionManager', () => {
selectionManager.selectLineAt(0);
assert.equal(selectionManager.selectionText, 'foobar', 'The selected text is correct');
assert.deepEqual(selectionManager.model.finalSelectionStart, [0, 0]);
assert.deepEqual(selectionManager.model.finalSelectionEnd, [terminal.cols, 1], 'The actual selection spans the entire column');
assert.deepEqual(selectionManager.model.finalSelectionEnd, [bufferService.cols, 1], 'The actual selection spans the entire column');
});
});
@@ -363,7 +371,7 @@ describe('SelectionManager', () => {
buffer.lines.set(3, stringToRow('4'));
buffer.lines.set(4, stringToRow('5'));
selectionManager.selectAll();
terminal.buffer.ybase = buffer.lines.length - terminal.rows;
terminal.buffer.ybase = buffer.lines.length - bufferService.rows;
assert.equal(selectionManager.selectionText, '1\n2\n3\n4\n5');
});
});
@@ -376,7 +384,7 @@ describe('SelectionManager', () => {
buffer.lines.set(2, stringToRow('3'));
selectionManager.selectLines(1, 1);
assert.deepEqual(selectionManager.model.finalSelectionStart, [0, 1]);
assert.deepEqual(selectionManager.model.finalSelectionEnd, [terminal.cols, 1]);
assert.deepEqual(selectionManager.model.finalSelectionEnd, [bufferService.cols, 1]);
});
it('should select multiple lines', () => {
buffer.lines.length = 5;
@@ -387,7 +395,7 @@ describe('SelectionManager', () => {
buffer.lines.set(4, stringToRow('5'));
selectionManager.selectLines(1, 3);
assert.deepEqual(selectionManager.model.finalSelectionStart, [0, 1]);
assert.deepEqual(selectionManager.model.finalSelectionEnd, [terminal.cols, 3]);
assert.deepEqual(selectionManager.model.finalSelectionEnd, [bufferService.cols, 3]);
});
it('should select the to the start when requesting a negative row', () => {
buffer.lines.length = 2;
@@ -395,7 +403,7 @@ describe('SelectionManager', () => {
buffer.lines.set(1, stringToRow('2'));
selectionManager.selectLines(-1, 0);
assert.deepEqual(selectionManager.model.finalSelectionStart, [0, 0]);
assert.deepEqual(selectionManager.model.finalSelectionEnd, [terminal.cols, 0]);
assert.deepEqual(selectionManager.model.finalSelectionEnd, [bufferService.cols, 0]);
});
it('should select the to the end when requesting beyond the final row', () => {
buffer.lines.length = 2;
@@ -403,7 +411,7 @@ describe('SelectionManager', () => {
buffer.lines.set(1, stringToRow('2'));
selectionManager.selectLines(1, 2);
assert.deepEqual(selectionManager.model.finalSelectionStart, [0, 1]);
assert.deepEqual(selectionManager.model.finalSelectionEnd, [terminal.cols, 1]);
assert.deepEqual(selectionManager.model.finalSelectionEnd, [bufferService.cols, 1]);
});
});
+6 -3
View File
@@ -3,7 +3,8 @@
* @license MIT
*/
import { ITerminal, ISelectionManager, IBuffer, ISelectionRedrawRequestEvent } from './Types';
import { ITerminal, ISelectionManager, ISelectionRedrawRequestEvent } from './Types';
import { IBuffer } from 'common/buffer/Types';
import { IBufferLine } from 'common/Types';
import { MouseHelper } from './MouseHelper';
import * as Browser from 'common/Platform';
@@ -13,6 +14,7 @@ import { CellData } from 'common/buffer/BufferLine';
import { IDisposable } from 'xterm';
import { EventEmitter2, IEvent } from 'common/EventEmitter2';
import { ICharSizeService } from 'browser/services/Services';
import { IBufferService } from 'common/services/Services';
/**
* The number of pixels the mouse needs to be above or below the viewport in
@@ -117,12 +119,13 @@ export class SelectionManager implements ISelectionManager {
constructor(
private _terminal: ITerminal,
private _charSizeService: ICharSizeService
private _charSizeService: ICharSizeService,
bufferService: IBufferService
) {
this._initListeners();
this.enable();
this._model = new SelectionModel(_terminal);
this._model = new SelectionModel(_terminal, bufferService);
this._activeSelectionMode = SelectionMode.NORMAL;
}
+12 -8
View File
@@ -6,14 +6,17 @@
import { assert } from 'chai';
import { ITerminal } from './Types';
import { SelectionModel } from './SelectionModel';
import { BufferSet } from './BufferSet';
import { BufferSet } from 'common/buffer/BufferSet';
import { MockTerminal } from './TestUtils.test';
import { MockOptionsService, MockBufferService } from 'common/TestUtils.test';
import { IBufferService } from 'common/services/Services';
class TestSelectionModel extends SelectionModel {
constructor(
terminal: ITerminal
terminal: ITerminal,
bufferService: IBufferService
) {
super(terminal);
super(terminal, bufferService);
}
}
@@ -23,13 +26,14 @@ describe('SelectionManager', () => {
beforeEach(() => {
terminal = new MockTerminal();
(terminal as any).cols = 80;
(terminal as any).rows = 2;
terminal.options.scrollback = 10;
terminal.buffers = new BufferSet(terminal);
const bufferService = new MockBufferService(80, 2);
terminal.buffers = new BufferSet(
new MockOptionsService({ scrollback: 10 }),
bufferService
);
terminal.buffer = terminal.buffers.active;
model = new TestSelectionModel(terminal);
model = new TestSelectionModel(terminal, bufferService);
});
describe('clearSelection', () => {
+6 -4
View File
@@ -4,6 +4,7 @@
*/
import { ITerminal } from './Types';
import { IBufferService } from 'common/services/Services';
/**
* Represents a selection within the buffer. This model only cares about column
@@ -33,7 +34,8 @@ export class SelectionModel {
public selectionEnd: [number, number];
constructor(
private _terminal: ITerminal
private _terminal: ITerminal,
private _bufferService: IBufferService
) {
this.clearSelection();
}
@@ -69,7 +71,7 @@ export class SelectionModel {
*/
public get finalSelectionEnd(): [number, number] {
if (this.isSelectAllActive) {
return [this._terminal.cols, this._terminal.buffer.ybase + this._terminal.rows - 1];
return [this._bufferService.cols, this._terminal.buffer.ybase + this._bufferService.rows - 1];
}
if (!this.selectionStart) {
@@ -79,8 +81,8 @@ export class SelectionModel {
// Use the selection start + length if the end doesn't exist or they're reversed
if (!this.selectionEnd || this.areSelectionValuesReversed()) {
const startPlusLength = this.selectionStart[0] + this.selectionStartLength;
if (startPlusLength > this._terminal.cols) {
return [startPlusLength % this._terminal.cols, this.selectionStart[1] + Math.floor(startPlusLength / this._terminal.cols)];
if (startPlusLength > this._bufferService.cols) {
return [startPlusLength % this._bufferService.cols, this.selectionStart[1] + Math.floor(startPlusLength / this._bufferService.cols)];
}
return [startPlusLength, this.selectionStart[1]];
}
+2 -2
View File
@@ -379,10 +379,10 @@ describe('Terminal', () => {
describe('scrollLines', () => {
let startYDisp: number;
beforeEach(() => {
for (let i = 0; i < term.rows * 2; i++) {
for (let i = 0; i < INIT_ROWS * 2; i++) {
term.writeln('test');
}
startYDisp = term.rows + 1;
startYDisp = INIT_ROWS + 1;
});
it('should scroll a single line', () => {
assert.equal(term.buffer.ydisp, startYDisp);
+14 -15
View File
@@ -23,8 +23,8 @@
import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminalOptions, ITerminal, IBrowser, ILinkifier, ILinkMatcherOptions, CustomKeyEventHandler, LinkMatcherHandler, CharacterJoinerHandler, IMouseZoneManager } from './Types';
import { IRenderer } from './renderer/Types';
import { BufferSet } from './BufferSet';
import { Buffer } from './Buffer';
import { BufferSet } from 'common/buffer/BufferSet';
import { Buffer } from 'common/buffer/Buffer';
import { CompositionHelper } from './CompositionHelper';
import { EventEmitter } from 'common/EventEmitter';
import { Viewport } from './Viewport';
@@ -51,10 +51,11 @@ import { Attributes, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
import { applyWindowsMode } from './WindowsMode';
import { ColorManager } from 'browser/ColorManager';
import { RenderCoordinator } from './renderer/RenderCoordinator';
import { IOptionsService } from 'common/services/Services';
import { IOptionsService, IBufferService } from 'common/services/Services';
import { OptionsService } from 'common/services/OptionsService';
import { ICharSizeService } from 'browser/services/Services';
import { CharSizeService } from 'browser/services/CharSizeService';
import { BufferService, MINIMUM_COLS, MINIMUM_ROWS } from 'common/services/BufferService';
// Let it work inside Node.js for automated testing purposes.
const document = (typeof window !== 'undefined') ? window.document : null;
@@ -75,9 +76,6 @@ const WRITE_BUFFER_PAUSE_THRESHOLD = 5;
const WRITE_TIMEOUT_MS = 12;
const WRITE_BUFFER_LENGTH_THRESHOLD = 50;
const MINIMUM_COLS = 2; // Less than 2 can mess with wide chars
const MINIMUM_ROWS = 1;
export class Terminal extends EventEmitter implements ITerminal, IDisposable, IInputHandlingTerminal {
public textarea: HTMLTextAreaElement;
public element: HTMLElement;
@@ -108,6 +106,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
private _customKeyEventHandler: CustomKeyEventHandler;
// common services
private _bufferService: IBufferService;
public optionsService: IOptionsService;
// browser services
@@ -188,8 +187,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
// bufferline to clone/copy from for new blank lines
private _blankLine: IBufferLine = null;
public cols: number;
public rows: number;
public get cols(): number { return this._bufferService.cols; }
public get rows(): number { return this._bufferService.rows; }
private _onCursorMove = new EventEmitter2<void>();
public get onCursorMove(): IEvent<void> { return this._onCursorMove.event; }
@@ -226,7 +225,11 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
options: ITerminalOptions = {}
) {
super();
// Initialize common services
this.optionsService = new OptionsService(options);
this._bufferService = new BufferService(this.optionsService);
this._setupOptionsListeners();
// this.options = clone(options);
@@ -263,9 +266,6 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
private _setup(): void {
this._parent = document ? document.body : null;
this.cols = Math.max(this.options.cols, MINIMUM_COLS);
this.rows = Math.max(this.options.rows, MINIMUM_ROWS);
this.cursorState = 0;
this.cursorHidden = false;
this._customKeyEventHandler = null;
@@ -313,7 +313,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
this.soundManager = this.soundManager || new SoundManager(this);
// Create the terminal's buffers and set the current buffer
this.buffers = new BufferSet(this);
this.buffers = new BufferSet(this.optionsService, this._bufferService);
if (this.selectionManager) {
this.selectionManager.clearSelection();
this.selectionManager.initBuffersListeners();
@@ -643,7 +643,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
this.register(this.addDisposableListener('focus', () => this._renderCoordinator.onFocus()));
this.register(this._renderCoordinator.onDimensionsChange(() => this.viewport.syncScrollArea()));
this.selectionManager = new SelectionManager(this, this._charSizeService);
this.selectionManager = new SelectionManager(this, this._charSizeService, this._bufferService);
this.register(this.selectionManager.onSelectionChange(() => this._onSelectionChange.fire()));
this.register(addDisposableDomListener(this.element, 'mousedown', (e: MouseEvent) => this.selectionManager.onMouseDown(e)));
this.register(this.selectionManager.onRedrawRequest(e => this._renderCoordinator.onSelectionChanged(e.start, e.end, e.columnSelectMode)));
@@ -1745,8 +1745,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
this.buffers.resize(x, y);
this.cols = x;
this.rows = y;
this._bufferService.resize(x, y);
this.buffers.setupTabStops(this.cols);
if (this._charSizeService) {
+4 -4
View File
@@ -4,9 +4,10 @@
*/
import { IRenderer, IRenderDimensions } from './renderer/Types';
import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminal, IBuffer, IBufferSet, IBrowser, ISelectionManager, ITerminalOptions, ILinkifier, IMouseHelper, ILinkMatcherOptions, CharacterJoinerHandler, IBufferStringIterator } from './Types';
import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminal, IBrowser, ISelectionManager, ITerminalOptions, ILinkifier, IMouseHelper, ILinkMatcherOptions, CharacterJoinerHandler } from './Types';
import { IBuffer, IBufferStringIterator, IBufferSet } from 'common/buffer/Types';
import { IBufferLine, ICellData, IAttributeData, ICircularList, XtermListener } from 'common/Types';
import { Buffer } from './Buffer';
import { Buffer } from 'common/buffer/Buffer';
import * as Browser from 'common/Platform';
import { IDisposable, IMarker, IEvent, ISelectionPosition } from 'xterm';
import { Terminal } from './Terminal';
@@ -30,8 +31,7 @@ export class MockTerminal implements ITerminal {
onTitleChange: IEvent<string>;
onScroll: IEvent<number>;
onKey: IEvent<{ key: string; domEvent: KeyboardEvent; }>;
onRender: IEvent<{ start: number
; end: number; }>;
onRender: IEvent<{ start: number; end: number; }>;
onResize: IEvent<{ cols: number; rows: number; }>;
markers: IMarker[];
optionsService: IOptionsService;
+2 -50
View File
@@ -4,10 +4,11 @@
*/
import { ITerminalOptions as IPublicTerminalOptions, IEventEmitter, IDisposable, IMarker, ISelectionPosition } from 'xterm';
import { ICharset, IAttributeData, ICellData, IBufferLine, CharData, ICircularList } from 'common/Types';
import { ICharset, IAttributeData, CharData } from 'common/Types';
import { IEvent } from 'common/EventEmitter2';
import { IColorSet } from 'browser/Types';
import { IOptionsService } from 'common/services/Services';
import { IBuffer, IBufferSet } from 'common/buffer/Types';
export type CustomKeyEventHandler = (event: KeyboardEvent) => boolean;
@@ -18,9 +19,6 @@ export type LinkMatcherValidationCallback = (uri: string, callback: (isValid: bo
export type CharacterJoinerHandler = (text: string) => [number, number][];
// BufferIndex denotes a position in the buffer: [rowIndex, colIndex]
export type BufferIndex = [number, number];
/**
* This interface encapsulates everything needed from the Terminal by the
* InputHandler. This cleanly separates the large amount of methods needed by
@@ -298,52 +296,6 @@ export interface ITerminalOptions extends IPublicTerminalOptions {
useFlowControl?: boolean;
}
export interface IBufferStringIteratorResult {
range: {first: number, last: number};
content: string;
}
export interface IBufferStringIterator {
hasNext(): boolean;
next(): IBufferStringIteratorResult;
}
export interface IBuffer {
readonly lines: ICircularList<IBufferLine>;
ydisp: number;
ybase: number;
y: number;
x: number;
tabs: any;
scrollBottom: number;
scrollTop: number;
hasScrollback: boolean;
savedY: number;
savedX: number;
savedCurAttrData: IAttributeData;
isCursorInViewport: boolean;
translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string;
getWrappedRangeForLine(y: number): { first: number, last: number };
nextStop(x?: number): number;
prevStop(x?: number): number;
getBlankLine(attr: IAttributeData, isWrapped?: boolean): IBufferLine;
stringIndexToBufferIndex(lineIndex: number, stringIndex: number): number[];
iterator(trimRight: boolean, startIndex?: number, endIndex?: number, startOverscan?: number, endOverscan?: number): IBufferStringIterator;
getNullCell(attr?: IAttributeData): ICellData;
getWhitespaceCell(attr?: IAttributeData): ICellData;
}
export interface IBufferSet {
alt: IBuffer;
normal: IBuffer;
active: IBuffer;
onBufferActivate: IEvent<{ activeBuffer: IBuffer, inactiveBuffer: IBuffer }>;
activateNormalBuffer(): void;
activateAltBuffer(fillAttr?: IAttributeData): void;
}
export interface ISelectionManager {
selectionText: string;
selectionStart: [number, number];
+1 -1
View File
@@ -72,7 +72,7 @@ class DomMeasureStrategy implements IMeasureStrategy {
// Note that this triggers a synchronous layout
const geometry = this._measureElement.getBoundingClientRect();
console.log('measure', geometry);
// If values are 0 then the element is likely currently display:none, in which case we should
// retain the previous value.
if (geometry.width !== 0 && geometry.height !== 0) {
+34
View File
@@ -0,0 +1,34 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { IBufferService, IOptionsService, ITerminalOptions, IPartialTerminalOptions } from 'common/services/Services';
import { IEvent, EventEmitter2 } from 'common/EventEmitter2';
import { clone } from 'common/Clone';
import { DEFAULT_OPTIONS } from 'common/services/OptionsService';
export class MockBufferService implements IBufferService {
constructor(
public cols: number,
public rows: number
) {}
resize(cols: number, rows: number): void {
this.cols = cols;
this.rows = rows;
}
}
export class MockOptionsService implements IOptionsService {
options: ITerminalOptions = clone(DEFAULT_OPTIONS);
onOptionChange: IEvent<string> = new EventEmitter2<string>().event;
constructor(testOptions: IPartialTerminalOptions) {
Object.keys(testOptions).forEach(key => this.options[key] = (<any>testOptions)[key]);
}
setOption<T>(key: string, value: T): void {
throw new Error('Method not implemented.');
}
getOption<T>(key: string): T {
throw new Error('Method not implemented.');
}
}
File diff suppressed because it is too large Load Diff
+26 -26
View File
@@ -4,11 +4,12 @@
*/
import { CircularList, IInsertEvent } from 'common/CircularList';
import { ITerminal, IBuffer, BufferIndex, IBufferStringIterator, IBufferStringIteratorResult } from './Types';
import { IBuffer, BufferIndex, IBufferStringIterator, IBufferStringIteratorResult } from 'common/buffer/Types';
import { IBufferLine, ICellData, IAttributeData } from 'common/Types';
import { BufferLine, CellData, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_WIDTH, WHITESPACE_CELL_CODE, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
import { reflowLargerApplyNewLayout, reflowLargerCreateNewLayout, reflowLargerGetLinesToRemove, reflowSmallerGetNewLineLengths, getWrappedLineTrimmedLength } from 'common/buffer/BufferReflow';
import { Marker } from 'common/buffer/Marker';
import { IOptionsService, IBufferService } from 'common/services/Services';
export const MAX_BUFFER_SIZE = 4294967295; // 2^32 - 1
@@ -21,15 +22,16 @@ export const MAX_BUFFER_SIZE = 4294967295; // 2^32 - 1
*/
export class Buffer implements IBuffer {
public lines: CircularList<IBufferLine>;
public ydisp: number;
public ybase: number;
public y: number;
public x: number;
public ydisp: number = 0;
public ybase: number = 0;
public y: number = 0;
public x: number = 0;
public scrollBottom: number;
public scrollTop: number;
// TODO: Type me
public tabs: any;
public savedY: number;
public savedX: number;
public savedY: number = 0;
public savedX: number = 0;
public savedCurAttrData = DEFAULT_ATTR_DATA.clone();
public markers: Marker[] = [];
private _nullCell: ICellData = CellData.fromCharData([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
@@ -37,19 +39,17 @@ export class Buffer implements IBuffer {
private _cols: number;
private _rows: number;
/**
* Create a new Buffer.
* @param _terminal The terminal the Buffer will belong to.
* @param _hasScrollback Whether the buffer should respect the scrollback of
* the terminal.
*/
constructor(
private _terminal: ITerminal,
private _hasScrollback: boolean
private _hasScrollback: boolean,
private _optionsService: IOptionsService,
private _bufferService: IBufferService
) {
this._cols = this._terminal.cols;
this._rows = this._terminal.rows;
this.clear();
this._cols = this._bufferService.cols;
this._rows = this._bufferService.rows;
this.lines = new CircularList<IBufferLine>(this._getCorrectBufferLength(this._rows));
this.scrollTop = 0;
this.scrollBottom = this._rows - 1;
this.setupTabStops();
}
public getNullCell(attr?: IAttributeData): ICellData {
@@ -75,7 +75,7 @@ export class Buffer implements IBuffer {
}
public getBlankLine(attr: IAttributeData, isWrapped?: boolean): IBufferLine {
return new BufferLine(this._terminal.cols, this.getNullCell(attr), isWrapped);
return new BufferLine(this._bufferService.cols, this.getNullCell(attr), isWrapped);
}
public get hasScrollback(): boolean {
@@ -98,7 +98,7 @@ export class Buffer implements IBuffer {
return rows;
}
const correctBufferLength = rows + this._terminal.options.scrollback;
const correctBufferLength = rows + this._optionsService.options.scrollback;
return correctBufferLength > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : correctBufferLength;
}
@@ -154,7 +154,7 @@ export class Buffer implements IBuffer {
// Deal with columns increasing (reducing needs to happen after reflow)
if (this._cols < newCols) {
for (let i = 0; i < this.lines.length; i++) {
this.lines.get(i).resize(newCols, nullCell);
this.lines.get(i)!.resize(newCols, nullCell);
}
}
@@ -227,7 +227,7 @@ export class Buffer implements IBuffer {
// Trim the end of the line off if cols shrunk
if (this._cols > newCols) {
for (let i = 0; i < this.lines.length; i++) {
this.lines.get(i).resize(newCols, nullCell);
this.lines.get(i)!.resize(newCols, nullCell);
}
}
}
@@ -237,7 +237,7 @@ export class Buffer implements IBuffer {
}
private get _isReflowEnabled(): boolean {
return this._hasScrollback && !this._terminal.options.windowsMode;
return this._hasScrollback && !this._optionsService.options.windowsMode;
}
private _reflow(newCols: number, newRows: number): void {
@@ -509,11 +509,11 @@ export class Buffer implements IBuffer {
let first = y;
let last = y;
// Scan upwards for wrapped lines
while (first > 0 && this.lines.get(first).isWrapped) {
while (first > 0 && this.lines.get(first)!.isWrapped) {
first--;
}
// Scan downwards for wrapped lines
while (last + 1 < this.lines.length && this.lines.get(last + 1).isWrapped) {
while (last + 1 < this.lines.length && this.lines.get(last + 1)!.isWrapped) {
last++;
}
return { first, last };
@@ -533,7 +533,7 @@ export class Buffer implements IBuffer {
i = 0;
}
for (; i < this._cols; i += this._terminal.options.tabStopWidth) {
for (; i < this._cols; i += this._optionsService.options.tabStopWidth) {
this.tabs[i] = true;
}
}
@@ -4,21 +4,18 @@
*/
import { assert } from 'chai';
import { ITerminal } from './Types';
import { BufferSet } from './BufferSet';
import { Buffer } from './Buffer';
import { MockTerminal } from './TestUtils.test';
import { BufferSet } from 'common/buffer/BufferSet';
import { Buffer } from 'common/buffer/Buffer';
import { MockOptionsService, MockBufferService } from 'common/TestUtils.test';
describe('BufferSet', () => {
let terminal: ITerminal;
let bufferSet: BufferSet;
beforeEach(() => {
terminal = new MockTerminal();
(terminal as any).cols = 80;
(terminal as any).rows = 24;
terminal.options.scrollback = 1000;
bufferSet = new BufferSet(terminal);
bufferSet = new BufferSet(
new MockOptionsService({ scrollback: 1000 }),
new MockBufferService(80, 24)
);
});
describe('constructor', () => {
@@ -3,10 +3,11 @@
* @license MIT
*/
import { ITerminal, IBufferSet, IBuffer } from './Types';
import { IBuffer, IBufferSet } from 'common/buffer/Types';
import { IAttributeData } from 'common/Types';
import { Buffer } from './Buffer';
import { Buffer } from 'common/buffer/Buffer';
import { EventEmitter2, IEvent } from 'common/EventEmitter2';
import { IOptionsService, IBufferService } from 'common/services/Services';
/**
* The BufferSet represents the set of two buffers used by xterm terminals (normal and alt) and
@@ -25,13 +26,16 @@ export class BufferSet implements IBufferSet {
* Create a new BufferSet for the given terminal.
* @param _terminal - The terminal the BufferSet will belong to
*/
constructor(private _terminal: ITerminal) {
this._normal = new Buffer(this._terminal, true);
constructor(
readonly optionsService: IOptionsService,
readonly bufferService: IBufferService
) {
this._normal = new Buffer(true, optionsService, bufferService);
this._normal.fillViewportRows();
// The alt buffer should never have scrollback.
// See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer
this._alt = new Buffer(this._terminal, false);
this._alt = new Buffer(false, optionsService, bufferService);
this._activeBuffer = this._normal;
this.setupTabStops();
+56
View File
@@ -0,0 +1,56 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { IAttributeData, ICircularList, IBufferLine, ICellData } from 'common/Types';
import { IEvent } from 'common/EventEmitter2';
// BufferIndex denotes a position in the buffer: [rowIndex, colIndex]
export type BufferIndex = [number, number];
export interface IBufferStringIteratorResult {
range: {first: number, last: number};
content: string;
}
export interface IBufferStringIterator {
hasNext(): boolean;
next(): IBufferStringIteratorResult;
}
export interface IBuffer {
readonly lines: ICircularList<IBufferLine>;
ydisp: number;
ybase: number;
y: number;
x: number;
tabs: any;
scrollBottom: number;
scrollTop: number;
hasScrollback: boolean;
savedY: number;
savedX: number;
savedCurAttrData: IAttributeData;
isCursorInViewport: boolean;
translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string;
getWrappedRangeForLine(y: number): { first: number, last: number };
nextStop(x?: number): number;
prevStop(x?: number): number;
getBlankLine(attr: IAttributeData, isWrapped?: boolean): IBufferLine;
stringIndexToBufferIndex(lineIndex: number, stringIndex: number): number[];
iterator(trimRight: boolean, startIndex?: number, endIndex?: number, startOverscan?: number, endOverscan?: number): IBufferStringIterator;
getNullCell(attr?: IAttributeData): ICellData;
getWhitespaceCell(attr?: IAttributeData): ICellData;
}
export interface IBufferSet {
alt: IBuffer;
normal: IBuffer;
active: IBuffer;
onBufferActivate: IEvent<{ activeBuffer: IBuffer, inactiveBuffer: IBuffer }>;
activateNormalBuffer(): void;
activateAltBuffer(fillAttr?: IAttributeData): void;
}
+26
View File
@@ -0,0 +1,26 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { IBufferService, IOptionsService } from './Services';
export const MINIMUM_COLS = 2; // Less than 2 can mess with wide chars
export const MINIMUM_ROWS = 1;
export class BufferService implements IBufferService {
public cols: number;
public rows: number;
constructor(
optionsService: IOptionsService
) {
this.cols = Math.max(optionsService.options.cols, MINIMUM_COLS);
this.rows = Math.max(optionsService.options.rows, MINIMUM_ROWS);
}
public resize(cols: number, rows: number): void {
this.cols = cols;
this.rows = rows;
}
}

Some files were not shown because too many files have changed in this diff Show More