mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge pull request #2208 from Tyriar/buffer_common
Move buffer to common
This commit is contained in:
@@ -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
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -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
@@ -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';
|
||||
|
||||
@@ -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]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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]];
|
||||
}
|
||||
|
||||
@@ -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
@@ -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,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
@@ -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];
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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();
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user