From cd8477a942e1fac85de167eab7e8c09c85f55255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Sun, 26 Aug 2018 14:27:38 +0200 Subject: [PATCH] move blankLine to TerminalLine --- src/Buffer.test.ts | 8 ++++---- src/Buffer.ts | 4 ++-- src/InputHandler.ts | 9 +++++---- src/Terminal.test.ts | 9 +++++---- src/Terminal.ts | 25 +++++-------------------- src/TerminalLine.ts | 20 ++++++++++++++++++++ src/utils/TestUtils.test.ts | 9 ++------- 7 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/Buffer.test.ts b/src/Buffer.test.ts index 82d5bd2b..ca1437d9 100644 --- a/src/Buffer.test.ts +++ b/src/Buffer.test.ts @@ -5,7 +5,7 @@ import { assert } from 'chai'; import { ITerminal } from './Types'; -import { Buffer } from './Buffer'; +import { Buffer, DEFAULT_ATTR } from './Buffer'; import { CircularList } from './common/CircularList'; import { MockTerminal } from './utils/TestUtils.test'; import { TerminalLine } from './TerminalLine'; @@ -37,7 +37,7 @@ describe('Buffer', () => { describe('fillViewportRows', () => { it('should fill the buffer with blank lines based on the size of the viewport', () => { - const blankLineChar = terminal.blankLine().get(0); + const blankLineChar = TerminalLine.blankLine(terminal.cols, DEFAULT_ATTR).get(0); buffer.fillViewportRows(); assert.equal(buffer.lines.length, INIT_ROWS); for (let y = 0; y < INIT_ROWS; y++) { @@ -180,7 +180,7 @@ describe('Buffer', () => { buffer.fillViewportRows(); // Create 10 extra blank lines for (let i = 0; i < 10; i++) { - buffer.lines.push(terminal.blankLine()); + buffer.lines.push(TerminalLine.blankLine(terminal.cols, DEFAULT_ATTR)); } // Set cursor to the bottom of the buffer buffer.y = INIT_ROWS - 1; @@ -200,7 +200,7 @@ describe('Buffer', () => { buffer.fillViewportRows(); // Create 10 extra blank lines for (let i = 0; i < 10; i++) { - buffer.lines.push(terminal.blankLine()); + buffer.lines.push(TerminalLine.blankLine(terminal.cols, DEFAULT_ATTR)); } // Set cursor to the bottom of the buffer buffer.y = INIT_ROWS - 1; diff --git a/src/Buffer.ts b/src/Buffer.ts index d98f1425..c34a3786 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -85,7 +85,7 @@ export class Buffer implements IBuffer { if (this.lines.length === 0) { let i = this._terminal.rows; while (i--) { - this.lines.push(this._terminal.blankLine()); + this.lines.push(TerminalLine.blankLine(this._terminal.cols, DEFAULT_ATTR)); } } } @@ -147,7 +147,7 @@ export class Buffer implements IBuffer { } else { // Add a blank line if there is no buffer left at the top to scroll to, or if there // are blank lines after the cursor - this.lines.push(this._terminal.blankLine(undefined, undefined, newCols)); + this.lines.push(TerminalLine.blankLine(newCols, DEFAULT_ATTR)); } } } diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 08486cd0..064d9f1c 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -13,6 +13,7 @@ import { wcwidth } from './CharWidth'; import { EscapeSequenceParser } from './EscapeSequenceParser'; import { ICharset } from './core/Types'; import { Disposable } from './common/Lifecycle'; +import { TerminalLine } from './TerminalLine'; /** * Map collect to glevel. Used in `selectCharset`. @@ -815,7 +816,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, this._terminal.blankLine(true)); + buffer.lines.splice(row, 0, TerminalLine.blankLine(this._terminal.cols, this._terminal.eraseAttr())); } // this.maxRange(); @@ -845,7 +846,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, this._terminal.blankLine(true)); + buffer.lines.splice(j, 0, TerminalLine.blankLine(this._terminal.cols, this._terminal.eraseAttr())); } // this.maxRange(); @@ -887,7 +888,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, this._terminal.blankLine()); + buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, TerminalLine.blankLine(this._terminal.cols, DEFAULT_ATTR)); } // this.maxRange(); this._terminal.updateRange(buffer.scrollTop); @@ -906,7 +907,7 @@ export class InputHandler extends Disposable implements IInputHandler { while (param--) { buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 1); - buffer.lines.splice(buffer.ybase + buffer.scrollTop, 0, this._terminal.blankLine()); + buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, TerminalLine.blankLine(this._terminal.cols, DEFAULT_ATTR)); } // this.maxRange(); this._terminal.updateRange(buffer.scrollTop); diff --git a/src/Terminal.test.ts b/src/Terminal.test.ts index 4344553e..322e6d6c 100644 --- a/src/Terminal.test.ts +++ b/src/Terminal.test.ts @@ -6,7 +6,8 @@ import { assert, expect } from 'chai'; import { Terminal } from './Terminal'; import { MockViewport, MockCompositionHelper, MockRenderer } from './utils/TestUtils.test'; -import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX } from './Buffer'; +import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, DEFAULT_ATTR } from './Buffer'; +import { TerminalLine } from './TerminalLine'; const INIT_COLS = 80; const INIT_ROWS = 24; @@ -141,7 +142,7 @@ describe('term.js addons', () => { assert.equal(term.buffer.lines.length, term.rows); assert.deepEqual(term.buffer.lines.get(0), promptLine); for (let i = 1; i < term.rows; i++) { - assert.deepEqual(term.buffer.lines.get(i), term.blankLine()); + assert.deepEqual(term.buffer.lines.get(i), TerminalLine.blankLine(term.cols, DEFAULT_ATTR)); } }); it('should clear a buffer larger than rows', () => { @@ -158,7 +159,7 @@ describe('term.js addons', () => { assert.equal(term.buffer.lines.length, term.rows); assert.deepEqual(term.buffer.lines.get(0), promptLine); for (let i = 1; i < term.rows; i++) { - assert.deepEqual(term.buffer.lines.get(i), term.blankLine()); + assert.deepEqual(term.buffer.lines.get(i), TerminalLine.blankLine(term.cols, DEFAULT_ATTR)); } }); it('should not break the prompt when cleared twice', () => { @@ -171,7 +172,7 @@ describe('term.js addons', () => { assert.equal(term.buffer.lines.length, term.rows); assert.deepEqual(term.buffer.lines.get(0), promptLine); for (let i = 1; i < term.rows; i++) { - assert.deepEqual(term.buffer.lines.get(i), term.blankLine()); + assert.deepEqual(term.buffer.lines.get(i), TerminalLine.blankLine(term.cols, DEFAULT_ATTR)); } }); }); diff --git a/src/Terminal.ts b/src/Terminal.ts index 5a6528c1..28dced6c 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -1170,7 +1170,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II * @param isWrapped Whether the new line is wrapped from the previous line. */ public scroll(isWrapped?: boolean): void { - const newLine = this.blankLine(undefined, isWrapped); + const newLine = TerminalLine.blankLine(this.cols, DEFAULT_ATTR, isWrapped); const topRow = this.buffer.ybase + this.buffer.scrollTop; const bottomRow = this.buffer.ybase + this.buffer.scrollBottom; @@ -1757,7 +1757,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II this.buffer.ybase = 0; this.buffer.y = 0; for (let i = 1; i < this.rows; i++) { - this.buffer.lines.push(this.blankLine()); + this.buffer.lines.push(TerminalLine.blankLine(this.cols, DEFAULT_ATTR)); } this.refresh(0, this.rows - 1); this.emit('scroll', this.buffer.ydisp); @@ -1778,24 +1778,9 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II * @param cols The number of columns in the terminal, if this is not * set, the terminal's current column count would be used. */ + // FIXME: can this be removed after transition to TerminalLine.blankLine? public blankLine(cur?: boolean, isWrapped?: boolean, cols?: number): TerminalLine { - const attr = cur ? this.eraseAttr() : DEFAULT_ATTR; - - const ch: CharData = [attr, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]; // width defaults to 1 halfwidth character - const line = new TerminalLine(); - - // TODO: It is not ideal that this is a property on an array, a buffer line - // class should be added that will hold this data and other useful functions. - if (isWrapped) { - line.isWrapped = isWrapped; - } - - cols = cols || this.cols; - for (let i = 0; i < cols; i++) { - line.set(i, ch); - } - - return line; + return TerminalLine.blankLine(cols || this.cols, cur ? this.eraseAttr() : DEFAULT_ATTR, isWrapped); } /** @@ -1884,7 +1869,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II // blankLine(true) is xterm/linux behavior const scrollRegionHeight = this.buffer.scrollBottom - this.buffer.scrollTop; this.buffer.lines.shiftElements(this.buffer.y + this.buffer.ybase, scrollRegionHeight, 1); - this.buffer.lines.set(this.buffer.y + this.buffer.ybase, this.blankLine(true)); + this.buffer.lines.set(this.buffer.y + this.buffer.ybase, TerminalLine.blankLine(this.cols, this.eraseAttr())); this.updateRange(this.buffer.scrollTop); this.updateRange(this.buffer.scrollBottom); } else { diff --git a/src/TerminalLine.ts b/src/TerminalLine.ts index 6e87a212..cf4f467c 100644 --- a/src/TerminalLine.ts +++ b/src/TerminalLine.ts @@ -3,8 +3,26 @@ * @license MIT */ import { CharData } from './Types'; +import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR } from './Buffer'; +/** + * Class representing a terminal line. + * Currently the class is a thin proxy to `CharData[]`. + * Once the storages are in place it will proxy access to + * typed array based line data. + * TODO: move typical line actions in `InputHandler` and `Terminal` here: + * - create blank line + * - insert cells + * - remove cells + */ export class TerminalLine { + static blankLine(cols: number, attr: number, isWrapped?: boolean): TerminalLine { + const ch: CharData = [attr, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]; + const line = new TerminalLine(); + if (isWrapped) line.isWrapped = true; + for (let i = 0; i < cols; i++) line.push(ch); + return line; + } private _data: CharData[]; public isWrapped = false; length: number; @@ -15,6 +33,7 @@ export class TerminalLine { // for debugging purpose: // throw Error when something tries to do number index access // TODO: remove when done with transition + /* for (let i = 0; i < 100; ++i) { Object.defineProperty(this, i.toString(), { get: () => { @@ -25,6 +44,7 @@ export class TerminalLine { } }); } + */ } get(index: number): CharData { diff --git a/src/utils/TestUtils.test.ts b/src/utils/TestUtils.test.ts index 0d14d471..2e60be9e 100644 --- a/src/utils/TestUtils.test.ts +++ b/src/utils/TestUtils.test.ts @@ -5,7 +5,7 @@ import { IColorSet, IRenderer, IRenderDimensions, IColorManager } from '../renderer/Types'; import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminal, IBuffer, IBufferSet, IBrowser, ICharMeasure, ISelectionManager, ITerminalOptions, ICircularList, ILinkifier, IMouseHelper, ILinkMatcherOptions, XtermListener, CharacterJoinerHandler } from '../Types'; -import { Buffer, NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR } from '../Buffer'; +import { Buffer } from '../Buffer'; import * as Browser from '../shared/utils/Browser'; import { ITheme, IDisposable, IMarker } from 'xterm'; import { TerminalLine } from '../TerminalLine'; @@ -147,12 +147,7 @@ export class MockTerminal implements ITerminal { throw new Error('Method not implemented.'); } blankLine(cur?: boolean, isWrapped?: boolean, cols?: number): TerminalLine { - const line = new TerminalLine(); - cols = cols || this.cols; - for (let i = 0; i < cols; i++) { - line.push([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]); - } - return line; + return TerminalLine.blankLine(this.cols, 0); } registerCharacterJoiner(handler: CharacterJoinerHandler): number { return 0; } deregisterCharacterJoiner(joinerId: number): void { }