From 9bb16e4b1672f10e4104b61a285e02d7e42c625f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 15 Jun 2019 19:24:14 -0700 Subject: [PATCH 01/11] Fix restore cursor related tests Weird failure happening sometimes after #2217, not sure why pipelines didn't pick it up. --- src/InputHandler.test.ts | 1 + src/common/buffer/Buffer.ts | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InputHandler.test.ts b/src/InputHandler.test.ts index 8170796f..19d5f6a2 100644 --- a/src/InputHandler.test.ts +++ b/src/InputHandler.test.ts @@ -18,6 +18,7 @@ describe('InputHandler', () => { const terminal = new MockInputHandlingTerminal(); terminal.buffer.x = 1; terminal.buffer.y = 2; + terminal.buffer.ybase = 0; terminal.curAttrData.fg = 3; const inputHandler = new InputHandler(terminal); // Save cursor position diff --git a/src/common/buffer/Buffer.ts b/src/common/buffer/Buffer.ts index 084b1bea..9c36a5a4 100644 --- a/src/common/buffer/Buffer.ts +++ b/src/common/buffer/Buffer.ts @@ -126,7 +126,6 @@ export class Buffer implements IBuffer { public clear(): void { this.ydisp = 0; this.ybase = 0; - this.savedY = 0; this.y = 0; this.x = 0; this.lines = new CircularList(this._getCorrectBufferLength(this._rows)); From a4d18a3b237371329febed1f1efb0d01a28e1dc4 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 15 Jun 2019 19:40:51 -0700 Subject: [PATCH 02/11] Introduce mouse service --- src/MouseZoneManager.ts | 6 ++- src/SelectionManager.test.ts | 4 +- src/SelectionManager.ts | 17 +++--- src/Terminal.ts | 27 +++++----- src/TestUtils.test.ts | 3 +- src/Types.d.ts | 3 +- src/browser/TestUtils.test.ts | 12 ++++- src/browser/Types.d.ts | 5 -- src/browser/input/Mouse.test.ts | 40 ++++++++++++++ src/browser/input/Mouse.ts | 58 +++++++++++++++++++++ src/browser/input/MouseHelper.test.ts | 49 ----------------- src/browser/input/MouseHelper.ts | 75 --------------------------- src/browser/services/MouseService.ts | 33 ++++++++++++ src/browser/services/Services.d.ts | 5 ++ src/handlers/AltClickHandler.ts | 6 ++- 15 files changed, 182 insertions(+), 161 deletions(-) create mode 100644 src/browser/input/Mouse.test.ts create mode 100644 src/browser/input/Mouse.ts delete mode 100644 src/browser/input/MouseHelper.test.ts delete mode 100644 src/browser/input/MouseHelper.ts create mode 100644 src/browser/services/MouseService.ts diff --git a/src/MouseZoneManager.ts b/src/MouseZoneManager.ts index b2ee9b14..de724b88 100644 --- a/src/MouseZoneManager.ts +++ b/src/MouseZoneManager.ts @@ -6,6 +6,7 @@ import { ITerminal, IMouseZoneManager, IMouseZone } from './Types'; import { Disposable } from 'common/Lifecycle'; import { addDisposableDomListener } from 'browser/Lifecycle'; +import { IMouseService } from 'browser/services/Services'; const HOVER_DURATION = 500; @@ -31,7 +32,8 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager { private _initialSelectionLength: number; constructor( - private _terminal: ITerminal + private _terminal: ITerminal, + private _mouseService: IMouseService ) { super(); @@ -203,7 +205,7 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager { } private _findZoneEventAt(e: MouseEvent): IMouseZone { - const coords = this._terminal.mouseHelper.getCoords(e, this._terminal.screenElement, this._terminal.cols, this._terminal.rows); + const coords = this._mouseService.getCoords(e, this._terminal.screenElement, this._terminal.cols, this._terminal.rows); if (!coords) { return null; } diff --git a/src/SelectionManager.test.ts b/src/SelectionManager.test.ts index f58815f0..8499497a 100644 --- a/src/SelectionManager.test.ts +++ b/src/SelectionManager.test.ts @@ -14,7 +14,7 @@ import { MockTerminal } from './TestUtils.test'; import { MockOptionsService, MockBufferService } from 'common/TestUtils.test'; import { BufferLine } from 'common/buffer/BufferLine'; import { IBufferService } from 'common/services/Services'; -import { MockCharSizeService } from 'browser/TestUtils.test'; +import { MockCharSizeService, MockMouseService } from 'browser/TestUtils.test'; import { CellData } from 'common/buffer/CellData'; class TestMockTerminal extends MockTerminal { @@ -26,7 +26,7 @@ class TestSelectionManager extends SelectionManager { terminal: ITerminal, bufferService: IBufferService ) { - super(terminal, new MockCharSizeService(10, 10), bufferService); + super(terminal, new MockCharSizeService(10, 10), bufferService, new MockMouseService()); } public get model(): SelectionModel { return this._model; } diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index 05beaeab..aa388d8a 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -6,15 +6,15 @@ import { ITerminal, ISelectionManager, ISelectionRedrawRequestEvent } from './Types'; import { IBuffer } from 'common/buffer/Types'; import { IBufferLine } from 'common/Types'; -import { MouseHelper } from 'browser/input/MouseHelper'; import * as Browser from 'common/Platform'; import { SelectionModel } from './SelectionModel'; import { AltClickHandler } from './handlers/AltClickHandler'; import { CellData } from 'common/buffer/CellData'; import { IDisposable } from 'xterm'; import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { ICharSizeService } from 'browser/services/Services'; +import { ICharSizeService, IMouseService } from 'browser/services/Services'; import { IBufferService } from 'common/services/Services'; +import { getCoordsRelativeToElement } from 'browser/input/Mouse'; /** * The number of pixels the mouse needs to be above or below the viewport in @@ -118,9 +118,10 @@ export class SelectionManager implements ISelectionManager { public get onSelectionChange(): IEvent { return this._onSelectionChange.event; } constructor( - private _terminal: ITerminal, - private _charSizeService: ICharSizeService, - bufferService: IBufferService + private readonly _terminal: ITerminal, + private readonly _charSizeService: ICharSizeService, + readonly bufferService: IBufferService, + private readonly _mouseService: IMouseService ) { this._initListeners(); this.enable(); @@ -357,7 +358,7 @@ export class SelectionManager implements ISelectionManager { * @param event The mouse event. */ private _getMouseBufferCoords(event: MouseEvent): [number, number] { - const coords = this._terminal.mouseHelper.getCoords(event, this._terminal.screenElement, this._terminal.cols, this._terminal.rows, true); + const coords = this._mouseService.getCoords(event, this._terminal.screenElement, this._terminal.cols, this._terminal.rows, true); if (!coords) { return null; } @@ -377,7 +378,7 @@ export class SelectionManager implements ISelectionManager { * @param event The mouse event. */ private _getMouseEventScrollAmount(event: MouseEvent): number { - let offset = MouseHelper.getCoordsRelativeToElement(event, this._terminal.screenElement)[1]; + let offset = getCoordsRelativeToElement(event, this._terminal.screenElement)[1]; const terminalHeight = this._terminal.rows * Math.ceil(this._charSizeService.height * this._terminal.options.lineHeight); if (offset >= 0 && offset <= terminalHeight) { return 0; @@ -654,7 +655,7 @@ export class SelectionManager implements ISelectionManager { this._removeMouseDownListeners(); if (this.selectionText.length <= 1 && timeElapsed < ALT_CLICK_MOVE_CURSOR_TIME) { - (new AltClickHandler(event, this._terminal)).move(); + (new AltClickHandler(event, this._terminal, this._mouseService)).move(); } else if (this.hasSelection) { this._onSelectionChange.fire(); } diff --git a/src/Terminal.ts b/src/Terminal.ts index 42cacf6f..59346505 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -34,7 +34,6 @@ import { SelectionManager } from './SelectionManager'; import * as Browser from 'common/Platform'; import { addDisposableDomListener } from 'browser/Lifecycle'; import * as Strings from './browser/LocalizableStrings'; -import { MouseHelper } from 'browser/input/MouseHelper'; import { SoundManager } from './SoundManager'; import { MouseZoneManager } from './MouseZoneManager'; import { AccessibilityManager } from './AccessibilityManager'; @@ -50,12 +49,13 @@ import { ColorManager } from 'browser/ColorManager'; import { RenderService } from 'browser/services/RenderService'; import { IOptionsService, IBufferService } from 'common/services/Services'; import { OptionsService } from 'common/services/OptionsService'; -import { ICharSizeService } from 'browser/services/Services'; +import { ICharSizeService, IRenderService, IMouseService } from 'browser/services/Services'; import { CharSizeService } from 'browser/services/CharSizeService'; import { BufferService, MINIMUM_COLS, MINIMUM_ROWS } from 'common/services/BufferService'; import { Disposable } from 'common/Lifecycle'; import { IBufferSet, IBuffer } from 'common/buffer/Types'; import { Attributes } from 'common/buffer/Constants'; +import { MouseService } from 'browser/services/MouseService'; // Let it work inside Node.js for automated testing purposes. const document = (typeof window !== 'undefined') ? window.document : null; @@ -111,7 +111,8 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp // browser services private _charSizeService: ICharSizeService; - private _renderService: RenderService; + private _renderService: IRenderService; + private _mouseService: IMouseService; // modes public applicationKeypad: boolean; @@ -177,7 +178,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp public viewport: IViewport; private _compositionHelper: ICompositionHelper; private _mouseZoneManager: IMouseZoneManager; - public mouseHelper: MouseHelper; private _accessibilityManager: AccessibilityManager; private _colorManager: ColorManager; private _theme: ITheme; @@ -591,11 +591,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this.screenElement.appendChild(this._helperContainer); fragment.appendChild(this.screenElement); - this._mouseZoneManager = new MouseZoneManager(this); - this.register(this._mouseZoneManager); - this.register(this.onScroll(() => this._mouseZoneManager.clearAll())); - this.linkifier.attachToDom(this._mouseZoneManager); - this.textarea = document.createElement('textarea'); this.textarea.classList.add('xterm-helper-textarea'); this.textarea.setAttribute('aria-label', Strings.promptLabel); @@ -628,6 +623,13 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this._renderService.onRender(e => this._onRender.fire(e)); this.onResize(e => this._renderService.resize(e.cols, e.rows)); + this._mouseService = new MouseService(this._renderService, this._charSizeService); + + this._mouseZoneManager = new MouseZoneManager(this, this._mouseService); + this.register(this._mouseZoneManager); + this.register(this.onScroll(() => this._mouseZoneManager.clearAll())); + this.linkifier.attachToDom(this._mouseZoneManager); + this.viewport = new Viewport(this, this._viewportElement, this._viewportScrollArea, this._renderService.dimensions, this._charSizeService); this.viewport.onThemeChange(this._colorManager.colors); this.register(this.viewport); @@ -638,7 +640,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this.register(this.onFocus(() => this._renderService.onFocus())); this.register(this._renderService.onDimensionsChange(() => this.viewport.syncScrollArea())); - this.selectionManager = new SelectionManager(this, this._charSizeService, this._bufferService); + this.selectionManager = new SelectionManager(this, this._charSizeService, this._bufferService, this._mouseService); 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._renderService.onSelectionChanged(e.start, e.end, e.columnSelectMode))); @@ -656,7 +658,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp })); this.register(addDisposableDomListener(this._viewportElement, 'scroll', () => this.selectionManager.refresh())); - this.mouseHelper = new MouseHelper(this._renderService, this._charSizeService); // apply mouse event classes set by escape codes before terminal was attached this.element.classList.toggle('enable-mouse-events', this.mouseEvents); if (this.mouseEvents) { @@ -738,7 +739,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp button = getButton(ev); // get mouse coordinates - pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.cols, self.rows); + pos = self._mouseService.getRawByteCoords(ev, self.screenElement, self.cols, self.rows); if (!pos) return; sendEvent(button, pos); @@ -764,7 +765,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp // ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7< function sendMove(ev: MouseEvent): void { let button = pressed; - const pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.cols, self.rows); + const pos = self._mouseService.getRawByteCoords(ev, self.screenElement, self.cols, self.rows); if (!pos) return; // buttons marked as motions diff --git a/src/TestUtils.test.ts b/src/TestUtils.test.ts index 257babe8..07f91705 100644 --- a/src/TestUtils.test.ts +++ b/src/TestUtils.test.ts @@ -12,7 +12,7 @@ import * as Browser from 'common/Platform'; import { IDisposable, IMarker, IEvent, ISelectionPosition } from 'xterm'; import { Terminal } from './Terminal'; import { AttributeData } from 'common/buffer/AttributeData'; -import { IColorManager, IColorSet, IMouseHelper } from 'browser/Types'; +import { IColorManager, IColorSet } from 'browser/Types'; import { IOptionsService } from 'common/services/Services'; import { EventEmitter } from 'common/EventEmitter'; @@ -122,7 +122,6 @@ export class MockTerminal implements ITerminal { throw new Error('Method not implemented.'); } bracketedPasteMode: boolean; - mouseHelper: IMouseHelper; renderer: IRenderer; linkifier: ILinkifier; isFocused: boolean; diff --git a/src/Types.d.ts b/src/Types.d.ts index 6f587931..5987d605 100644 --- a/src/Types.d.ts +++ b/src/Types.d.ts @@ -6,7 +6,7 @@ import { ITerminalOptions as IPublicTerminalOptions, IDisposable, IMarker, ISelectionPosition } from 'xterm'; import { ICharset, IAttributeData, CharData } from 'common/Types'; import { IEvent, IEventEmitter } from 'common/EventEmitter'; -import { IColorSet, IMouseHelper } from 'browser/Types'; +import { IColorSet } from 'browser/Types'; import { IOptionsService } from 'common/services/Services'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; @@ -204,7 +204,6 @@ export interface ITerminal extends IPublicTerminal, IElementAccessor, IBufferAcc buffer: IBuffer; buffers: IBufferSet; isFocused: boolean; - mouseHelper: IMouseHelper; viewport: IViewport; bracketedPasteMode: boolean; applicationCursor: boolean; diff --git a/src/browser/TestUtils.test.ts b/src/browser/TestUtils.test.ts index b286295b..d89dc391 100644 --- a/src/browser/TestUtils.test.ts +++ b/src/browser/TestUtils.test.ts @@ -4,7 +4,7 @@ */ import { IEvent, EventEmitter } from 'common/EventEmitter'; -import { ICharSizeService } from 'browser/services/Services'; +import { ICharSizeService, IMouseService } from 'browser/services/Services'; export class MockCharSizeService implements ICharSizeService { get hasValidSize(): boolean { return this.width > 0 && this.height > 0; } @@ -12,3 +12,13 @@ export class MockCharSizeService implements ICharSizeService { constructor(public width: number, public height: number) {} measure(): void {} } + +export class MockMouseService implements IMouseService { + public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined { + throw new Error('Not implemented'); + } + + public getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number, y: number } | undefined { + throw new Error('Not implemented'); + } +} diff --git a/src/browser/Types.d.ts b/src/browser/Types.d.ts index a1ea662c..ef725ba6 100644 --- a/src/browser/Types.d.ts +++ b/src/browser/Types.d.ts @@ -20,8 +20,3 @@ export interface IColorSet { selection: IColor; ansi: IColor[]; } - -export interface IMouseHelper { - getCoords(event: { clientX: number, clientY: number }, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined; - getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number | undefined, y: number | undefined }; -} diff --git a/src/browser/input/Mouse.test.ts b/src/browser/input/Mouse.test.ts new file mode 100644 index 00000000..6a908499 --- /dev/null +++ b/src/browser/input/Mouse.test.ts @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2017 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import jsdom = require('jsdom'); +import { assert } from 'chai'; +import { getCoords } from 'browser/input/Mouse'; + +const CHAR_WIDTH = 10; +const CHAR_HEIGHT = 20; + +describe('Mouse getCoords', () => { + let document: Document; + + beforeEach(() => { + document = new jsdom.JSDOM('').window.document; + }); + + it('should return the cell that was clicked', () => { + let coords: [number, number] | undefined; + coords = getCoords({ clientX: CHAR_WIDTH / 2, clientY: CHAR_HEIGHT / 2 }, document.createElement('div'), 10, 10, true, CHAR_WIDTH, CHAR_HEIGHT); + assert.deepEqual(coords, [1, 1]); + coords = getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT }, document.createElement('div'), 10, 10, true, CHAR_WIDTH, CHAR_HEIGHT); + assert.deepEqual(coords, [1, 1]); + coords = getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT + 1 }, document.createElement('div'), 10, 10, true, CHAR_WIDTH, CHAR_HEIGHT); + assert.deepEqual(coords, [1, 2]); + coords = getCoords({ clientX: CHAR_WIDTH + 1, clientY: CHAR_HEIGHT }, document.createElement('div'), 10, 10, true, CHAR_WIDTH, CHAR_HEIGHT); + assert.deepEqual(coords, [2, 1]); + }); + + it('should ensure the coordinates are returned within the terminal bounds', () => { + let coords: [number, number] | undefined; + coords = getCoords({ clientX: -1, clientY: -1 }, document.createElement('div'), 10, 10, true, CHAR_WIDTH, CHAR_HEIGHT); + assert.deepEqual(coords, [1, 1]); + // Event are double the cols/rows + coords = getCoords({ clientX: CHAR_WIDTH * 20, clientY: CHAR_HEIGHT * 20 }, document.createElement('div'), 10, 10, true, CHAR_WIDTH, CHAR_HEIGHT); + assert.deepEqual(coords, [10, 10], 'coordinates should never come back as larger than the terminal'); + }); +}); diff --git a/src/browser/input/Mouse.ts b/src/browser/input/Mouse.ts new file mode 100644 index 00000000..2986fb3c --- /dev/null +++ b/src/browser/input/Mouse.ts @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2017 The xterm.js authors. All rights reserved. + * @license MIT + */ + +export function getCoordsRelativeToElement(event: {clientX: number, clientY: number}, element: HTMLElement): [number, number] { + const rect = element.getBoundingClientRect(); + return [event.clientX - rect.left, event.clientY - rect.top]; +} + +/** + * Gets coordinates within the terminal for a particular mouse event. The result + * is returned as an array in the form [x, y] instead of an object as it's a + * little faster and this function is used in some low level code. + * @param event The mouse event. + * @param element The terminal's container element. + * @param colCount The number of columns in the terminal. + * @param rowCount The number of rows n the terminal. + * @param isSelection Whether the request is for the selection or not. This will + * apply an offset to the x value such that the left half of the cell will + * select that cell and the right half will select the next cell. + */ +export function getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, hasValidCharSize: boolean, actualCellWidth: number, actualCellHeight: number, isSelection?: boolean): [number, number] | undefined { + // Coordinates cannot be measured if there are no valid + if (!hasValidCharSize) { + return undefined; + } + + const coords = getCoordsRelativeToElement(event, element); + if (!coords) { + return undefined; + } + + coords[0] = Math.ceil((coords[0] + (isSelection ? actualCellWidth / 2 : 0)) / actualCellWidth); + coords[1] = Math.ceil(coords[1] / actualCellHeight); + + // Ensure coordinates are within the terminal viewport. Note that selections + // need an addition point of precision to cover the end point (as characters + // cover half of one char and half of the next). + coords[0] = Math.min(Math.max(coords[0], 1), colCount + (isSelection ? 1 : 0)); + coords[1] = Math.min(Math.max(coords[1], 1), rowCount); + + return coords; +} + +/** + * Gets coordinates within the terminal for a particular mouse event, wrapping + * them to the bounds of the terminal and adding 32 to both the x and y values + * as expected by xterm. + */ +export function getRawByteCoords(coords: [number, number] | undefined): { x: number, y: number } | undefined { + if (!coords) { + return undefined; + } + + // xterm sends raw bytes and starts at 32 (SP) for each. + return { x: coords[0] + 32, y: coords[1] + 32 }; +} diff --git a/src/browser/input/MouseHelper.test.ts b/src/browser/input/MouseHelper.test.ts deleted file mode 100644 index 5d4b567c..00000000 --- a/src/browser/input/MouseHelper.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import jsdom = require('jsdom'); -import { assert } from 'chai'; -import { MouseHelper } from 'browser/input/MouseHelper'; -import { MockCharSizeService } from 'browser/TestUtils.test'; - -const CHAR_WIDTH = 10; -const CHAR_HEIGHT = 20; - -describe('MouseHelper.getCoords', () => { - let document: Document; - let mouseHelper: MouseHelper; - - beforeEach(() => { - document = new jsdom.JSDOM('').window.document; - const mockRenderService = { - dimensions: { - actualCellWidth: CHAR_WIDTH, - actualCellHeight: CHAR_HEIGHT - } - }; - mouseHelper = new MouseHelper(mockRenderService as any, new MockCharSizeService(CHAR_WIDTH, CHAR_HEIGHT)); - }); - - it('should return the cell that was clicked', () => { - let coords: [number, number] | undefined; - coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH / 2, clientY: CHAR_HEIGHT / 2 }, document.createElement('div'), 10, 10); - assert.deepEqual(coords, [1, 1]); - coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT }, document.createElement('div'), 10, 10); - assert.deepEqual(coords, [1, 1]); - coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT + 1 }, document.createElement('div'), 10, 10); - assert.deepEqual(coords, [1, 2]); - coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH + 1, clientY: CHAR_HEIGHT }, document.createElement('div'), 10, 10); - assert.deepEqual(coords, [2, 1]); - }); - - it('should ensure the coordinates are returned within the terminal bounds', () => { - let coords: [number, number] | undefined; - coords = mouseHelper.getCoords({ clientX: -1, clientY: -1 }, document.createElement('div'), 10, 10); - assert.deepEqual(coords, [1, 1]); - // Event are double the cols/rows - coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH * 20, clientY: CHAR_HEIGHT * 20 }, document.createElement('div'), 10, 10); - assert.deepEqual(coords, [10, 10], 'coordinates should never come back as larger than the terminal'); - }); -}); diff --git a/src/browser/input/MouseHelper.ts b/src/browser/input/MouseHelper.ts deleted file mode 100644 index b99757db..00000000 --- a/src/browser/input/MouseHelper.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IMouseHelper } from 'browser/Types'; -import { RenderService } from 'browser/services/RenderService'; -import { ICharSizeService } from 'browser/services/Services'; - -export class MouseHelper implements IMouseHelper { - constructor( - private _renderService: RenderService, - private _charSizeService: ICharSizeService - ) { - } - - public static getCoordsRelativeToElement(event: {clientX: number, clientY: number}, element: HTMLElement): [number, number] { - const rect = element.getBoundingClientRect(); - return [event.clientX - rect.left, event.clientY - rect.top]; - } - - /** - * Gets coordinates within the terminal for a particular mouse event. The result - * is returned as an array in the form [x, y] instead of an object as it's a - * little faster and this function is used in some low level code. - * @param event The mouse event. - * @param element The terminal's container element. - * @param colCount The number of columns in the terminal. - * @param rowCount The number of rows n the terminal. - * @param isSelection Whether the request is for the selection or not. This will - * apply an offset to the x value such that the left half of the cell will - * select that cell and the right half will select the next cell. - */ - public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined { - // Coordinates cannot be measured if there are no valid - if (!this._charSizeService.hasValidSize) { - return undefined; - } - - const coords = MouseHelper.getCoordsRelativeToElement(event, element); - if (!coords) { - return undefined; - } - - coords[0] = Math.ceil((coords[0] + (isSelection ? this._renderService.dimensions.actualCellWidth / 2 : 0)) / this._renderService.dimensions.actualCellWidth); - coords[1] = Math.ceil(coords[1] / this._renderService.dimensions.actualCellHeight); - - // Ensure coordinates are within the terminal viewport. Note that selections - // need an addition point of precision to cover the end point (as characters - // cover half of one char and half of the next). - coords[0] = Math.min(Math.max(coords[0], 1), colCount + (isSelection ? 1 : 0)); - coords[1] = Math.min(Math.max(coords[1], 1), rowCount); - - return coords; - } - - /** - * Gets coordinates within the terminal for a particular mouse event, wrapping - * them to the bounds of the terminal and adding 32 to both the x and y values - * as expected by xterm. - * @param event The mouse event. - * @param element The terminal's container element. - * @param colCount The number of columns in the terminal. - * @param rowCount The number of rows in the terminal. - */ - public getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number | undefined, y: number | undefined } { - const coords = this.getCoords(event, element, colCount, rowCount); - - // xterm sends raw bytes and starts at 32 (SP) for each. - const x = coords ? coords[0] + 32 : undefined; - const y = coords ? coords[1] + 32 : undefined; - - return { x, y }; - } -} diff --git a/src/browser/services/MouseService.ts b/src/browser/services/MouseService.ts new file mode 100644 index 00000000..76968698 --- /dev/null +++ b/src/browser/services/MouseService.ts @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2017 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { ICharSizeService, IRenderService, IMouseService } from './Services'; +import { getCoords, getRawByteCoords } from 'browser/input/Mouse'; + +export class MouseService implements IMouseService { + constructor( + private readonly _renderService: IRenderService, + private readonly _charSizeService: ICharSizeService + ) { + } + + public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined { + return getCoords( + event, + element, + colCount, + rowCount, + this._charSizeService.hasValidSize, + this._renderService.dimensions.actualCellWidth, + this._renderService.dimensions.actualCellHeight, + isSelection + ); + } + + public getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number, y: number } | undefined { + const coords = this.getCoords(event, element, colCount, rowCount); + return getRawByteCoords(coords); + } +} diff --git a/src/browser/services/Services.d.ts b/src/browser/services/Services.d.ts index 1916572c..64539b95 100644 --- a/src/browser/services/Services.d.ts +++ b/src/browser/services/Services.d.ts @@ -17,6 +17,11 @@ export interface ICharSizeService { measure(): void; } +export interface IMouseService { + getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined; + getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number, y: number } | undefined; +} + export interface IRenderService { onDimensionsChange: IEvent; onRender: IEvent<{ start: number, end: number }>; diff --git a/src/handlers/AltClickHandler.ts b/src/handlers/AltClickHandler.ts index 506e6ee1..334b78d8 100644 --- a/src/handlers/AltClickHandler.ts +++ b/src/handlers/AltClickHandler.ts @@ -6,6 +6,7 @@ import { ITerminal } from '../Types'; import { IBufferLine, ICircularList } from 'common/Types'; import { C0 } from 'common/data/EscapeSequences'; +import { IMouseService } from 'browser/services/Services'; const enum Direction { UP = 'A', @@ -23,13 +24,14 @@ export class AltClickHandler { constructor( private _mouseEvent: MouseEvent, - private _terminal: ITerminal + private _terminal: ITerminal, + private readonly _mouseService: IMouseService ) { this._lines = this._terminal.buffer.lines; this._startCol = this._terminal.buffer.x; this._startRow = this._terminal.buffer.y; - const coordinates = this._terminal.mouseHelper.getCoords( + const coordinates = this._mouseService.getCoords( this._mouseEvent, this._terminal.element, this._terminal.cols, From 9980457eefb85b533296b2eafa060e840dbd079c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 15 Jun 2019 23:10:25 -0700 Subject: [PATCH 03/11] Remove terminal dep from SelectionModel --- src/SelectionManager.ts | 2 +- src/SelectionModel.test.ts | 27 +++------------------------ src/SelectionModel.ts | 4 +--- 3 files changed, 5 insertions(+), 28 deletions(-) diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index aa388d8a..08fcbaa0 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -126,7 +126,7 @@ export class SelectionManager implements ISelectionManager { this._initListeners(); this.enable(); - this._model = new SelectionModel(_terminal, bufferService); + this._model = new SelectionModel(bufferService); this._activeSelectionMode = SelectionMode.NORMAL; } diff --git a/src/SelectionModel.test.ts b/src/SelectionModel.test.ts index 605ba9e8..29d916da 100644 --- a/src/SelectionModel.test.ts +++ b/src/SelectionModel.test.ts @@ -4,36 +4,15 @@ */ import { assert } from 'chai'; -import { ITerminal } from './Types'; import { SelectionModel } from './SelectionModel'; -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, - bufferService: IBufferService - ) { - super(terminal, bufferService); - } -} +import { MockBufferService } from 'common/TestUtils.test'; describe('SelectionManager', () => { - let terminal: ITerminal; - let model: TestSelectionModel; + let model: SelectionModel; beforeEach(() => { - terminal = new MockTerminal(); const bufferService = new MockBufferService(80, 2); - terminal.buffers = new BufferSet( - new MockOptionsService({ scrollback: 10 }), - bufferService - ); - terminal.buffer = terminal.buffers.active; - - model = new TestSelectionModel(terminal, bufferService); + model = new SelectionModel(bufferService); }); describe('clearSelection', () => { diff --git a/src/SelectionModel.ts b/src/SelectionModel.ts index 44cd4cac..c8010c1c 100644 --- a/src/SelectionModel.ts +++ b/src/SelectionModel.ts @@ -3,7 +3,6 @@ * @license MIT */ -import { ITerminal } from './Types'; import { IBufferService } from 'common/services/Services'; /** @@ -34,7 +33,6 @@ export class SelectionModel { public selectionEnd: [number, number]; constructor( - private _terminal: ITerminal, private _bufferService: IBufferService ) { this.clearSelection(); @@ -71,7 +69,7 @@ export class SelectionModel { */ public get finalSelectionEnd(): [number, number] { if (this.isSelectAllActive) { - return [this._bufferService.cols, this._terminal.buffer.ybase + this._bufferService.rows - 1]; + return [this._bufferService.cols, this._bufferService.buffer.ybase + this._bufferService.rows - 1]; } if (!this.selectionStart) { From 6e90b7371b6a519dc3642a3c0e54608c2e03f662 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 15 Jun 2019 23:28:51 -0700 Subject: [PATCH 04/11] Move SelectionModel to browser, fix strict --- src/SelectionManager.test.ts | 13 +++------ src/SelectionManager.ts | 2 +- .../selection}/SelectionModel.test.ts | 14 +++++----- src/{ => browser/selection}/SelectionModel.ts | 27 +++++++++---------- src/common/TestUtils.test.ts | 16 +++++++---- 5 files changed, 36 insertions(+), 36 deletions(-) rename src/{ => browser/selection}/SelectionModel.test.ts (92%) rename src/{ => browser/selection}/SelectionModel.ts (89%) diff --git a/src/SelectionManager.test.ts b/src/SelectionManager.test.ts index 8499497a..0b82466d 100644 --- a/src/SelectionManager.test.ts +++ b/src/SelectionManager.test.ts @@ -5,13 +5,12 @@ import { assert } from 'chai'; import { SelectionManager, SelectionMode } from './SelectionManager'; -import { SelectionModel } from './SelectionModel'; -import { BufferSet } from 'common/buffer/BufferSet'; +import { SelectionModel } from 'browser/selection/SelectionModel'; import { ITerminal } from './Types'; import { IBuffer } from 'common/buffer/Types'; import { IBufferLine } from 'common/Types'; import { MockTerminal } from './TestUtils.test'; -import { MockOptionsService, MockBufferService } from 'common/TestUtils.test'; +import { MockBufferService } from 'common/TestUtils.test'; import { BufferLine } from 'common/buffer/BufferLine'; import { IBufferService } from 'common/services/Services'; import { MockCharSizeService, MockMouseService } from 'browser/TestUtils.test'; @@ -52,10 +51,7 @@ describe('SelectionManager', () => { beforeEach(() => { terminal = new TestMockTerminal(); bufferService = new MockBufferService(20, 20); - terminal.buffers = new BufferSet( - new MockOptionsService({ scrollback: 100 }), - bufferService - ); + terminal.buffers = bufferService.buffers; terminal.cols = 20; terminal.rows = 20; terminal.buffer = terminal.buffers.active; @@ -366,14 +362,13 @@ describe('SelectionManager', () => { describe('selectAll', () => { it('should select the entire buffer, beyond the viewport', () => { - buffer.lines.length = 5; + bufferService.resize(20, 5); buffer.lines.set(0, stringToRow('1')); buffer.lines.set(1, stringToRow('2')); buffer.lines.set(2, stringToRow('3')); buffer.lines.set(3, stringToRow('4')); buffer.lines.set(4, stringToRow('5')); selectionManager.selectAll(); - terminal.buffer.ybase = buffer.lines.length - bufferService.rows; assert.equal(selectionManager.selectionText, '1\n2\n3\n4\n5'); }); }); diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index 08fcbaa0..0b77d183 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -7,7 +7,7 @@ import { ITerminal, ISelectionManager, ISelectionRedrawRequestEvent } from './Ty import { IBuffer } from 'common/buffer/Types'; import { IBufferLine } from 'common/Types'; import * as Browser from 'common/Platform'; -import { SelectionModel } from './SelectionModel'; +import { SelectionModel } from 'browser/selection/SelectionModel'; import { AltClickHandler } from './handlers/AltClickHandler'; import { CellData } from 'common/buffer/CellData'; import { IDisposable } from 'xterm'; diff --git a/src/SelectionModel.test.ts b/src/browser/selection/SelectionModel.test.ts similarity index 92% rename from src/SelectionModel.test.ts rename to src/browser/selection/SelectionModel.test.ts index 29d916da..c15cdd29 100644 --- a/src/SelectionModel.test.ts +++ b/src/browser/selection/SelectionModel.test.ts @@ -7,7 +7,7 @@ import { assert } from 'chai'; import { SelectionModel } from './SelectionModel'; import { MockBufferService } from 'common/TestUtils.test'; -describe('SelectionManager', () => { +describe('SelectionModel', () => { let model: SelectionModel; beforeEach(() => { @@ -22,8 +22,8 @@ describe('SelectionManager', () => { assert.deepEqual(model.finalSelectionStart, [0, 0]); assert.deepEqual(model.finalSelectionEnd, [10, 2]); model.clearSelection(); - assert.deepEqual(model.finalSelectionStart, null); - assert.deepEqual(model.finalSelectionEnd, null); + assert.deepEqual(model.finalSelectionStart, undefined); + assert.deepEqual(model.finalSelectionEnd, undefined); }); }); @@ -61,8 +61,8 @@ describe('SelectionManager', () => { model.selectionStart = [0, 0]; model.selectionEnd = [10, 0]; model.onTrim(1); - assert.deepEqual(model.finalSelectionStart, null); - assert.deepEqual(model.finalSelectionEnd, null); + assert.deepEqual(model.finalSelectionStart, undefined); + assert.deepEqual(model.finalSelectionEnd, undefined); }); }); @@ -90,9 +90,9 @@ describe('SelectionManager', () => { assert.deepEqual(model.finalSelectionEnd, [80, 1]); }); it('should return null if there is no selection start', () => { - assert.equal(model.finalSelectionEnd, null); + assert.equal(model.finalSelectionEnd, undefined); model.selectionEnd = [1, 2]; - assert.equal(model.finalSelectionEnd, null); + assert.equal(model.finalSelectionEnd, undefined); }); it('should return selection start + length if there is no selection end', () => { model.selectionStart = [2, 2]; diff --git a/src/SelectionModel.ts b/src/browser/selection/SelectionModel.ts similarity index 89% rename from src/SelectionModel.ts rename to src/browser/selection/SelectionModel.ts index c8010c1c..1420444e 100644 --- a/src/SelectionModel.ts +++ b/src/browser/selection/SelectionModel.ts @@ -13,37 +13,36 @@ export class SelectionModel { /** * Whether select all is currently active. */ - public isSelectAllActive: boolean; - - /** - * The [x, y] position the selection starts at. - */ - public selectionStart: [number, number]; + public isSelectAllActive: boolean = false; /** * The minimal length of the selection from the start position. When double * clicking on a word, the word will be selected which makes the selection * start at the start of the word and makes this variable the length. */ - public selectionStartLength: number; + public selectionStartLength: number = 0; + + /** + * The [x, y] position the selection starts at. + */ + public selectionStart: [number, number] | undefined; /** * The [x, y] position the selection ends at. */ - public selectionEnd: [number, number]; + public selectionEnd: [number, number] | undefined; constructor( private _bufferService: IBufferService ) { - this.clearSelection(); } /** * Clears the current selection. */ public clearSelection(): void { - this.selectionStart = null; - this.selectionEnd = null; + this.selectionStart = undefined; + this.selectionEnd = undefined; this.isSelectAllActive = false; this.selectionStartLength = 0; } @@ -51,7 +50,7 @@ export class SelectionModel { /** * The final selection start, taking into consideration select all. */ - public get finalSelectionStart(): [number, number] { + public get finalSelectionStart(): [number, number] | undefined { if (this.isSelectAllActive) { return [0, 0]; } @@ -67,13 +66,13 @@ export class SelectionModel { * The final selection end, taking into consideration select all, double click * word selection and triple click line selection. */ - public get finalSelectionEnd(): [number, number] { + public get finalSelectionEnd(): [number, number] | undefined { if (this.isSelectAllActive) { return [this._bufferService.cols, this._bufferService.buffer.ybase + this._bufferService.rows - 1]; } if (!this.selectionStart) { - return null; + return undefined; } // Use the selection start + length if the end doesn't exist or they're reversed diff --git a/src/common/TestUtils.test.ts b/src/common/TestUtils.test.ts index 8e03dcad..c6402fb1 100644 --- a/src/common/TestUtils.test.ts +++ b/src/common/TestUtils.test.ts @@ -8,14 +8,18 @@ import { IEvent, EventEmitter } from 'common/EventEmitter'; import { clone } from 'common/Clone'; import { DEFAULT_OPTIONS } from 'common/services/OptionsService'; import { IBufferSet, IBuffer } from 'common/buffer/Types'; +import { BufferSet } from 'common/buffer/BufferSet'; export class MockBufferService implements IBufferService { - public buffer: IBuffer = {} as any; + public get buffer(): IBuffer { return this.buffers.active; } public buffers: IBufferSet = {} as any; constructor( public cols: number, - public rows: number - ) {} + public rows: number, + optionsService: IOptionsService = new MockOptionsService() + ) { + this.buffers = new BufferSet(optionsService, this); + } resize(cols: number, rows: number): void { this.cols = cols; this.rows = rows; @@ -26,8 +30,10 @@ export class MockBufferService implements IBufferService { export class MockOptionsService implements IOptionsService { options: ITerminalOptions = clone(DEFAULT_OPTIONS); onOptionChange: IEvent = new EventEmitter().event; - constructor(testOptions: IPartialTerminalOptions) { - Object.keys(testOptions).forEach(key => this.options[key] = (testOptions)[key]); + constructor(testOptions?: IPartialTerminalOptions) { + if (testOptions) { + Object.keys(testOptions).forEach(key => this.options[key] = (testOptions)[key]); + } } setOption(key: string, value: T): void { throw new Error('Method not implemented.'); From 308cf8247a694e4201b6c8d6b534f5d45145af1b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 15 Jun 2019 23:40:31 -0700 Subject: [PATCH 05/11] Remove terminal dep in char joiner registry --- src/renderer/CharacterJoinerRegistry.test.ts | 15 ++++----------- src/renderer/CharacterJoinerRegistry.ts | 13 ++++++------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/renderer/CharacterJoinerRegistry.test.ts b/src/renderer/CharacterJoinerRegistry.test.ts index a73672a2..acc87054 100644 --- a/src/renderer/CharacterJoinerRegistry.test.ts +++ b/src/renderer/CharacterJoinerRegistry.test.ts @@ -4,24 +4,19 @@ */ import { assert } from 'chai'; - -import { MockTerminal, MockBuffer } from '../TestUtils.test'; -import { CircularList } from 'common/CircularList'; - import { ICharacterJoinerRegistry } from './Types'; import { CharacterJoinerRegistry } from './CharacterJoinerRegistry'; import { BufferLine } from 'common/buffer/BufferLine'; import { IBufferLine } from 'common/Types'; import { CellData } from 'common/buffer/CellData'; +import { MockBufferService } from 'common/TestUtils.test'; describe('CharacterJoinerRegistry', () => { let registry: ICharacterJoinerRegistry; beforeEach(() => { - const terminal = new MockTerminal(); - terminal.cols = 16; - terminal.buffer = new MockBuffer(); - const lines = new CircularList(7); + const bufferService = new MockBufferService(16, 10); + const lines = bufferService.buffer.lines; lines.set(0, lineData([['a -> b -> c -> d']])); lines.set(1, lineData([['a -> b => c -> d']])); lines.set(2, lineData([['a -> b -', 0xFFFFFFFF], ['> c -> d', 0]])); @@ -44,9 +39,7 @@ describe('CharacterJoinerRegistry', () => { for (let i = 0; i < sub.length; ++i) line6.setCell(i + oldSize, sub.loadCell(i, new CellData())); lines.set(6, line6); - (terminal.buffer).setLines(lines); - terminal.buffer.ydisp = 0; - registry = new CharacterJoinerRegistry(terminal); + registry = new CharacterJoinerRegistry(bufferService); }); it('has no joiners upon creation', () => { diff --git a/src/renderer/CharacterJoinerRegistry.ts b/src/renderer/CharacterJoinerRegistry.ts index 80fff2b1..d5f19fdd 100644 --- a/src/renderer/CharacterJoinerRegistry.ts +++ b/src/renderer/CharacterJoinerRegistry.ts @@ -3,12 +3,12 @@ * @license MIT */ -import { ITerminal } from '../Types'; import { IBufferLine, ICellData, CharData } from 'common/Types'; import { ICharacterJoinerRegistry, ICharacterJoiner } from './Types'; import { AttributeData } from 'common/buffer/AttributeData'; import { WHITESPACE_CELL_CHAR, Content } from 'common/buffer/Constants'; import { CellData } from 'common/buffer/CellData'; +import { IBufferService } from 'common/services/Services'; export class JoinedCellData extends AttributeData implements ICellData { private _width: number; @@ -61,8 +61,7 @@ export class CharacterJoinerRegistry implements ICharacterJoinerRegistry { private _nextCharacterJoinerId: number = 0; private _workCell: CellData = new CellData(); - constructor(private _terminal: ITerminal) { - } + constructor(private _bufferService: IBufferService) { } public registerCharacterJoiner(handler: (text: string) => [number, number][]): number { const joiner: ICharacterJoiner = { @@ -90,7 +89,7 @@ export class CharacterJoinerRegistry implements ICharacterJoinerRegistry { return []; } - const line = this._terminal.buffer.lines.get(row); + const line = this._bufferService.buffer.lines.get(row); if (line.length === 0) { return []; } @@ -144,7 +143,7 @@ export class CharacterJoinerRegistry implements ICharacterJoinerRegistry { } // Process any trailing ranges. - if (this._terminal.cols - rangeStartColumn > 1) { + if (this._bufferService.cols - rangeStartColumn > 1) { const joinedRanges = this._getJoinedRanges( lineStr, rangeStartStringIndex, @@ -204,7 +203,7 @@ export class CharacterJoinerRegistry implements ICharacterJoinerRegistry { return; } - for (let x = startCol; x < this._terminal.cols; x++) { + for (let x = startCol; x < this._bufferService.cols; x++) { const width = line.getWidth(x); const length = line.getString(x).length || WHITESPACE_CELL_CHAR.length; @@ -252,7 +251,7 @@ export class CharacterJoinerRegistry implements ICharacterJoinerRegistry { // If there is still a range left at the end, it must extend all the way to // the end of the line. if (currentRange) { - currentRange[1] = this._terminal.cols; + currentRange[1] = this._bufferService.cols; } } From e35d911fd18686311e201e7dc17ca279853029f2 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 15 Jun 2019 23:45:03 -0700 Subject: [PATCH 06/11] Move char joiner registry to browser layer --- .../renderer/CharacterJoinerRegistry.test.ts | 6 +++--- .../renderer/CharacterJoinerRegistry.ts | 4 ++-- src/browser/renderer/Types.d.ts | 11 +++++++++++ src/renderer/Renderer.ts | 6 +++--- src/renderer/TextRenderLayer.ts | 5 ++--- src/renderer/Types.d.ts | 13 +------------ 6 files changed, 22 insertions(+), 23 deletions(-) rename src/{ => browser}/renderer/CharacterJoinerRegistry.test.ts (98%) rename src/{ => browser}/renderer/CharacterJoinerRegistry.ts (98%) diff --git a/src/renderer/CharacterJoinerRegistry.test.ts b/src/browser/renderer/CharacterJoinerRegistry.test.ts similarity index 98% rename from src/renderer/CharacterJoinerRegistry.test.ts rename to src/browser/renderer/CharacterJoinerRegistry.test.ts index acc87054..bca12d6b 100644 --- a/src/renderer/CharacterJoinerRegistry.test.ts +++ b/src/browser/renderer/CharacterJoinerRegistry.test.ts @@ -4,8 +4,8 @@ */ import { assert } from 'chai'; -import { ICharacterJoinerRegistry } from './Types'; -import { CharacterJoinerRegistry } from './CharacterJoinerRegistry'; +import { ICharacterJoinerRegistry } from 'browser/renderer/Types'; +import { CharacterJoinerRegistry } from 'browser/renderer/CharacterJoinerRegistry'; import { BufferLine } from 'common/buffer/BufferLine'; import { IBufferLine } from 'common/Types'; import { CellData } from 'common/buffer/CellData'; @@ -26,7 +26,7 @@ describe('CharacterJoinerRegistry', () => { lines.set(5, lineData([['a', 0x11111111], [' -> b -> c -> '], ['d', 0x22222222]])); const line6 = lineData([['wi']]); line6.resize(line6.length + 1, CellData.fromCharData([0, '¥', 2, '¥'.charCodeAt(0)])); - line6.resize(line6.length + 1, CellData.fromCharData([0, '', 0, null])); + line6.resize(line6.length + 1, CellData.fromCharData([0, '', 0, 0])); let sub = lineData([['deemo']]); let oldSize = line6.length; line6.resize(oldSize + sub.length, CellData.fromCharData([0, '', 0, 0])); diff --git a/src/renderer/CharacterJoinerRegistry.ts b/src/browser/renderer/CharacterJoinerRegistry.ts similarity index 98% rename from src/renderer/CharacterJoinerRegistry.ts rename to src/browser/renderer/CharacterJoinerRegistry.ts index d5f19fdd..a5abe80f 100644 --- a/src/renderer/CharacterJoinerRegistry.ts +++ b/src/browser/renderer/CharacterJoinerRegistry.ts @@ -4,7 +4,7 @@ */ import { IBufferLine, ICellData, CharData } from 'common/Types'; -import { ICharacterJoinerRegistry, ICharacterJoiner } from './Types'; +import { ICharacterJoinerRegistry, ICharacterJoiner } from 'browser/renderer/Types'; import { AttributeData } from 'common/buffer/AttributeData'; import { WHITESPACE_CELL_CHAR, Content } from 'common/buffer/Constants'; import { CellData } from 'common/buffer/CellData'; @@ -90,7 +90,7 @@ export class CharacterJoinerRegistry implements ICharacterJoinerRegistry { } const line = this._bufferService.buffer.lines.get(row); - if (line.length === 0) { + if (!line || line.length === 0) { return []; } diff --git a/src/browser/renderer/Types.d.ts b/src/browser/renderer/Types.d.ts index e580ff8d..df8f0031 100644 --- a/src/browser/renderer/Types.d.ts +++ b/src/browser/renderer/Types.d.ts @@ -45,3 +45,14 @@ export interface IRenderer extends IDisposable { registerCharacterJoiner(handler: CharacterJoinerHandler): number; deregisterCharacterJoiner(joinerId: number): boolean; } + +export interface ICharacterJoiner { + id: number; + handler: CharacterJoinerHandler; +} + +export interface ICharacterJoinerRegistry { + registerCharacterJoiner(handler: (text: string) => [number, number][]): number; + deregisterCharacterJoiner(joinerId: number): boolean; + getJoinedCharacters(row: number): [number, number][]; +} diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index 56e12b57..dfdf11bb 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -6,11 +6,11 @@ import { TextRenderLayer } from './TextRenderLayer'; import { SelectionRenderLayer } from './SelectionRenderLayer'; import { CursorRenderLayer } from './CursorRenderLayer'; -import { IRenderLayer, ICharacterJoinerRegistry } from './Types'; -import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; +import { IRenderLayer } from './Types'; +import { IRenderer, IRenderDimensions, CharacterJoinerHandler, ICharacterJoinerRegistry } from 'browser/renderer/Types'; import { ITerminal } from '../Types'; import { LinkRenderLayer } from './LinkRenderLayer'; -import { CharacterJoinerRegistry } from '../renderer/CharacterJoinerRegistry'; +import { CharacterJoinerRegistry } from '../browser/renderer/CharacterJoinerRegistry'; import { Disposable } from 'common/Lifecycle'; import { IColorSet } from 'browser/Types'; import { ICharSizeService } from 'browser/services/Services'; diff --git a/src/renderer/TextRenderLayer.ts b/src/renderer/TextRenderLayer.ts index db3bec19..9db35b6a 100644 --- a/src/renderer/TextRenderLayer.ts +++ b/src/renderer/TextRenderLayer.ts @@ -3,15 +3,14 @@ * @license MIT */ -import { ICharacterJoinerRegistry } from './Types'; -import { IRenderDimensions } from 'browser/renderer/Types'; +import { ICharacterJoinerRegistry, IRenderDimensions } from 'browser/renderer/Types'; import { ITerminal } from '../Types'; import { CharData, ICellData } from 'common/Types'; import { GridCache } from './GridCache'; import { BaseRenderLayer } from './BaseRenderLayer'; import { AttributeData } from 'common/buffer/AttributeData'; import { NULL_CELL_CODE, Content } from 'common/buffer/Constants'; -import { JoinedCellData } from './CharacterJoinerRegistry'; +import { JoinedCellData } from '../browser/renderer/CharacterJoinerRegistry'; import { IColorSet } from 'browser/Types'; import { CellData } from 'common/buffer/CellData'; diff --git a/src/renderer/Types.d.ts b/src/renderer/Types.d.ts index 5f7d67a8..1546248a 100644 --- a/src/renderer/Types.d.ts +++ b/src/renderer/Types.d.ts @@ -6,7 +6,7 @@ import { ITerminal } from '../Types'; import { IDisposable } from 'xterm'; import { IColorSet } from 'browser/Types'; -import { IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; +import { IRenderDimensions, CharacterJoinerHandler, ICharacterJoiner } from 'browser/renderer/Types'; export interface IRenderLayer extends IDisposable { /** @@ -65,14 +65,3 @@ export interface IRenderLayer extends IDisposable { */ reset(terminal: ITerminal): void; } - -export interface ICharacterJoiner { - id: number; - handler: CharacterJoinerHandler; -} - -export interface ICharacterJoinerRegistry { - registerCharacterJoiner(handler: (text: string) => [number, number][]): number; - deregisterCharacterJoiner(joinerId: number): boolean; - getJoinedCharacters(row: number): [number, number][]; -} From b5093e0c29e4b00c144f92fdea2158b34162fde1 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 15 Jun 2019 23:47:35 -0700 Subject: [PATCH 07/11] Move GridCache to browser --- src/{ => browser}/renderer/GridCache.test.ts | 2 +- src/{ => browser}/renderer/GridCache.ts | 6 +++--- src/renderer/TextRenderLayer.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename src/{ => browser}/renderer/GridCache.test.ts (96%) rename src/{ => browser}/renderer/GridCache.ts (84%) diff --git a/src/renderer/GridCache.test.ts b/src/browser/renderer/GridCache.test.ts similarity index 96% rename from src/renderer/GridCache.test.ts rename to src/browser/renderer/GridCache.test.ts index c4b1c220..30d22e81 100644 --- a/src/renderer/GridCache.test.ts +++ b/src/browser/renderer/GridCache.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { GridCache } from './GridCache'; +import { GridCache } from 'browser/renderer/GridCache'; describe('GridCache', () => { let grid: GridCache; diff --git a/src/renderer/GridCache.ts b/src/browser/renderer/GridCache.ts similarity index 84% rename from src/renderer/GridCache.ts rename to src/browser/renderer/GridCache.ts index dd188c62..b48798d2 100644 --- a/src/renderer/GridCache.ts +++ b/src/browser/renderer/GridCache.ts @@ -4,7 +4,7 @@ */ export class GridCache { - public cache: T[][]; + public cache: (T | undefined)[][]; public constructor() { this.cache = []; @@ -16,7 +16,7 @@ export class GridCache { this.cache.push([]); } for (let y = this.cache[x].length; y < height; y++) { - this.cache[x].push(null); + this.cache[x].push(undefined); } this.cache[x].length = height; } @@ -26,7 +26,7 @@ export class GridCache { public clear(): void { for (let x = 0; x < this.cache.length; x++) { for (let y = 0; y < this.cache[x].length; y++) { - this.cache[x][y] = null; + this.cache[x][y] = undefined; } } } diff --git a/src/renderer/TextRenderLayer.ts b/src/renderer/TextRenderLayer.ts index 9db35b6a..1858f005 100644 --- a/src/renderer/TextRenderLayer.ts +++ b/src/renderer/TextRenderLayer.ts @@ -6,7 +6,7 @@ import { ICharacterJoinerRegistry, IRenderDimensions } from 'browser/renderer/Types'; import { ITerminal } from '../Types'; import { CharData, ICellData } from 'common/Types'; -import { GridCache } from './GridCache'; +import { GridCache } from 'browser/renderer/GridCache'; import { BaseRenderLayer } from './BaseRenderLayer'; import { AttributeData } from 'common/buffer/AttributeData'; import { NULL_CELL_CODE, Content } from 'common/buffer/Constants'; From c0e27b98e84c231a5fedbaa631f5cfcfdcfc9040 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 15 Jun 2019 23:51:36 -0700 Subject: [PATCH 08/11] Move LRUMap to browser --- .../renderer/atlas/LRUMap.test.ts | 2 +- src/{ => browser}/renderer/atlas/LRUMap.ts | 18 +++++++++--------- src/renderer/atlas/DynamicCharAtlas.ts | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) rename src/{ => browser}/renderer/atlas/LRUMap.test.ts (96%) rename src/{ => browser}/renderer/atlas/LRUMap.ts (91%) diff --git a/src/renderer/atlas/LRUMap.test.ts b/src/browser/renderer/atlas/LRUMap.test.ts similarity index 96% rename from src/renderer/atlas/LRUMap.test.ts rename to src/browser/renderer/atlas/LRUMap.test.ts index b24ad2af..792f85a7 100644 --- a/src/renderer/atlas/LRUMap.test.ts +++ b/src/browser/renderer/atlas/LRUMap.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { LRUMap } from './LRUMap'; +import { LRUMap } from 'browser/renderer/atlas/LRUMap'; describe('LRUMap', () => { it('can be used to store and retrieve values', () => { diff --git a/src/renderer/atlas/LRUMap.ts b/src/browser/renderer/atlas/LRUMap.ts similarity index 91% rename from src/renderer/atlas/LRUMap.ts rename to src/browser/renderer/atlas/LRUMap.ts index 0db5621f..f70962fe 100644 --- a/src/renderer/atlas/LRUMap.ts +++ b/src/browser/renderer/atlas/LRUMap.ts @@ -4,16 +4,16 @@ */ interface ILinkedListNode { - prev: ILinkedListNode; - next: ILinkedListNode; - key: number; - value: T; + prev: ILinkedListNode | null; + next: ILinkedListNode | null; + key: number | null; + value: T | null; } export class LRUMap { private _map: { [key: number]: ILinkedListNode } = {}; - private _head: ILinkedListNode = null; - private _tail: ILinkedListNode = null; + private _head: ILinkedListNode | null = null; + private _tail: ILinkedListNode | null = null; private _nodePool: ILinkedListNode[] = []; public size: number = 0; @@ -106,9 +106,9 @@ export class LRUMap { node.value = value; } else if (this.size >= this.capacity) { // we're out of space: recycle the head node, move it to the tail - node = this._head; + node = this._head!; this._unlinkNode(node); - delete this._map[node.key]; + delete this._map[node.key!]; node.key = key; node.value = value; this._map[key] = node; @@ -117,7 +117,7 @@ export class LRUMap { const nodePool = this._nodePool; if (nodePool.length > 0) { // use a preallocated node if we can - node = nodePool.pop(); + node = nodePool.pop()!; node.key = key; node.value = value; } else { diff --git a/src/renderer/atlas/DynamicCharAtlas.ts b/src/renderer/atlas/DynamicCharAtlas.ts index fdae4e80..24f31b35 100644 --- a/src/renderer/atlas/DynamicCharAtlas.ts +++ b/src/renderer/atlas/DynamicCharAtlas.ts @@ -7,7 +7,7 @@ import { IGlyphIdentifier, ICharAtlasConfig } from './Types'; import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from './Constants'; import { BaseCharAtlas } from './BaseCharAtlas'; import { DEFAULT_ANSI_COLORS } from 'browser/ColorManager'; -import { LRUMap } from './LRUMap'; +import { LRUMap } from '../../browser/renderer/atlas/LRUMap'; import { isFirefox, isSafari } from 'common/Platform'; import { IColor } from 'browser/Types'; From c4f903e2833eded67bb57554d94da91a7d103e22 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 15 Jun 2019 23:53:45 -0700 Subject: [PATCH 09/11] Move atlas/Constants to browser --- src/{ => browser}/renderer/atlas/Constants.ts | 0 src/renderer/BaseRenderLayer.ts | 2 +- src/renderer/LinkRenderLayer.ts | 2 +- src/renderer/atlas/DynamicCharAtlas.ts | 4 ++-- src/renderer/dom/DomRenderer.ts | 2 +- src/renderer/dom/DomRendererRowFactory.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename src/{ => browser}/renderer/atlas/Constants.ts (100%) diff --git a/src/renderer/atlas/Constants.ts b/src/browser/renderer/atlas/Constants.ts similarity index 100% rename from src/renderer/atlas/Constants.ts rename to src/browser/renderer/atlas/Constants.ts diff --git a/src/renderer/BaseRenderLayer.ts b/src/renderer/BaseRenderLayer.ts index 5101fdd5..b47434e2 100644 --- a/src/renderer/BaseRenderLayer.ts +++ b/src/renderer/BaseRenderLayer.ts @@ -9,7 +9,7 @@ import { ITerminal } from '../Types'; import { ICellData } from 'common/Types'; import { DEFAULT_COLOR, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE } from 'common/buffer/Constants'; import { IGlyphIdentifier } from './atlas/Types'; -import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from './atlas/Constants'; +import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { BaseCharAtlas } from './atlas/BaseCharAtlas'; import { acquireCharAtlas } from './atlas/CharAtlasCache'; import { AttributeData } from 'common/buffer/AttributeData'; diff --git a/src/renderer/LinkRenderLayer.ts b/src/renderer/LinkRenderLayer.ts index 99eff4a2..8c6976d7 100644 --- a/src/renderer/LinkRenderLayer.ts +++ b/src/renderer/LinkRenderLayer.ts @@ -6,7 +6,7 @@ import { ILinkifierEvent, ITerminal, ILinkifierAccessor } from '../Types'; import { IRenderDimensions } from 'browser/renderer/Types'; import { BaseRenderLayer } from './BaseRenderLayer'; -import { INVERTED_DEFAULT_COLOR } from './atlas/Constants'; +import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { is256Color } from './atlas/CharAtlasUtils'; import { IColorSet } from 'browser/Types'; diff --git a/src/renderer/atlas/DynamicCharAtlas.ts b/src/renderer/atlas/DynamicCharAtlas.ts index 24f31b35..6e669d91 100644 --- a/src/renderer/atlas/DynamicCharAtlas.ts +++ b/src/renderer/atlas/DynamicCharAtlas.ts @@ -4,10 +4,10 @@ */ import { IGlyphIdentifier, ICharAtlasConfig } from './Types'; -import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from './Constants'; +import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { BaseCharAtlas } from './BaseCharAtlas'; import { DEFAULT_ANSI_COLORS } from 'browser/ColorManager'; -import { LRUMap } from '../../browser/renderer/atlas/LRUMap'; +import { LRUMap } from 'browser/renderer/atlas/LRUMap'; import { isFirefox, isSafari } from 'common/Platform'; import { IColor } from 'browser/Types'; diff --git a/src/renderer/dom/DomRenderer.ts b/src/renderer/dom/DomRenderer.ts index fe6ab4d1..eb49b665 100644 --- a/src/renderer/dom/DomRenderer.ts +++ b/src/renderer/dom/DomRenderer.ts @@ -6,7 +6,7 @@ import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; import { ILinkifierEvent, ITerminal } from '../../Types'; import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from './DomRendererRowFactory'; -import { INVERTED_DEFAULT_COLOR } from '../atlas/Constants'; +import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { Disposable } from 'common/Lifecycle'; import { IColorSet } from 'browser/Types'; import { ICharSizeService } from 'browser/services/Services'; diff --git a/src/renderer/dom/DomRendererRowFactory.ts b/src/renderer/dom/DomRendererRowFactory.ts index 687d207d..8a4d71c1 100644 --- a/src/renderer/dom/DomRendererRowFactory.ts +++ b/src/renderer/dom/DomRendererRowFactory.ts @@ -5,7 +5,7 @@ import { ITerminalOptions } from '../../Types'; import { IBufferLine } from 'common/Types'; -import { INVERTED_DEFAULT_COLOR } from '../atlas/Constants'; +import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { AttributeData } from 'common/buffer/AttributeData'; import { NULL_CELL_CODE, WHITESPACE_CELL_CHAR } from 'common/buffer/Constants'; import { CellData } from 'common/buffer/CellData'; From a6f49318104e9fda2a47704a57ede1dae69ac2ca Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 15 Jun 2019 23:59:32 -0700 Subject: [PATCH 10/11] Move DomRendererRowFactory to browser --- src/Terminal.ts | 2 +- .../renderer/dom/DomRendererRowFactory.test.ts | 12 ++++-------- .../renderer/dom/DomRendererRowFactory.ts | 8 ++++---- src/renderer/dom/DomRenderer.ts | 8 +++++--- 4 files changed, 14 insertions(+), 16 deletions(-) rename src/{ => browser}/renderer/dom/DomRendererRowFactory.test.ts (96%) rename src/{ => browser}/renderer/dom/DomRendererRowFactory.ts (95%) diff --git a/src/Terminal.ts b/src/Terminal.ts index 59346505..b28cfcfa 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -691,7 +691,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp private _createRenderer(): IRenderer { switch (this.options.rendererType) { case 'canvas': return new Renderer(this, this._colorManager.colors, this._charSizeService); break; - case 'dom': return new DomRenderer(this, this._colorManager.colors, this._charSizeService); break; + case 'dom': return new DomRenderer(this, this._colorManager.colors, this._charSizeService, this.optionsService); break; default: throw new Error(`Unrecognized rendererType "${this.options.rendererType}"`); } } diff --git a/src/renderer/dom/DomRendererRowFactory.test.ts b/src/browser/renderer/dom/DomRendererRowFactory.test.ts similarity index 96% rename from src/renderer/dom/DomRendererRowFactory.test.ts rename to src/browser/renderer/dom/DomRendererRowFactory.test.ts index 6ad9641c..b76d644d 100644 --- a/src/renderer/dom/DomRendererRowFactory.test.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.test.ts @@ -5,25 +5,21 @@ import jsdom = require('jsdom'); import { assert } from 'chai'; -import { DomRendererRowFactory } from './DomRendererRowFactory'; +import { DomRendererRowFactory } from 'browser/renderer/dom/DomRendererRowFactory'; import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, DEFAULT_ATTR, FgFlags, BgFlags, Attributes } from 'common/buffer/Constants'; import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; -import { ITerminalOptions } from '../../Types'; import { IBufferLine } from 'common/Types'; import { CellData } from 'common/buffer/CellData'; +import { MockOptionsService } from 'common/TestUtils.test'; describe('DomRendererRowFactory', () => { let dom: jsdom.JSDOM; - const options: ITerminalOptions = {}; let rowFactory: DomRendererRowFactory; let lineData: IBufferLine; beforeEach(() => { dom = new jsdom.JSDOM(''); - - options.drawBoldTextInBrightColors = true; - - rowFactory = new DomRendererRowFactory(options, dom.window.document); + rowFactory = new DomRendererRowFactory(dom.window.document, new MockOptionsService({ drawBoldTextInBrightColors: true })); lineData = createEmptyLineData(2); }); @@ -38,7 +34,7 @@ describe('DomRendererRowFactory', () => { it('should set correct attributes for double width characters', () => { lineData.setCell(0, CellData.fromCharData([DEFAULT_ATTR, '語', 2, '語'.charCodeAt(0)])); // There should be no element for the following "empty" cell - lineData.setCell(1, CellData.fromCharData([DEFAULT_ATTR, '', 0, undefined])); + lineData.setCell(1, CellData.fromCharData([DEFAULT_ATTR, '', 0, 0])); const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20); assert.equal(getFragmentHtml(fragment), '' diff --git a/src/renderer/dom/DomRendererRowFactory.ts b/src/browser/renderer/dom/DomRendererRowFactory.ts similarity index 95% rename from src/renderer/dom/DomRendererRowFactory.ts rename to src/browser/renderer/dom/DomRendererRowFactory.ts index 8a4d71c1..316645f8 100644 --- a/src/renderer/dom/DomRendererRowFactory.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.ts @@ -3,12 +3,12 @@ * @license MIT */ -import { ITerminalOptions } from '../../Types'; import { IBufferLine } from 'common/Types'; import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { AttributeData } from 'common/buffer/AttributeData'; import { NULL_CELL_CODE, WHITESPACE_CELL_CHAR } from 'common/buffer/Constants'; import { CellData } from 'common/buffer/CellData'; +import { ITerminalOptions, IOptionsService } from 'common/services/Services'; export const BOLD_CLASS = 'xterm-bold'; export const DIM_CLASS = 'xterm-dim'; @@ -24,8 +24,8 @@ export class DomRendererRowFactory { private _workCell: CellData = new CellData(); constructor( - private _terminalOptions: ITerminalOptions, - private _document: Document + private _document: Document, + private _optionsService: IOptionsService ) { } @@ -106,7 +106,7 @@ export class DomRendererRowFactory { charElement.setAttribute('style', style); } else if (this._workCell.isFgPalette()) { let fg = this._workCell.getFgColor(); - if (this._workCell.isBold() && fg < 8 && !swapColor && this._terminalOptions.drawBoldTextInBrightColors) { + if (this._workCell.isBold() && fg < 8 && !swapColor && this._optionsService.options.drawBoldTextInBrightColors) { fg += 8; } charElement.classList.add(`xterm-${swapColor ? 'b' : 'f'}g-${fg}`); diff --git a/src/renderer/dom/DomRenderer.ts b/src/renderer/dom/DomRenderer.ts index eb49b665..a6b6e868 100644 --- a/src/renderer/dom/DomRenderer.ts +++ b/src/renderer/dom/DomRenderer.ts @@ -5,11 +5,12 @@ import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; import { ILinkifierEvent, ITerminal } from '../../Types'; -import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from './DomRendererRowFactory'; +import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from 'browser/renderer/dom/DomRendererRowFactory'; import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { Disposable } from 'common/Lifecycle'; import { IColorSet } from 'browser/Types'; import { ICharSizeService } from 'browser/services/Services'; +import { IOptionsService } from 'common/services/Services'; const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-'; const ROW_CONTAINER_CLASS = 'xterm-rows'; @@ -43,7 +44,8 @@ export class DomRenderer extends Disposable implements IRenderer { constructor( private _terminal: ITerminal, private _colors: IColorSet, - private _charSizeService: ICharSizeService + private _charSizeService: ICharSizeService, + private _optionsService: IOptionsService ) { super(); @@ -73,7 +75,7 @@ export class DomRenderer extends Disposable implements IRenderer { this._updateDimensions(); this._injectCss(); - this._rowFactory = new DomRendererRowFactory(_terminal.options, document); + this._rowFactory = new DomRendererRowFactory(document, this._optionsService); this._terminal.element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass); this._terminal.screenElement.appendChild(this._rowContainer); From de86d140c5743957493871fe8429a05933b4d93f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 16 Jun 2019 00:02:10 -0700 Subject: [PATCH 11/11] Fix absolute imports --- src/renderer/Renderer.ts | 2 +- src/renderer/TextRenderLayer.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index dfdf11bb..a6e8fca7 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -10,7 +10,7 @@ import { IRenderLayer } from './Types'; import { IRenderer, IRenderDimensions, CharacterJoinerHandler, ICharacterJoinerRegistry } from 'browser/renderer/Types'; import { ITerminal } from '../Types'; import { LinkRenderLayer } from './LinkRenderLayer'; -import { CharacterJoinerRegistry } from '../browser/renderer/CharacterJoinerRegistry'; +import { CharacterJoinerRegistry } from 'browser/renderer/CharacterJoinerRegistry'; import { Disposable } from 'common/Lifecycle'; import { IColorSet } from 'browser/Types'; import { ICharSizeService } from 'browser/services/Services'; diff --git a/src/renderer/TextRenderLayer.ts b/src/renderer/TextRenderLayer.ts index 1858f005..96678a5d 100644 --- a/src/renderer/TextRenderLayer.ts +++ b/src/renderer/TextRenderLayer.ts @@ -10,7 +10,7 @@ import { GridCache } from 'browser/renderer/GridCache'; import { BaseRenderLayer } from './BaseRenderLayer'; import { AttributeData } from 'common/buffer/AttributeData'; import { NULL_CELL_CODE, Content } from 'common/buffer/Constants'; -import { JoinedCellData } from '../browser/renderer/CharacterJoinerRegistry'; +import { JoinedCellData } from 'browser/renderer/CharacterJoinerRegistry'; import { IColorSet } from 'browser/Types'; import { CellData } from 'common/buffer/CellData';