Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handle selection when resizing #4837

Merged
merged 4 commits into from Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion addons/addon-canvas/src/BaseRenderLayer.ts
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion addons/addon-webgl/src/WebglRenderer.ts
Expand Up @@ -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();
}

Expand Down
2 changes: 1 addition & 1 deletion src/browser/Terminal.ts
Expand Up @@ -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);
}

/**
Expand Down
29 changes: 20 additions & 9 deletions src/browser/renderer/dom/DomRenderer.ts
Expand Up @@ -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';
Expand All @@ -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
Expand All @@ -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<IRequestRedrawEvent>()).event;

constructor(
private readonly _terminal: ITerminal,
private readonly _document: Document,
private readonly _element: HTMLElement,
private readonly _screenElement: HTMLElement,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}

Expand Down
8 changes: 5 additions & 3 deletions src/browser/renderer/shared/SelectionRenderModel.ts
Expand Up @@ -3,6 +3,7 @@
* @license MIT
*/

import { ITerminal } from 'browser/Types';
import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
import { Terminal } from '@xterm/xterm';

Expand Down Expand Up @@ -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
Expand All @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions src/browser/renderer/shared/Types.d.ts
Expand Up @@ -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';

Expand Down Expand Up @@ -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;
}