From 3a5def98e574909ad34385c0bcaa3112a6807e0e Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 25 Apr 2020 06:56:00 -0700 Subject: [PATCH 1/2] Correct selection types being optional --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 4 ++-- addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts | 2 +- addons/xterm-addon-webgl/src/renderLayer/Types.ts | 2 +- src/browser/renderer/BaseRenderLayer.ts | 2 +- src/browser/renderer/Renderer.ts | 2 +- src/browser/renderer/SelectionRenderLayer.ts | 4 ++-- src/browser/renderer/Types.d.ts | 4 ++-- src/browser/renderer/dom/DomRenderer.ts | 2 +- src/browser/services/RenderService.ts | 2 +- src/browser/services/Services.ts | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 8d52a35e..4ea4589a 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -170,7 +170,7 @@ export class WebglRenderer extends Disposable implements IRenderer { this._renderLayers.forEach(l => l.onFocus(this._terminal)); } - public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void { + public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void { this._renderLayers.forEach(l => l.onSelectionChanged(this._terminal, start, end, columnSelectMode)); this._updateSelectionModel(start, end); @@ -292,7 +292,7 @@ export class WebglRenderer extends Disposable implements IRenderer { this._rectangleRenderer.updateBackgrounds(this._model); } - private _updateSelectionModel(start: [number, number], end: [number, number]): void { + private _updateSelectionModel(start: [number, number] | undefined, end: [number, number] | undefined): void { const terminal = this._terminal; // Selection does not exist diff --git a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts index 93f84492..da3b4d41 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts @@ -58,7 +58,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { public onFocus(terminal: Terminal): void {} public onCursorMove(terminal: Terminal): void {} public onGridChanged(terminal: Terminal, startRow: number, endRow: number): void {} - public onSelectionChanged(terminal: Terminal, start: [number, number], end: [number, number], columnSelectMode: boolean = false): void {} + public onSelectionChanged(terminal: Terminal, start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void {} public setColors(terminal: Terminal, colorSet: IColorSet): void { this._refreshCharAtlas(terminal, colorSet); diff --git a/addons/xterm-addon-webgl/src/renderLayer/Types.ts b/addons/xterm-addon-webgl/src/renderLayer/Types.ts index 148ea469..70acff34 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/Types.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/Types.ts @@ -42,7 +42,7 @@ export interface IRenderLayer extends IDisposable { /** * Calls when the selection changes. */ - onSelectionChanged(terminal: Terminal, start: [number, number], end: [number, number], columnSelectMode: boolean): void; + onSelectionChanged(terminal: Terminal, start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void; /** * Registers a handler to join characters to render as a group diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index 595aa1a5..837f18e4 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -77,7 +77,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { public onFocus(): void {} public onCursorMove(): void {} public onGridChanged(startRow: number, endRow: number): void {} - public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean = false): void {} + public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void {} public setColors(colorSet: IColorSet): void { this._refreshCharAtlas(colorSet); diff --git a/src/browser/renderer/Renderer.ts b/src/browser/renderer/Renderer.ts index 0856553f..5142e4cb 100644 --- a/src/browser/renderer/Renderer.ts +++ b/src/browser/renderer/Renderer.ts @@ -119,7 +119,7 @@ export class Renderer extends Disposable implements IRenderer { this._runOperation(l => l.onFocus()); } - public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean = false): void { + public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void { this._runOperation(l => l.onSelectionChanged(start, end, columnSelectMode)); } diff --git a/src/browser/renderer/SelectionRenderLayer.ts b/src/browser/renderer/SelectionRenderLayer.ts index 257944fc..5689ce93 100644 --- a/src/browser/renderer/SelectionRenderLayer.ts +++ b/src/browser/renderer/SelectionRenderLayer.ts @@ -52,7 +52,7 @@ export class SelectionRenderLayer extends BaseRenderLayer { } } - public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void { + public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void { // Selection has not changed if (!this._didStateChange(start, end, columnSelectMode, this._bufferService.buffer.ydisp)) { return; @@ -110,7 +110,7 @@ export class SelectionRenderLayer extends BaseRenderLayer { this._state.ydisp = this._bufferService.buffer.ydisp; } - private _didStateChange(start: [number, number], end: [number, number], columnSelectMode: boolean, ydisp: number): boolean { + private _didStateChange(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean, ydisp: number): boolean { return !this._areCoordinatesEqual(start, this._state.start) || !this._areCoordinatesEqual(end, this._state.end) || columnSelectMode !== this._state.columnSelectMode || diff --git a/src/browser/renderer/Types.d.ts b/src/browser/renderer/Types.d.ts index 02c62ab2..cab14b88 100644 --- a/src/browser/renderer/Types.d.ts +++ b/src/browser/renderer/Types.d.ts @@ -49,7 +49,7 @@ export interface IRenderer extends IDisposable { onCharSizeChanged(): void; onBlur(): void; onFocus(): void; - onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void; + onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void; onCursorMove(): void; onOptionsChanged(): void; clear(): void; @@ -104,7 +104,7 @@ export interface IRenderLayer extends IDisposable { /** * Calls when the selection changes. */ - onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void; + onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void; /** * Registers a handler to join characters to render as a group diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index 1303ec1b..ff955140 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -273,7 +273,7 @@ export class DomRenderer extends Disposable implements IRenderer { this._rowContainer.classList.add(FOCUS_CLASS); } - public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void { + public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void { // Remove all selections while (this._selectionContainer.children.length) { this._selectionContainer.removeChild(this._selectionContainer.children[0]); diff --git a/src/browser/services/RenderService.ts b/src/browser/services/RenderService.ts index d7ff5814..109db2e6 100644 --- a/src/browser/services/RenderService.ts +++ b/src/browser/services/RenderService.ts @@ -163,7 +163,7 @@ export class RenderService extends Disposable implements IRenderService { this._renderer.onFocus(); } - public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void { + public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void { this._renderer.onSelectionChanged(start, end, columnSelectMode); } diff --git a/src/browser/services/Services.ts b/src/browser/services/Services.ts index 3754e6fe..7a559dab 100644 --- a/src/browser/services/Services.ts +++ b/src/browser/services/Services.ts @@ -63,7 +63,7 @@ export interface IRenderService extends IDisposable { onCharSizeChanged(): void; onBlur(): void; onFocus(): void; - onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void; + onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void; onCursorMove(): void; clear(): void; registerCharacterJoiner(handler: CharacterJoinerHandler): number; From c185529ad5e1fe6cade88ca98159d882c992f97d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 25 Apr 2020 07:11:43 -0700 Subject: [PATCH 2/2] Make sure selection gets redrawn when switching renderers Fixes #2555 --- src/browser/RenderDebouncer.ts | 12 ++++++------ src/browser/services/RenderService.ts | 28 ++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/browser/RenderDebouncer.ts b/src/browser/RenderDebouncer.ts index 27c866df..814afcef 100644 --- a/src/browser/RenderDebouncer.ts +++ b/src/browser/RenderDebouncer.ts @@ -49,15 +49,15 @@ export class RenderDebouncer implements IDisposable { } // Clamp values - this._rowStart = Math.max(this._rowStart, 0); - this._rowEnd = Math.min(this._rowEnd, this._rowCount - 1); + const start = Math.max(this._rowStart, 0); + const end = Math.min(this._rowEnd, this._rowCount - 1); - // Run render callback - this._renderCallback(this._rowStart, this._rowEnd); - - // Reset debouncer + // Reset debouncer (this happens before render callback as the render could trigger it again) this._rowStart = undefined; this._rowEnd = undefined; this._animationFrame = undefined; + + // Run render callback + this._renderCallback(start, end); } } diff --git a/src/browser/services/RenderService.ts b/src/browser/services/RenderService.ts index 109db2e6..7c8a13cc 100644 --- a/src/browser/services/RenderService.ts +++ b/src/browser/services/RenderService.ts @@ -13,6 +13,12 @@ import { IColorSet } from 'browser/Types'; import { IOptionsService } from 'common/services/Services'; import { ICharSizeService, IRenderService } from 'browser/services/Services'; +interface ISelectionState { + start: [number, number] | undefined; + end: [number, number] | undefined; + columnSelectMode: boolean; +} + export class RenderService extends Disposable implements IRenderService { public serviceBrand: any; @@ -22,8 +28,14 @@ export class RenderService extends Disposable implements IRenderService { private _isPaused: boolean = false; private _needsFullRefresh: boolean = false; private _isNextRenderRedrawOnly: boolean = true; + private _needsSelectionRefresh: boolean = false; private _canvasWidth: number = 0; private _canvasHeight: number = 0; + private _selectionState: ISelectionState = { + start: undefined, + end: undefined, + columnSelectMode: false + }; private _onDimensionsChange = new EventEmitter(); public get onDimensionsChange(): IEvent { return this._onDimensionsChange.event; } @@ -89,6 +101,14 @@ export class RenderService extends Disposable implements IRenderService { private _renderRows(start: number, end: number): void { this._renderer.renderRows(start, end); + + // Update selection if needed + if (this._needsSelectionRefresh) { + this._renderer.onSelectionChanged(this._selectionState.start, this._selectionState.end, this._selectionState.columnSelectMode); + this._needsSelectionRefresh = false; + } + + // Fire render event only if it was not a redraw if (!this._isNextRenderRedrawOnly) { this._onRender.fire({ start, end }); } @@ -124,7 +144,10 @@ export class RenderService extends Disposable implements IRenderService { this._renderer.dispose(); this._renderer = renderer; this._renderer.onRequestRedraw(e => this.refreshRows(e.start, e.end, true)); - this.refreshRows(0, this._rowCount - 1); + + // Force a refresh + this._needsSelectionRefresh = true; + this._fullRefresh(); } private _fullRefresh(): void { @@ -164,6 +187,9 @@ export class RenderService extends Disposable implements IRenderService { } public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void { + this._selectionState.start = start; + this._selectionState.end = end; + this._selectionState.columnSelectMode = columnSelectMode; this._renderer.onSelectionChanged(start, end, columnSelectMode); }