From 9a7517d3ebb0c0692a45820a8ab183c4b0025445 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 19 Oct 2025 01:15:30 -0700 Subject: [PATCH] Clear selection on vertical resize Fixes #5300 --- src/browser/services/SelectionService.ts | 8 ++++++++ src/common/TestUtils.test.ts | 4 ++-- src/common/services/BufferService.ts | 10 +++++----- src/common/services/Services.ts | 9 ++++++++- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/browser/services/SelectionService.ts b/src/browser/services/SelectionService.ts index 9da8ab5d..39d666de 100644 --- a/src/browser/services/SelectionService.ts +++ b/src/browser/services/SelectionService.ts @@ -152,6 +152,14 @@ export class SelectionService extends Disposable implements ISelectionService { this._register(toDisposable(() => { this._removeMouseDownListeners(); })); + + // Clear selection when resizing vertically. This experience could be improved, this is the + // simple option to fix the buggy behavior. https://github.com/xtermjs/xterm.js/issues/5300 + this._register(this._bufferService.onResize(e => { + if (e.rowsChanged) { + this.clearSelection(); + } + })); } public reset(): void { diff --git a/src/common/TestUtils.test.ts b/src/common/TestUtils.test.ts index 8e3d02f9..e12311ff 100644 --- a/src/common/TestUtils.test.ts +++ b/src/common/TestUtils.test.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { IBufferService, ICoreService, ILogService, IOptionsService, ITerminalOptions, ICoreMouseService, ICharsetService, UnicodeCharProperties, UnicodeCharWidth, IUnicodeService, IUnicodeVersionProvider, LogLevelEnum, IDecorationService, IInternalDecoration, IOscLinkService } from 'common/services/Services'; +import { IBufferService, ICoreService, ILogService, IOptionsService, ITerminalOptions, ICoreMouseService, ICharsetService, UnicodeCharProperties, UnicodeCharWidth, IUnicodeService, IUnicodeVersionProvider, LogLevelEnum, IDecorationService, IInternalDecoration, IOscLinkService, type IBufferResizeEvent } from 'common/services/Services'; import { UnicodeService } from 'common/services/UnicodeService'; import { clone } from 'common/Clone'; import { DEFAULT_OPTIONS } from 'common/services/OptionsService'; @@ -18,7 +18,7 @@ export class MockBufferService implements IBufferService { public serviceBrand: any; public get buffer(): IBuffer { return this.buffers.active; } public buffers: IBufferSet = {} as any; - public onResize: Event<{ cols: number, rows: number }> = new Emitter<{ cols: number, rows: number }>().event; + public onResize: Event = new Emitter().event; public onScroll: Event = new Emitter().event; private readonly _onScroll = new Emitter(); public isUserScrolling: boolean = false; diff --git a/src/common/services/BufferService.ts b/src/common/services/BufferService.ts index d8d8d6b6..4cba3c15 100644 --- a/src/common/services/BufferService.ts +++ b/src/common/services/BufferService.ts @@ -7,7 +7,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IAttributeData, IBufferLine } from 'common/Types'; import { BufferSet } from 'common/buffer/BufferSet'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; -import { IBufferService, IOptionsService } from 'common/services/Services'; +import { IBufferService, IOptionsService, type IBufferResizeEvent } from 'common/services/Services'; import { Emitter } from 'vs/base/common/event'; export const MINIMUM_COLS = 2; // Less than 2 can mess with wide chars @@ -22,7 +22,7 @@ export class BufferService extends Disposable implements IBufferService { /** Whether the user is scrolling (locks the scroll position) */ public isUserScrolling: boolean = false; - private readonly _onResize = this._register(new Emitter<{ cols: number, rows: number }>()); + private readonly _onResize = this._register(new Emitter()); public readonly onResize = this._onResize.event; private readonly _onScroll = this._register(new Emitter()); public readonly onScroll = this._onScroll.event; @@ -43,12 +43,12 @@ export class BufferService extends Disposable implements IBufferService { } public resize(cols: number, rows: number): void { + const colsChanged = this.cols !== cols; + const rowsChanged = this.rows !== rows; this.cols = cols; this.rows = rows; this.buffers.resize(cols, rows); - // TODO: This doesn't fire when scrollback changes - add a resize event to BufferSet and forward - // event - this._onResize.fire({ cols, rows }); + this._onResize.fire({ cols, rows, colsChanged, rowsChanged }); } public reset(): void { diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index d47c3bbc..a2847f1b 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -18,7 +18,7 @@ export interface IBufferService { readonly buffer: IBuffer; readonly buffers: IBufferSet; isUserScrolling: boolean; - onResize: Event<{ cols: number, rows: number }>; + onResize: Event; onScroll: Event; scroll(eraseAttr: IAttributeData, isWrapped?: boolean): void; scrollLines(disp: number, suppressScrollEvent?: boolean): void; @@ -26,6 +26,13 @@ export interface IBufferService { reset(): void; } +export interface IBufferResizeEvent { + cols: number; + rows: number; + colsChanged: boolean; + rowsChanged: boolean; +} + export const ICoreMouseService = createDecorator('CoreMouseService'); export interface ICoreMouseService { serviceBrand: undefined;