From c3d35fcea9c38bfdff99dab2df6cc049e505c97d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 1 Jun 2026 20:27:15 -0700 Subject: [PATCH] fix(InputHandler): clear wrap below scroll margins after column ops scrollLeft, scrollRight, insertColumns, and deleteColumns set isWrapped=false on every line inside the scroll margins but left the first line below scrollBottom unchanged. A soft wrap spanning the bottom margin and the next row could leave a stale isWrapped flag on the line below, breaking wrapped string translation. Clear isWrapped on the buffer line below the bottom margin after each of these column operations. Co-authored-by: Cursor --- src/common/InputHandler.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index 94a6401d3..ade09ff51 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -1202,6 +1202,21 @@ export class InputHandler extends Disposable implements IInputHandler { } } + /** + * Scroll-margin column operations clear isWrapped on lines inside the margins. + * Also clear the line below the bottom margin when it still continues a wrap chain. + */ + private _clearWrapBelowScrollMargins(): void { + const rowBelowMargin = this._activeBuffer.scrollBottom + 1; + if (rowBelowMargin >= this._bufferService.rows) { + return; + } + const lineBelow = this._activeBuffer.lines.get(this._activeBuffer.ybase + rowBelowMargin); + if (lineBelow) { + lineBelow.isWrapped = false; + } + } + /** * CSI Ps J Erase in Display (ED). * Ps = 0 -> Erase Below (default). @@ -1521,6 +1536,7 @@ export class InputHandler extends Disposable implements IInputHandler { line.deleteCells(0, param, this._activeBuffer.getNullCell(this._eraseAttrData())); line.isWrapped = false; } + this._clearWrapBelowScrollMargins(); this._dirtyRowTracker.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); return true; } @@ -1554,6 +1570,7 @@ export class InputHandler extends Disposable implements IInputHandler { line.insertCells(0, param, this._activeBuffer.getNullCell(this._eraseAttrData())); line.isWrapped = false; } + this._clearWrapBelowScrollMargins(); this._dirtyRowTracker.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); return true; } @@ -1577,6 +1594,7 @@ export class InputHandler extends Disposable implements IInputHandler { line.insertCells(this._activeBuffer.x, param, this._activeBuffer.getNullCell(this._eraseAttrData())); line.isWrapped = false; } + this._clearWrapBelowScrollMargins(); this._dirtyRowTracker.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); return true; } @@ -1600,6 +1618,7 @@ export class InputHandler extends Disposable implements IInputHandler { line.deleteCells(this._activeBuffer.x, param, this._activeBuffer.getNullCell(this._eraseAttrData())); line.isWrapped = false; } + this._clearWrapBelowScrollMargins(); this._dirtyRowTracker.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); return true; }