From 7a1bef7daf2e9f74529a607aa968eda1595ce649 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 18 Dec 2019 11:47:45 +1100 Subject: [PATCH] More cur/erase attr data to input handler --- src/InputHandler.ts | 68 +++++++++++++++++++++++++------------------ src/Terminal.test.ts | 18 ++++++------ src/Terminal.ts | 18 +----------- src/TestUtils.test.ts | 1 + src/Types.d.ts | 4 +-- 5 files changed, 52 insertions(+), 57 deletions(-) diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 21b19475..d01ebc5e 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -128,6 +128,9 @@ export class InputHandler extends Disposable implements IInputHandler { private _utf8Decoder: Utf8ToUtf32 = new Utf8ToUtf32(); private _workCell: CellData = new CellData(); + private _curAttrData: IAttributeData = DEFAULT_ATTR_DATA.clone(); + private _eraseAttrDataInternal: IAttributeData = DEFAULT_ATTR_DATA.clone(); + private _onRequestRefreshRows = new EventEmitter(); public get onRequestRefreshRows(): IEvent { return this._onRequestRefreshRows.event; } private _onCursorMove = new EventEmitter(); @@ -387,7 +390,7 @@ export class InputHandler extends Disposable implements IInputHandler { const cols = this._bufferService.cols; const wraparoundMode = this._coreService.decPrivateModes.wraparound; const insertMode = this._terminal.insertMode; - const curAttr = this._terminal.curAttrData; + const curAttr = this._curAttrData; let bufferRow = buffer.lines.get(buffer.y + buffer.ybase); this._dirtyRowService.markDirty(buffer.y); @@ -442,7 +445,7 @@ export class InputHandler extends Disposable implements IInputHandler { buffer.y++; if (buffer.y === buffer.scrollBottom + 1) { buffer.y--; - this._terminal.scroll(true); + this._terminal.scroll(this._eraseAttrData(), true); } else { if (buffer.y >= this._bufferService.rows) { buffer.y = this._bufferService.rows - 1; @@ -556,7 +559,7 @@ export class InputHandler extends Disposable implements IInputHandler { buffer.y++; if (buffer.y === buffer.scrollBottom + 1) { buffer.y--; - this._terminal.scroll(); + this._terminal.scroll(this._eraseAttrData()); } else if (buffer.y >= this._bufferService.rows) { buffer.y = this._bufferService.rows - 1; } @@ -848,7 +851,7 @@ export class InputHandler extends Disposable implements IInputHandler { line.replaceCells( start, end, - this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData()) + this._bufferService.buffer.getNullCell(this._eraseAttrData()) ); if (clearWrap) { line.isWrapped = false; @@ -862,7 +865,7 @@ export class InputHandler extends Disposable implements IInputHandler { */ private _resetBufferLine(y: number): void { const line = this._bufferService.buffer.lines.get(this._bufferService.buffer.ybase + y); - line.fill(this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData())); + line.fill(this._bufferService.buffer.getNullCell(this._eraseAttrData())); line.isWrapped = false; } @@ -977,7 +980,7 @@ export class InputHandler extends Disposable implements IInputHandler { // test: echo -e '\e[44m\e[1L\e[0m' // blankLine(true) - xterm/linux behavior buffer.lines.splice(scrollBottomAbsolute - 1, 1); - buffer.lines.splice(row, 0, buffer.getBlankLine(this._terminal.eraseAttrData())); + buffer.lines.splice(row, 0, buffer.getBlankLine(this._eraseAttrData())); } this._dirtyRowService.markRangeDirty(buffer.y, buffer.scrollBottom); @@ -1008,7 +1011,7 @@ export class InputHandler extends Disposable implements IInputHandler { // test: echo -e '\e[44m\e[1M\e[0m' // blankLine(true) - xterm/linux behavior buffer.lines.splice(row, 1); - buffer.lines.splice(j, 0, buffer.getBlankLine(this._terminal.eraseAttrData())); + buffer.lines.splice(j, 0, buffer.getBlankLine(this._eraseAttrData())); } this._dirtyRowService.markRangeDirty(buffer.y, buffer.scrollBottom); @@ -1026,7 +1029,7 @@ export class InputHandler extends Disposable implements IInputHandler { line.insertCells( this._bufferService.buffer.x, params.params[0] || 1, - this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData()) + this._bufferService.buffer.getNullCell(this._eraseAttrData()) ); this._dirtyRowService.markDirty(this._bufferService.buffer.y); } @@ -1043,7 +1046,7 @@ export class InputHandler extends Disposable implements IInputHandler { line.deleteCells( this._bufferService.buffer.x, params.params[0] || 1, - this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData()) + this._bufferService.buffer.getNullCell(this._eraseAttrData()) ); this._dirtyRowService.markDirty(this._bufferService.buffer.y); } @@ -1060,7 +1063,7 @@ export class InputHandler extends Disposable implements IInputHandler { while (param--) { buffer.lines.splice(buffer.ybase + buffer.scrollTop, 1); - buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, buffer.getBlankLine(this._terminal.eraseAttrData())); + buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, buffer.getBlankLine(this._eraseAttrData())); } this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); } @@ -1103,7 +1106,7 @@ export class InputHandler extends Disposable implements IInputHandler { const param = params.params[0] || 1; for (let y = buffer.scrollTop; y <= buffer.scrollBottom; ++y) { const line = buffer.lines.get(buffer.ybase + y); - line.deleteCells(0, param, buffer.getNullCell(this._terminal.eraseAttrData())); + line.deleteCells(0, param, buffer.getNullCell(this._eraseAttrData())); line.isWrapped = false; } this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); @@ -1131,7 +1134,7 @@ export class InputHandler extends Disposable implements IInputHandler { const param = params.params[0] || 1; for (let y = buffer.scrollTop; y <= buffer.scrollBottom; ++y) { const line = buffer.lines.get(buffer.ybase + y); - line.insertCells(0, param, buffer.getNullCell(this._terminal.eraseAttrData())); + line.insertCells(0, param, buffer.getNullCell(this._eraseAttrData())); line.isWrapped = false; } this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); @@ -1149,7 +1152,7 @@ export class InputHandler extends Disposable implements IInputHandler { const param = params.params[0] || 1; for (let y = buffer.scrollTop; y <= buffer.scrollBottom; ++y) { const line = this._bufferService.buffer.lines.get(buffer.ybase + y); - line.insertCells(buffer.x, param, buffer.getNullCell(this._terminal.eraseAttrData())); + line.insertCells(buffer.x, param, buffer.getNullCell(this._eraseAttrData())); line.isWrapped = false; } this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); @@ -1167,7 +1170,7 @@ export class InputHandler extends Disposable implements IInputHandler { const param = params.params[0] || 1; for (let y = buffer.scrollTop; y <= buffer.scrollBottom; ++y) { const line = buffer.lines.get(buffer.ybase + y); - line.deleteCells(buffer.x, param, buffer.getNullCell(this._terminal.eraseAttrData())); + line.deleteCells(buffer.x, param, buffer.getNullCell(this._eraseAttrData())); line.isWrapped = false; } this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); @@ -1184,7 +1187,7 @@ export class InputHandler extends Disposable implements IInputHandler { line.replaceCells( this._bufferService.buffer.x, this._bufferService.buffer.x + (params.params[0] || 1), - this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData()) + this._bufferService.buffer.getNullCell(this._eraseAttrData()) ); this._dirtyRowService.markDirty(this._bufferService.buffer.y); } @@ -1465,7 +1468,7 @@ export class InputHandler extends Disposable implements IInputHandler { // FALL-THROUGH case 47: // alt screen buffer case 1047: // alt screen buffer - this._bufferService.buffers.activateAltBuffer(this._terminal.eraseAttrData()); + this._bufferService.buffers.activateAltBuffer(this._eraseAttrData()); this._onRequestRefreshRows.fire(0, this._bufferService.rows - 1); this._terminal.viewport?.syncScrollArea(); this._terminal.showCursor(); @@ -1787,14 +1790,14 @@ export class InputHandler extends Disposable implements IInputHandler { public charAttributes(params: IParams): void { // Optimize a single SGR0. if (params.length === 1 && params.params[0] === 0) { - this._terminal.curAttrData.fg = DEFAULT_ATTR_DATA.fg; - this._terminal.curAttrData.bg = DEFAULT_ATTR_DATA.bg; + this._curAttrData.fg = DEFAULT_ATTR_DATA.fg; + this._curAttrData.bg = DEFAULT_ATTR_DATA.bg; return; } const l = params.length; let p; - const attr = this._terminal.curAttrData; + const attr = this._curAttrData; for (let i = 0; i < l; i++) { p = params.params[i]; @@ -1959,7 +1962,7 @@ export class InputHandler extends Disposable implements IInputHandler { this._terminal.viewport?.syncScrollArea(); this._bufferService.buffer.scrollTop = 0; this._bufferService.buffer.scrollBottom = this._bufferService.rows - 1; - this._terminal.curAttrData = DEFAULT_ATTR_DATA.clone(); + this._curAttrData = DEFAULT_ATTR_DATA.clone(); this._bufferService.buffer.x = this._bufferService.buffer.y = 0; // ? this._coreService.reset(); this._charsetService.reset(); @@ -2024,8 +2027,8 @@ export class InputHandler extends Disposable implements IInputHandler { public saveCursor(params?: IParams): void { this._bufferService.buffer.savedX = this._bufferService.buffer.x; this._bufferService.buffer.savedY = this._bufferService.buffer.ybase + this._bufferService.buffer.y; - this._bufferService.buffer.savedCurAttrData.fg = this._terminal.curAttrData.fg; - this._bufferService.buffer.savedCurAttrData.bg = this._terminal.curAttrData.bg; + this._bufferService.buffer.savedCurAttrData.fg = this._curAttrData.fg; + this._bufferService.buffer.savedCurAttrData.bg = this._curAttrData.bg; this._bufferService.buffer.savedCharset = this._charsetService.charset; } @@ -2038,8 +2041,8 @@ export class InputHandler extends Disposable implements IInputHandler { public restoreCursor(params?: IParams): void { this._bufferService.buffer.x = this._bufferService.buffer.savedX || 0; this._bufferService.buffer.y = Math.max(this._bufferService.buffer.savedY - this._bufferService.buffer.ybase, 0); - this._terminal.curAttrData.fg = this._bufferService.buffer.savedCurAttrData.fg; - this._terminal.curAttrData.bg = this._bufferService.buffer.savedCurAttrData.bg; + this._curAttrData.fg = this._bufferService.buffer.savedCurAttrData.fg; + this._curAttrData.bg = this._bufferService.buffer.savedCurAttrData.bg; this._charsetService.charset = (this as any)._savedCharset; if (this._bufferService.buffer.savedCharset) { this._charsetService.charset = this._bufferService.buffer.savedCharset; @@ -2141,7 +2144,7 @@ export class InputHandler extends Disposable implements IInputHandler { this._bufferService.buffer.y++; if (buffer.y === buffer.scrollBottom + 1) { buffer.y--; - this._terminal.scroll(); + this._terminal.scroll(this._eraseAttrData()); } else if (buffer.y >= this._bufferService.rows) { buffer.y = this._bufferService.rows - 1; } @@ -2175,7 +2178,7 @@ export class InputHandler extends Disposable implements IInputHandler { // blankLine(true) is xterm/linux behavior 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())); + buffer.lines.set(buffer.y + buffer.ybase, buffer.getBlankLine(this._eraseAttrData())); this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); } else { buffer.y--; @@ -2193,6 +2196,15 @@ export class InputHandler extends Disposable implements IInputHandler { this._terminal.reset(); // TODO: save to move from terminal? } + /** + * back_color_erase feature for xterm. + */ + private _eraseAttrData(): IAttributeData { + this._eraseAttrDataInternal.bg &= ~(Attributes.CM_MASK | 0xFFFFFF); + this._eraseAttrDataInternal.bg |= this._curAttrData.bg & ~0xFC000000; + return this._eraseAttrDataInternal; + } + /** * ESC n * ESC o @@ -2219,8 +2231,8 @@ export class InputHandler extends Disposable implements IInputHandler { // prepare cell data const cell = new CellData(); cell.content = 1 << Content.WIDTH_SHIFT | 'E'.charCodeAt(0); - cell.fg = this._terminal.curAttrData.fg; - cell.bg = this._terminal.curAttrData.bg; + cell.fg = this._curAttrData.fg; + cell.bg = this._curAttrData.bg; const buffer = this._bufferService.buffer; diff --git a/src/Terminal.test.ts b/src/Terminal.test.ts index 062bddf4..90522bf4 100644 --- a/src/Terminal.test.ts +++ b/src/Terminal.test.ts @@ -112,7 +112,7 @@ describe('Terminal', () => { assert.equal(typeof e, 'number'); done(); }); - term.scroll(); + term.scroll(DEFAULT_ATTR_DATA.clone()); }); it('should fire the onTitleChange event', (done) => { term.onTitleChange(e => { @@ -397,7 +397,7 @@ describe('Terminal', () => { term.buffer.lines.get(0).setCell(0, CellData.fromCharData([0, 'a', 0, 'a'.charCodeAt(0)])); term.buffer.lines.get(INIT_ROWS - 1).setCell(0, CellData.fromCharData([0, 'b', 0, 'b'.charCodeAt(0)])); term.buffer.y = INIT_ROWS - 1; // Move cursor to last line - term.scroll(); + term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS + 1); assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a'); assert.equal(term.buffer.lines.get(INIT_ROWS - 1).loadCell(0, new CellData()).getChars(), 'b'); @@ -410,7 +410,7 @@ describe('Terminal', () => { term.buffer.lines.get(2).setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); term.buffer.y = INIT_ROWS - 1; // Move cursor to last line term.buffer.scrollTop = 1; - term.scroll(); + term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS); assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a'); assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c'); @@ -424,7 +424,7 @@ describe('Terminal', () => { term.buffer.lines.get(4).setCell(0, CellData.fromCharData([0, 'e', 0, 'e'.charCodeAt(0)])); term.buffer.y = 3; term.buffer.scrollBottom = 3; - term.scroll(); + term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS + 1); assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a', '\'a\' should be pushed to the scrollback'); assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'b'); @@ -443,7 +443,7 @@ describe('Terminal', () => { term.buffer.y = INIT_ROWS - 1; // Move cursor to last line term.buffer.scrollTop = 1; term.buffer.scrollBottom = 3; - term.scroll(); + term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS); assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a'); assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c', '\'b\' should be removed from the buffer'); @@ -465,7 +465,7 @@ describe('Terminal', () => { term.buffer.lines.get(INIT_ROWS - 1).setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); term.buffer.y = INIT_ROWS - 1; // Move cursor to last line assert.equal(term.buffer.lines.length, INIT_ROWS); - term.scroll(); + term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS); // 'a' gets pushed out of buffer assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'b'); @@ -480,7 +480,7 @@ describe('Terminal', () => { term.buffer.lines.get(2).setCell(0, CellData.fromCharData([0, 'c', 0, 'c'.charCodeAt(0)])); term.buffer.y = INIT_ROWS - 1; // Move cursor to last line term.buffer.scrollTop = 1; - term.scroll(); + term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS); assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a'); assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c'); @@ -494,7 +494,7 @@ describe('Terminal', () => { term.buffer.lines.get(4).setCell(0, CellData.fromCharData([0, 'e', 0, 'e'.charCodeAt(0)])); term.buffer.y = 3; term.buffer.scrollBottom = 3; - term.scroll(); + term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS); assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'b'); assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c'); @@ -512,7 +512,7 @@ describe('Terminal', () => { term.buffer.y = INIT_ROWS - 1; // Move cursor to last line term.buffer.scrollTop = 1; term.buffer.scrollBottom = 3; - term.scroll(); + term.scroll(DEFAULT_ATTR_DATA.clone()); assert.equal(term.buffer.lines.length, INIT_ROWS); assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a'); assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c', '\'b\' should be removed from the buffer'); diff --git a/src/Terminal.ts b/src/Terminal.ts index 6d0bbea2..21d8ee60 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -122,9 +122,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp // misc public savedCols: number; - public curAttrData: IAttributeData; - private _eraseAttrData: IAttributeData; - public params: (string | number)[]; public currentParam: string | number; @@ -254,9 +251,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp // charset this._charsetService.reset(); - this.curAttrData = DEFAULT_ATTR_DATA.clone(); - this._eraseAttrData = DEFAULT_ATTR_DATA.clone(); - this.params = []; this.currentParam = 0; @@ -293,15 +287,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp return this._bufferService.buffers; } - /** - * back_color_erase feature for xterm. - */ - public eraseAttrData(): IAttributeData { - this._eraseAttrData.bg &= ~(Attributes.CM_MASK | 0xFFFFFF); - this._eraseAttrData.bg |= this.curAttrData.bg & ~0xFC000000; - return this._eraseAttrData; - } - /** * Focus the terminal. Delegates focus handling to the terminal's DOM element. */ @@ -946,10 +931,9 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp * Scroll the terminal down 1 row, creating a blank line. * @param isWrapped Whether the new line is wrapped from the previous line. */ - public scroll(isWrapped: boolean = false): void { + public scroll(eraseAttr: IAttributeData, isWrapped: boolean = false): void { let newLine: IBufferLine; newLine = this._blankLine; - const eraseAttr = this.eraseAttrData(); if (!newLine || newLine.length !== this.cols || newLine.getFg(0) !== eraseAttr.fg || newLine.getBg(0) !== eraseAttr.bg) { newLine = this.buffer.getBlankLine(eraseAttr, isWrapped); this._blankLine = newLine; diff --git a/src/TestUtils.test.ts b/src/TestUtils.test.ts index cf23b8eb..9338fbc0 100644 --- a/src/TestUtils.test.ts +++ b/src/TestUtils.test.ts @@ -19,6 +19,7 @@ import { IParams, IFunctionIdentifier } from 'common/parser/Types'; import { ISelectionService } from 'browser/services/Services'; export class TestTerminal extends Terminal { + get curAttrData(): IAttributeData { return (this as any)._inputHandler._curAttrData; } keyDown(ev: any): boolean { return this._keyDown(ev); } keyPress(ev: any): boolean { return this._keyPress(ev); } } diff --git a/src/Types.d.ts b/src/Types.d.ts index 7742b69c..e5021f88 100644 --- a/src/Types.d.ts +++ b/src/Types.d.ts @@ -27,7 +27,6 @@ export interface IInputHandlingTerminal { rows: number; insertMode: boolean; bracketedPasteMode: boolean; - curAttrData: IAttributeData; savedCols: number; mouseEvents: CoreMouseEventType; sendFocus: boolean; @@ -41,8 +40,7 @@ export interface IInputHandlingTerminal { bell(): void; focus(): void; - scroll(isWrapped?: boolean): void; - eraseAttrData(): IAttributeData; + scroll(eraseAttr: IAttributeData, isWrapped?: boolean): void; is(term: string): boolean; resize(x: number, y: number): void; reset(): void;