diff --git a/packages/pi-tui/src/tui.ts b/packages/pi-tui/src/tui.ts index 3408016a0..b0240aad3 100644 --- a/packages/pi-tui/src/tui.ts +++ b/packages/pi-tui/src/tui.ts @@ -239,6 +239,7 @@ export class TUI extends Container { public onDebug?: () => void; private renderRequested = false; private cursorRow = 0; // Logical cursor row (end of rendered content) + private contentCursorRow = 0; // Cursor row after content rendering, before IME repositioning private hardwareCursorRow = 0; // Actual terminal cursor row (may differ due to IME positioning) private inputBuffer = ""; // Buffer for parsing terminal responses private cellSizeQueryPending = false; @@ -498,6 +499,7 @@ export class TUI extends Container { this.previousWidth = -1; // -1 triggers widthChanged, forcing a full clear this.previousHeight = -1; // -1 triggers heightChanged, forcing a full clear this.cursorRow = 0; + this.contentCursorRow = 0; this.hardwareCursorRow = 0; this.maxLinesRendered = 0; this.previousViewportTop = 0; @@ -616,10 +618,9 @@ export class TUI extends Container { const height = this.terminal.rows; let viewportTop = Math.max(0, this.maxLinesRendered - height); let prevViewportTop = this.previousViewportTop; - let contentCursorRow = this.cursorRow; - let hardwareCursorRow = this.hardwareCursorRow; + let hardwareCursorRow = this.contentCursorRow; const computeLineDiff = (targetRow: number): number => { - const currentScreenRow = contentCursorRow - prevViewportTop; + const currentScreenRow = hardwareCursorRow - prevViewportTop; const targetScreenRow = targetRow - viewportTop; return targetScreenRow - currentScreenRow; }; @@ -664,6 +665,7 @@ export class TUI extends Container { buffer += "\x1b[?2026l"; // End synchronized output this.terminal.write(buffer); this.cursorRow = Math.max(0, newLines.length - 1); + this.contentCursorRow = this.cursorRow; this.hardwareCursorRow = this.cursorRow; // Reset max lines when clearing, otherwise track growth if (clear) { @@ -771,6 +773,7 @@ export class TUI extends Container { buffer += "\x1b[?2026l"; this.terminal.write(buffer); this.cursorRow = targetRow; + this.contentCursorRow = targetRow; this.hardwareCursorRow = targetRow; } this.positionHardwareCursor(cursorPos, newLines.length); @@ -806,7 +809,6 @@ export class TUI extends Container { buffer += "\r\n".repeat(scroll); prevViewportTop += scroll; viewportTop += scroll; - contentCursorRow = moveTargetRow; hardwareCursorRow = moveTargetRow; } @@ -889,8 +891,10 @@ export class TUI extends Container { // Track cursor position for next render // cursorRow tracks end of content (for viewport calculation) - // hardwareCursorRow tracks actual terminal cursor position (for movement) + // contentCursorRow tracks cursor after content rendering (before IME repositioning) + // hardwareCursorRow tracks actual terminal cursor position (may differ due to IME) this.cursorRow = Math.max(0, newLines.length - 1); + this.contentCursorRow = finalCursorRow; this.hardwareCursorRow = finalCursorRow; // Track terminal's working area (grows but doesn't shrink unless cleared) this.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);