fix(pi-tui): use contentCursorRow for render movement baseline instead of cursorRow
PR #3744 fixed autocomplete ghost lines by introducing a local contentCursorRow initialized from this.cursorRow, but this.cursorRow tracks the content end (last line), not where the cursor actually ended up after rendering. This caused computeLineDiff to compute wrong movement deltas, making content clear and jump on every keystroke. Fix: add an instance field contentCursorRow that stores finalCursorRow after content rendering but before positionHardwareCursor moves the cursor for IME. This correctly separates three cursor concepts: - cursorRow: logical content end (viewport calculation) - contentCursorRow: post-render cursor position (movement baseline) - hardwareCursorRow: actual terminal cursor (may differ due to IME) Closes #3764
This commit is contained in:
parent
0d69b9c57d
commit
561d73d3aa
1 changed files with 9 additions and 5 deletions
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue