From c078f3db487c33be1828a4d64dc351e946423d99 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 13 Jul 2019 18:25:22 -0700 Subject: [PATCH] Move range updating to DirtyRowService --- src/InputHandler.test.ts | 20 +++--- src/InputHandler.ts | 86 ++++++++++---------------- src/Terminal.ts | 59 +++--------------- src/Types.d.ts | 1 - src/common/TestUtils.test.ts | 11 +++- src/common/Types.d.ts | 5 ++ src/common/services/DirtyRowService.ts | 51 +++++++++++++++ src/common/services/Services.d.ts | 10 +++ src/renderer/dom/DomRenderer.ts | 3 - 9 files changed, 127 insertions(+), 119 deletions(-) create mode 100644 src/common/services/DirtyRowService.ts diff --git a/src/InputHandler.test.ts b/src/InputHandler.test.ts index 53d0bc496..558cfe7ee 100644 --- a/src/InputHandler.test.ts +++ b/src/InputHandler.test.ts @@ -13,7 +13,7 @@ import { CellData } from 'common/buffer/CellData'; import { Attributes } from 'common/buffer/Constants'; import { AttributeData } from 'common/buffer/AttributeData'; import { Params } from 'common/parser/Params'; -import { MockCoreService, MockBufferService, MockOptionsService, MockLogService } from 'common/TestUtils.test'; +import { MockCoreService, MockBufferService, MockDirtyRowService, MockOptionsService, MockLogService } from 'common/TestUtils.test'; import { IBufferService } from 'common/services/Services'; function getCursor(term: TestTerminal): number[] { @@ -31,7 +31,7 @@ describe('InputHandler', () => { bufferService.buffer.x = 1; bufferService.buffer.y = 2; bufferService.buffer.ybase = 0; - const inputHandler = new InputHandler(terminal, bufferService, new MockCoreService(), new MockLogService(), new MockOptionsService()); + const inputHandler = new InputHandler(terminal, bufferService, new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService()); // Save cursor position inputHandler.saveCursor(); assert.equal(bufferService.buffer.x, 1); @@ -50,7 +50,7 @@ describe('InputHandler', () => { describe('setCursorStyle', () => { it('should call Terminal.setOption with correct params', () => { const terminal = new MockInputHandlingTerminal(); - const inputHandler = new InputHandler(terminal, new MockBufferService(80, 30), new MockCoreService(), new MockLogService(), new MockOptionsService()); + const inputHandler = new InputHandler(terminal, new MockBufferService(80, 30), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService()); const collect = ' '; inputHandler.setCursorStyle(Params.fromArray([0]), collect); @@ -93,7 +93,7 @@ describe('InputHandler', () => { const terminal = new MockInputHandlingTerminal(); const collect = '?'; terminal.bracketedPasteMode = false; - const inputHandler = new InputHandler(terminal, new MockBufferService(80, 30), new MockCoreService(), new MockLogService(), new MockOptionsService()); + const inputHandler = new InputHandler(terminal, new MockBufferService(80, 30), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService()); // Set bracketed paste mode inputHandler.setMode(Params.fromArray([2004]), collect); assert.equal(terminal.bracketedPasteMode, true); @@ -112,7 +112,7 @@ describe('InputHandler', () => { it('insertChars', function(): void { const term = new Terminal(); const bufferService = new MockBufferService(80, 30); - const inputHandler = new InputHandler(term, bufferService, new MockCoreService(), new MockLogService(), new MockOptionsService()); + const inputHandler = new InputHandler(term, bufferService, new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService()); // insert some data in first and second line inputHandler.parse(Array(bufferService.cols - 9).join('a')); @@ -150,7 +150,7 @@ describe('InputHandler', () => { it('deleteChars', function(): void { const term = new Terminal(); const bufferService = new MockBufferService(80, 30); - const inputHandler = new InputHandler(term, bufferService, new MockCoreService(), new MockLogService(), new MockOptionsService()); + const inputHandler = new InputHandler(term, bufferService, new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService()); // insert some data in first and second line inputHandler.parse(Array(bufferService.cols - 9).join('a')); @@ -191,7 +191,7 @@ describe('InputHandler', () => { it('eraseInLine', function(): void { const term = new Terminal(); const bufferService = new MockBufferService(80, 30); - const inputHandler = new InputHandler(term, bufferService, new MockCoreService(), new MockLogService(), new MockOptionsService()); + const inputHandler = new InputHandler(term, bufferService, new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService()); // fill 6 lines to test 3 different states inputHandler.parse(Array(bufferService.cols + 1).join('a')); @@ -220,7 +220,7 @@ describe('InputHandler', () => { it('eraseInDisplay', function(): void { const term = new Terminal({cols: 80, rows: 7}); const bufferService = new MockBufferService(80, 7); - const inputHandler = new InputHandler(term, bufferService, new MockCoreService(), new MockLogService(), new MockOptionsService()); + const inputHandler = new InputHandler(term, bufferService, new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService()); // fill display with a's for (let i = 0; i < bufferService.rows; ++i) inputHandler.parse(Array(bufferService.cols + 1).join('a')); @@ -355,7 +355,7 @@ describe('InputHandler', () => { describe('print', () => { it('should not cause an infinite loop (regression test)', () => { const term = new Terminal(); - const inputHandler = new InputHandler(term, new MockBufferService(80, 30), new MockCoreService(), new MockLogService(), new MockOptionsService()); + const inputHandler = new InputHandler(term, new MockBufferService(80, 30), new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService()); const container = new Uint32Array(10); container[0] = 0x200B; inputHandler.print(container, 0, 1); @@ -370,7 +370,7 @@ describe('InputHandler', () => { beforeEach(() => { term = new Terminal(); bufferService = new MockBufferService(80, 30); - handler = new InputHandler(term, bufferService, new MockCoreService(), new MockLogService(), new MockOptionsService()); + handler = new InputHandler(term, bufferService, new MockCoreService(), new MockDirtyRowService(), new MockLogService(), new MockOptionsService()); }); it('should handle DECSET/DECRST 47 (alt screen buffer)', () => { handler.parse('\x1b[?47h\r\n\x1b[31mJUNK\x1b[?47lTEST'); diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 0f4da0414..cc767a163 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -19,7 +19,7 @@ import { NULL_CELL_CODE, NULL_CELL_WIDTH, Attributes, FgFlags, BgFlags, Content import { CellData } from 'common/buffer/CellData'; import { AttributeData } from 'common/buffer/AttributeData'; import { IAttributeData, IDisposable } from 'common/Types'; -import { ICoreService, IBufferService, IOptionsService, ILogService } from 'common/services/Services'; +import { ICoreService, IBufferService, IOptionsService, ILogService, IDirtyRowService } from 'common/services/Services'; import { ISelectionService } from 'browser/services/Services'; /** @@ -128,12 +128,13 @@ export class InputHandler extends Disposable implements IInputHandler { public get onScroll(): IEvent { return this._onScroll.event; } constructor( - protected _terminal: IInputHandlingTerminal, - private _bufferService: IBufferService, - private _coreService: ICoreService, - private _logService: ILogService, - private _optionsService: IOptionsService, - private _parser: IEscapeSequenceParser = new EscapeSequenceParser()) + protected _terminal: IInputHandlingTerminal, + private readonly _bufferService: IBufferService, + private readonly _coreService: ICoreService, + private readonly _dirtyRowService: IDirtyRowService, + private readonly _logService: ILogService, + private readonly _optionsService: IOptionsService, + private readonly _parser: IEscapeSequenceParser = new EscapeSequenceParser()) { super(); @@ -306,7 +307,6 @@ export class InputHandler extends Disposable implements IInputHandler { public dispose(): void { super.dispose(); - this._terminal = null; } // TODO: When InputHandler moves into common, browser dependencies need to move out @@ -315,11 +315,6 @@ export class InputHandler extends Disposable implements IInputHandler { } public parse(data: string): void { - // Ensure the terminal is not disposed - if (!this._terminal) { - return; - } - let buffer = this._bufferService.buffer; const cursorStartX = buffer.x; const cursorStartY = buffer.y; @@ -338,11 +333,6 @@ export class InputHandler extends Disposable implements IInputHandler { } public parseUtf8(data: Uint8Array): void { - // Ensure the terminal is not disposed - if (!this._terminal) { - return; - } - let buffer = this._bufferService.buffer; const cursorStartX = buffer.x; const cursorStartY = buffer.y; @@ -365,14 +355,14 @@ export class InputHandler extends Disposable implements IInputHandler { let chWidth: number; const buffer = this._bufferService.buffer; const charset = this._terminal.charset; - const screenReaderMode = this._terminal.options.screenReaderMode; + const screenReaderMode = this._optionsService.options.screenReaderMode; const cols = this._bufferService.cols; const wraparoundMode = this._terminal.wraparoundMode; const insertMode = this._terminal.insertMode; const curAttr = this._terminal.curAttrData; let bufferRow = buffer.lines.get(buffer.y + buffer.ybase); - this._terminal.updateRange(buffer.y); + this._dirtyRowService.markDirty(buffer.y); for (let pos = start; pos < end; ++pos) { code = data[pos]; @@ -481,7 +471,7 @@ export class InputHandler extends Disposable implements IInputHandler { this._parser.precedingCodepoint = this._workCell.content; } } - this._terminal.updateRange(buffer.y); + this._dirtyRowService.markDirty(buffer.y); } /** @@ -514,7 +504,7 @@ export class InputHandler extends Disposable implements IInputHandler { // make buffer local for faster access const buffer = this._bufferService.buffer; - if (this._terminal.options.convertEol) { + if (this._optionsService.options.convertEol) { buffer.x = 0; } buffer.y++; @@ -559,7 +549,7 @@ export class InputHandler extends Disposable implements IInputHandler { } const originalX = this._bufferService.buffer.x; this._bufferService.buffer.x = this._bufferService.buffer.nextStop(); - if (this._terminal.options.screenReaderMode) { + if (this._optionsService.options.screenReaderMode) { this._terminal.onA11yTabEmitter.fire(this._bufferService.buffer.x - originalX); } } @@ -830,16 +820,16 @@ export class InputHandler extends Disposable implements IInputHandler { switch (params.params[0]) { case 0: j = this._bufferService.buffer.y; - this._terminal.updateRange(j); + this._dirtyRowService.markDirty(j); this._eraseInBufferLine(j++, this._bufferService.buffer.x, this._bufferService.cols, this._bufferService.buffer.x === 0); for (; j < this._bufferService.rows; j++) { this._resetBufferLine(j); } - this._terminal.updateRange(j); + this._dirtyRowService.markDirty(j); break; case 1: j = this._bufferService.buffer.y; - this._terminal.updateRange(j); + this._dirtyRowService.markDirty(j); // Deleted front part of line and everything before. This line will no longer be wrapped. this._eraseInBufferLine(j, 0, this._bufferService.buffer.x + 1, true); if (this._bufferService.buffer.x + 1 >= this._bufferService.cols) { @@ -849,15 +839,15 @@ export class InputHandler extends Disposable implements IInputHandler { while (j--) { this._resetBufferLine(j); } - this._terminal.updateRange(0); + this._dirtyRowService.markDirty(0); break; case 2: j = this._bufferService.rows; - this._terminal.updateRange(j - 1); + this._dirtyRowService.markDirty(j - 1); while (j--) { this._resetBufferLine(j); } - this._terminal.updateRange(0); + this._dirtyRowService.markDirty(0); break; case 3: // Clear scrollback (everything not in viewport) @@ -897,7 +887,7 @@ export class InputHandler extends Disposable implements IInputHandler { this._eraseInBufferLine(this._bufferService.buffer.y, 0, this._bufferService.cols); break; } - this._terminal.updateRange(this._bufferService.buffer.y); + this._dirtyRowService.markDirty(this._bufferService.buffer.y); } /** @@ -926,9 +916,7 @@ export class InputHandler extends Disposable implements IInputHandler { buffer.lines.splice(row, 0, buffer.getBlankLine(this._terminal.eraseAttrData())); } - // this.maxRange(); - this._terminal.updateRange(buffer.y); - this._terminal.updateRange(buffer.scrollBottom); + this._dirtyRowService.markRangeDirty(buffer.y, buffer.scrollBottom); buffer.x = 0; // see https://vt100.net/docs/vt220-rm/chapter4.html - vt220 only? } @@ -959,9 +947,7 @@ export class InputHandler extends Disposable implements IInputHandler { buffer.lines.splice(j, 0, buffer.getBlankLine(this._terminal.eraseAttrData())); } - // this.maxRange(); - this._terminal.updateRange(buffer.y); - this._terminal.updateRange(buffer.scrollBottom); + this._dirtyRowService.markRangeDirty(buffer.y, buffer.scrollBottom); buffer.x = 0; // see https://vt100.net/docs/vt220-rm/chapter4.html - vt220 only? } @@ -978,7 +964,7 @@ export class InputHandler extends Disposable implements IInputHandler { params.params[0] || 1, this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData()) ); - this._terminal.updateRange(this._bufferService.buffer.y); + this._dirtyRowService.markDirty(this._bufferService.buffer.y); } } @@ -995,7 +981,7 @@ export class InputHandler extends Disposable implements IInputHandler { params.params[0] || 1, this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData()) ); - this._terminal.updateRange(this._bufferService.buffer.y); + this._dirtyRowService.markDirty(this._bufferService.buffer.y); } } @@ -1012,9 +998,7 @@ export class InputHandler extends Disposable implements IInputHandler { buffer.lines.splice(buffer.ybase + buffer.scrollTop, 1); buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, buffer.getBlankLine(DEFAULT_ATTR_DATA)); } - // this.maxRange(); - this._terminal.updateRange(buffer.scrollTop); - this._terminal.updateRange(buffer.scrollBottom); + this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); } /** @@ -1031,9 +1015,7 @@ export class InputHandler extends Disposable implements IInputHandler { buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 1); buffer.lines.splice(buffer.ybase + buffer.scrollTop, 0, buffer.getBlankLine(DEFAULT_ATTR_DATA)); } - // this.maxRange(); - this._terminal.updateRange(buffer.scrollTop); - this._terminal.updateRange(buffer.scrollBottom); + this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); } } @@ -1050,7 +1032,7 @@ export class InputHandler extends Disposable implements IInputHandler { this._bufferService.buffer.x + (params.params[0] || 1), this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData()) ); - this._terminal.updateRange(this._bufferService.buffer.y); + this._dirtyRowService.markDirty(this._bufferService.buffer.y); } } @@ -1893,19 +1875,19 @@ export class InputHandler extends Disposable implements IInputHandler { switch (param) { case 1: case 2: - this._terminal.options.cursorStyle = 'block'; + this._optionsService.options.cursorStyle = 'block'; break; case 3: case 4: - this._terminal.options.cursorStyle = 'underline'; + this._optionsService.options.cursorStyle = 'underline'; break; case 5: case 6: - this._terminal.options.cursorStyle = 'bar'; + this._optionsService.options.cursorStyle = 'bar'; break; } const isBlinking = param % 2 === 1; - this._terminal.options.cursorBlink = isBlinking; + this._optionsService.options.cursorBlink = isBlinking; } } @@ -2097,8 +2079,7 @@ export class InputHandler extends Disposable implements IInputHandler { const scrollRegionHeight = buffer.scrollBottom - buffer.scrollTop; buffer.lines.shiftElements(buffer.y + buffer.ybase, scrollRegionHeight, 1); buffer.lines.set(buffer.y + buffer.ybase, buffer.getBlankLine(this._terminal.eraseAttrData())); - this._terminal.updateRange(buffer.scrollTop); - this._terminal.updateRange(buffer.scrollBottom); + this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); } else { buffer.y--; this._restrictCursor(); // quickfix to not run out of bounds @@ -2152,8 +2133,7 @@ export class InputHandler extends Disposable implements IInputHandler { buffer.lines.get(row).fill(cell); buffer.lines.get(row).isWrapped = false; } - this._terminal.updateRange(0); - this._terminal.updateRange(this._bufferService.rows); + this._dirtyRowService.markAllDirty(); this._setCursor(0, 0); } } diff --git a/src/Terminal.ts b/src/Terminal.ts index e1d0a4d71..e23ea7783 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -47,7 +47,7 @@ import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; import { applyWindowsMode } from './WindowsMode'; import { ColorManager } from 'browser/ColorManager'; import { RenderService } from 'browser/services/RenderService'; -import { IOptionsService, IBufferService, ICoreService, ILogService } from 'common/services/Services'; +import { IOptionsService, IBufferService, ICoreService, ILogService, IDirtyRowService } from 'common/services/Services'; import { OptionsService } from 'common/services/OptionsService'; import { ICharSizeService, IRenderService, IMouseService, ISelectionService, ISoundService } from 'browser/services/Services'; import { CharSizeService } from 'browser/services/CharSizeService'; @@ -60,6 +60,7 @@ import { IParams } from 'common/parser/Types'; import { CoreService } from 'common/services/CoreService'; import { LogService } from 'common/services/LogService'; import { ILinkifier, IMouseZoneManager, LinkMatcherHandler, ILinkMatcherOptions, IViewport } from 'browser/Types'; +import { DirtyRowService } from 'common/services/DirtyRowService'; // Let it work inside Node.js for automated testing purposes. const document = (typeof window !== 'undefined') ? window.document : null; @@ -111,6 +112,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp // common services private _bufferService: IBufferService; private _coreService: ICoreService; + private _dirtyRowService: IDirtyRowService; private _logService: ILogService; public optionsService: IOptionsService; @@ -148,8 +150,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp public urxvtMouse: boolean; // misc - private _refreshStart: number; - private _refreshEnd: number; public savedCols: number; public curAttrData: IAttributeData; @@ -243,6 +243,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this._bufferService = new BufferService(this.optionsService); this._coreService = new CoreService(() => this.scrollToBottom(), this._bufferService, this.optionsService); this._coreService.onData(e => this._onData.fire(e)); + this._dirtyRowService = new DirtyRowService(this._bufferService); this._logService = new LogService(this.optionsService); this._setupOptionsListeners(); @@ -300,7 +301,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this._userScrolling = false; // Register input handler and refire/handle events - this._inputHandler = new InputHandler(this, this._bufferService, this._coreService, this._logService, this.optionsService); + this._inputHandler = new InputHandler(this, this._bufferService, this._coreService, this._dirtyRowService, this._logService, this.optionsService); this._inputHandler.onCursorMove(() => this._onCursorMove.fire()); this._inputHandler.onLineFeed(() => this._onLineFeed.fire()); this.register(this._inputHandler); @@ -1136,8 +1137,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp } // Flag rows that need updating - this.updateRange(this.buffer.scrollTop); - this.updateRange(this.buffer.scrollBottom); + this._dirtyRowService.markRangeDirty(this.buffer.scrollTop, this.buffer.scrollBottom); this._onScroll.fire(this.buffer.ydisp); } @@ -1258,19 +1258,9 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this._xoffSentToCatchUp = false; } - this._refreshStart = this.buffer.y; - this._refreshEnd = this.buffer.y; - - // HACK: Set the parser state based on it's state at the time of return. - // This works around the bug #662 which saw the parser state reset in the - // middle of parsing escape sequence in two chunks. For some reason the - // state of the parser resets to 0 after exiting parser.parse. This change - // just sets the state back based on the correct return statement. - this._inputHandler.parseUtf8(data); - this.updateRange(this.buffer.y); - this.refresh(this._refreshStart, this._refreshEnd); + this.refresh(this._dirtyRowService.start, this._dirtyRowService.end); if (Date.now() - startTime >= WRITE_TIMEOUT_MS) { break; @@ -1345,19 +1335,9 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this._xoffSentToCatchUp = false; } - this._refreshStart = this.buffer.y; - this._refreshEnd = this.buffer.y; - - // HACK: Set the parser state based on it's state at the time of return. - // This works around the bug #662 which saw the parser state reset in the - // middle of parsing escape sequence in two chunks. For some reason the - // state of the parser resets to 0 after exiting parser.parse. This change - // just sets the state back based on the correct return statement. - this._inputHandler.parse(data); - this.updateRange(this.buffer.y); - this.refresh(this._refreshStart, this._refreshEnd); + this.refresh(this._dirtyRowService.start, this._dirtyRowService.end); if (Date.now() - startTime >= WRITE_TIMEOUT_MS) { break; @@ -1717,29 +1697,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this._onResize.fire({ cols: x, rows: y }); } - /** - * Updates the range of rows to refresh - * @param y The number of rows to refresh next. - */ - public updateRange(y: number): void { - if (y < this._refreshStart) this._refreshStart = y; - if (y > this._refreshEnd) this._refreshEnd = y; - // if (y > this.refreshEnd) { - // this.refreshEnd = y; - // if (y > this.rows - 1) { - // this.refreshEnd = this.rows - 1; - // } - // } - } - - /** - * Set the range of refreshing to the maximum value - */ - public maxRange(): void { - this._refreshStart = 0; - this._refreshEnd = this.rows - 1; - } - /** * Clear the entire buffer, making the prompt line the new first line. */ diff --git a/src/Types.d.ts b/src/Types.d.ts index 124aa4289..f96ba07d1 100644 --- a/src/Types.d.ts +++ b/src/Types.d.ts @@ -55,7 +55,6 @@ export interface IInputHandlingTerminal { bell(): void; focus(): void; - updateRange(y: number): void; scroll(isWrapped?: boolean): void; setgLevel(g: number): void; eraseAttrData(): IAttributeData; diff --git a/src/common/TestUtils.test.ts b/src/common/TestUtils.test.ts index c786a06d6..67584a362 100644 --- a/src/common/TestUtils.test.ts +++ b/src/common/TestUtils.test.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { IBufferService, ICoreService, ILogService, IOptionsService, ITerminalOptions, IPartialTerminalOptions } from 'common/services/Services'; +import { IBufferService, ICoreService, ILogService, IOptionsService, ITerminalOptions, IPartialTerminalOptions, IDirtyRowService } from 'common/services/Services'; import { IEvent, EventEmitter } from 'common/EventEmitter'; import { clone } from 'common/Clone'; import { DEFAULT_OPTIONS } from 'common/services/OptionsService'; @@ -36,6 +36,15 @@ export class MockCoreService implements ICoreService { triggerDataEvent(data: string, wasUserInput?: boolean): void {} } +export class MockDirtyRowService implements IDirtyRowService { + start: number = 0; + end: number = 0; + clearRange(): void {} + markDirty(y: number): void {} + markRangeDirty(y1: number, y2: number): void {} + markAllDirty(): void {} +} + export class MockLogService implements ILogService { debug(message: any, ...optionalParams: any[]): void {} info(message: any, ...optionalParams: any[]): void {} diff --git a/src/common/Types.d.ts b/src/common/Types.d.ts index 320aaeb8b..b25b50a5b 100644 --- a/src/common/Types.d.ts +++ b/src/common/Types.d.ts @@ -153,3 +153,8 @@ export interface IMarker extends IDisposable { export interface IDecPrivateModes { applicationCursorKeys: boolean; } + +export interface IRowRange { + start: number; + end: number; +} diff --git a/src/common/services/DirtyRowService.ts b/src/common/services/DirtyRowService.ts new file mode 100644 index 000000000..58f40dca2 --- /dev/null +++ b/src/common/services/DirtyRowService.ts @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { IBufferService, IDirtyRowService } from 'common/services/Services'; + +export class DirtyRowService implements IDirtyRowService { + private _start!: number; + private _end!: number; + + public get start(): number { return this._start; } + public get end(): number { return this._end; } + + constructor( + private readonly _bufferService: IBufferService + ) { + this.clearRange(); + } + + public clearRange(): void { + this._start = this._bufferService.buffer.y; + this._end = this._bufferService.buffer.y; + } + + public markDirty(y: number): void { + if (y < this._start) { + this._start = y; + } else if (y > this._end) { + this._end = y; + } + } + + public markRangeDirty(y1: number, y2: number): void { + if (y1 > y2) { + const temp = y1; + y1 = y2; + y2 = temp; + } + if (y1 < this._start) { + this._start = y1; + } + if (y2 > this._end) { + this._end = y2; + } + } + + public markAllDirty(): void { + this.markRangeDirty(0, this._bufferService.rows - 1); + } +} diff --git a/src/common/services/Services.d.ts b/src/common/services/Services.d.ts index 9a98ca927..427728f17 100644 --- a/src/common/services/Services.d.ts +++ b/src/common/services/Services.d.ts @@ -38,6 +38,16 @@ export interface ICoreService { triggerDataEvent(data: string, wasUserInput?: boolean): void; } +export interface IDirtyRowService { + readonly start: number; + readonly end: number; + + clearRange(): void; + markDirty(y: number): void; + markRangeDirty(y1: number, y2: number): void; + markAllDirty(): void; +} + export interface ILogService { debug(message: any, ...optionalParams: any[]): void; info(message: any, ...optionalParams: any[]): void; diff --git a/src/renderer/dom/DomRenderer.ts b/src/renderer/dom/DomRenderer.ts index 60bf50dae..22b50349b 100644 --- a/src/renderer/dom/DomRenderer.ts +++ b/src/renderer/dom/DomRenderer.ts @@ -21,9 +21,6 @@ const SELECTION_CLASS = 'xterm-selection'; let nextTerminalId = 1; -// TODO: Pull into an addon when TS composite projects allow easier sharing of code (not just -// interfaces) between core and addons - /** * A fallback renderer for when canvas is slow. This is not meant to be * particularly fast or feature complete, more just stable and usable for when