diff --git a/addons/addon-canvas/src/BaseRenderLayer.ts b/addons/addon-canvas/src/BaseRenderLayer.ts index 0e85901a..c2ec1c36 100644 --- a/addons/addon-canvas/src/BaseRenderLayer.ts +++ b/addons/addon-canvas/src/BaseRenderLayer.ts @@ -91,7 +91,7 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer public handleGridChanged(startRow: number, endRow: number): void {} public handleSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void { - this._selectionModel.update(this._terminal, start, end, columnSelectMode); + this._selectionModel.update((this._terminal as any)._core, start, end, columnSelectMode); } protected _setTransparency(alpha: boolean): void { diff --git a/addons/addon-webgl/src/WebglRenderer.ts b/addons/addon-webgl/src/WebglRenderer.ts index 9b7d56df..d50d7301 100644 --- a/addons/addon-webgl/src/WebglRenderer.ts +++ b/addons/addon-webgl/src/WebglRenderer.ts @@ -219,7 +219,7 @@ export class WebglRenderer extends Disposable implements IRenderer { for (const l of this._renderLayers) { l.handleSelectionChanged(this._terminal, start, end, columnSelectMode); } - this._model.selection.update(this._terminal, start, end, columnSelectMode); + this._model.selection.update(this._core, start, end, columnSelectMode); this._requestRedrawViewport(); } diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 0413b906..fad2d80b 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -575,7 +575,7 @@ export class Terminal extends CoreTerminal implements ITerminal { } private _createRenderer(): IRenderer { - return this._instantiationService.createInstance(DomRenderer, this._document!, this.element!, this.screenElement!, this._viewportElement!, this._helperContainer!, this.linkifier2); + return this._instantiationService.createInstance(DomRenderer, this, this._document!, this.element!, this.screenElement!, this._viewportElement!, this._helperContainer!, this.linkifier2); } /** diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index 2e9f3701..1549b130 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -7,9 +7,10 @@ import { DomRendererRowFactory, RowCss } from 'browser/renderer/dom/DomRendererR import { WidthCache } from 'browser/renderer/dom/WidthCache'; import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/shared/Constants'; import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils'; -import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/shared/Types'; +import { createSelectionRenderModel } from 'browser/renderer/shared/SelectionRenderModel'; +import { IRenderDimensions, IRenderer, IRequestRedrawEvent, ISelectionRenderModel } from 'browser/renderer/shared/Types'; import { ICharSizeService, ICoreBrowserService, IThemeService } from 'browser/services/Services'; -import { ILinkifier2, ILinkifierEvent, ReadonlyColorSet } from 'browser/Types'; +import { ILinkifier2, ILinkifierEvent, ITerminal, ReadonlyColorSet } from 'browser/Types'; import { color } from 'common/Color'; import { EventEmitter } from 'common/EventEmitter'; import { Disposable, toDisposable } from 'common/Lifecycle'; @@ -25,7 +26,6 @@ const SELECTION_CLASS = 'xterm-selection'; let nextTerminalId = 1; - /** * A fallback renderer for when canvas is slow. This is not meant to be * particularly fast or feature complete, more just stable and usable for when @@ -41,12 +41,14 @@ export class DomRenderer extends Disposable implements IRenderer { private _rowElements: HTMLElement[] = []; private _selectionContainer: HTMLElement; private _widthCache: WidthCache; + private _selectionRenderModel: ISelectionRenderModel = createSelectionRenderModel(); public dimensions: IRenderDimensions; public readonly onRequestRedraw = this.register(new EventEmitter()).event; constructor( + private readonly _terminal: ITerminal, private readonly _document: Document, private readonly _element: HTMLElement, private readonly _screenElement: HTMLElement, @@ -291,6 +293,7 @@ export class DomRenderer extends Disposable implements IRenderer { public handleResize(cols: number, rows: number): void { this._refreshRowElements(cols, rows); this._updateDimensions(); + this.handleSelectionChanged(this._selectionRenderModel.selectionStart, this._selectionRenderModel.selectionEnd, this._selectionRenderModel.columnSelectMode); } public handleCharSizeChanged(): void { @@ -320,11 +323,13 @@ export class DomRenderer extends Disposable implements IRenderer { return; } + this._selectionRenderModel.update(this._terminal, start, end, columnSelectMode); + // Translate from buffer position to viewport position - const viewportStartRow = start[1] - this._bufferService.buffer.ydisp; - const viewportEndRow = end[1] - this._bufferService.buffer.ydisp; - const viewportCappedStartRow = Math.max(viewportStartRow, 0); - const viewportCappedEndRow = Math.min(viewportEndRow, this._bufferService.rows - 1); + const viewportStartRow = this._selectionRenderModel.viewportStartRow; + const viewportEndRow = this._selectionRenderModel.viewportEndRow; + const viewportCappedStartRow = this._selectionRenderModel.viewportCappedStartRow; + const viewportCappedEndRow = this._selectionRenderModel.viewportCappedEndRow; // No need to draw the selection if (viewportCappedStartRow >= this._bufferService.rows || viewportCappedEndRow < 0) { @@ -365,10 +370,16 @@ export class DomRenderer extends Disposable implements IRenderer { */ private _createSelectionElement(row: number, colStart: number, colEnd: number, rowCount: number = 1): HTMLElement { const element = this._document.createElement('div'); + const left = colStart * this.dimensions.css.cell.width; + let width = this.dimensions.css.cell.width * (colEnd - colStart); + if (left + width > this.dimensions.css.canvas.width) { + width = this.dimensions.css.canvas.width - left; + } + element.style.height = `${rowCount * this.dimensions.css.cell.height}px`; element.style.top = `${row * this.dimensions.css.cell.height}px`; - element.style.left = `${colStart * this.dimensions.css.cell.width}px`; - element.style.width = `${this.dimensions.css.cell.width * (colEnd - colStart)}px`; + element.style.left = `${left}px`; + element.style.width = `${width}px`; return element; } diff --git a/src/browser/renderer/shared/SelectionRenderModel.ts b/src/browser/renderer/shared/SelectionRenderModel.ts index 1568ad8b..d3b7a99c 100644 --- a/src/browser/renderer/shared/SelectionRenderModel.ts +++ b/src/browser/renderer/shared/SelectionRenderModel.ts @@ -3,6 +3,7 @@ * @license MIT */ +import { ITerminal } from 'browser/Types'; import { ISelectionRenderModel } from 'browser/renderer/shared/Types'; import { Terminal } from '@xterm/xterm'; @@ -35,7 +36,7 @@ class SelectionRenderModel implements ISelectionRenderModel { this.selectionEnd = undefined; } - public update(terminal: Terminal, start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void { + public update(terminal: ITerminal, start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void { this.selectionStart = start; this.selectionEnd = end; // Selection does not exist @@ -45,8 +46,9 @@ class SelectionRenderModel implements ISelectionRenderModel { } // Translate from buffer position to viewport position - const viewportStartRow = start[1] - terminal.buffer.active.viewportY; - const viewportEndRow = end[1] - terminal.buffer.active.viewportY; + const viewportY = terminal.buffers.active.ydisp; + const viewportStartRow = start[1] - viewportY; + const viewportEndRow = end[1] - viewportY; const viewportCappedStartRow = Math.max(viewportStartRow, 0); const viewportCappedEndRow = Math.min(viewportEndRow, terminal.rows - 1); diff --git a/src/browser/renderer/shared/Types.d.ts b/src/browser/renderer/shared/Types.d.ts index 029ac88a..c0d5e9d6 100644 --- a/src/browser/renderer/shared/Types.d.ts +++ b/src/browser/renderer/shared/Types.d.ts @@ -4,7 +4,7 @@ */ import { FontWeight, Terminal } from '@xterm/xterm'; -import { IColorSet } from 'browser/Types'; +import { IColorSet, ITerminal } from 'browser/Types'; import { IDisposable } from 'common/Types'; import { IEvent } from 'common/EventEmitter'; @@ -168,6 +168,6 @@ export interface ISelectionRenderModel { readonly selectionStart: [number, number] | undefined; readonly selectionEnd: [number, number] | undefined; clear(): void; - update(terminal: Terminal, start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode?: boolean): void; + update(terminal: ITerminal, start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode?: boolean): void; isCellSelected(terminal: Terminal, x: number, y: number): boolean; }