-
Notifications
You must be signed in to change notification settings - Fork 379
fix(pi-tui): avoid spurious viewport scroll jumps from idle cursor repositioning #1310
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
base: main
Are you sure you want to change the base?
Changes from all commits
8d4dd8b
b3593a8
0644fc1
fef1667
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -319,6 +319,7 @@ export class TUI extends Container { | |
| private static readonly MIN_RENDER_INTERVAL_MS = 16; | ||
| private cursorRow = 0; // Logical cursor row (end of rendered content) | ||
| private hardwareCursorRow = 0; // Actual terminal cursor row (may differ due to IME positioning) | ||
| private hardwareCursorCol = 0; // Actual terminal cursor column (tracked to avoid spurious ANSI writes) | ||
| private showHardwareCursor = process.env['PI_HARDWARE_CURSOR'] === "1"; | ||
| private clearOnShrink = process.env['PI_CLEAR_ON_SHRINK'] === "1"; // Clear empty rows when content shrinks (default: off) | ||
| private maxLinesRendered = 0; // Track terminal's working area (max lines ever rendered) | ||
|
|
@@ -726,6 +727,7 @@ export class TUI extends Container { | |
| this.previousHeight = -1; // -1 triggers heightChanged, forcing a full clear | ||
| this.cursorRow = 0; | ||
| this.hardwareCursorRow = 0; | ||
| this.hardwareCursorCol = 0; | ||
| this.maxLinesRendered = 0; | ||
| this.previousViewportTop = 0; | ||
| if (this.renderTimer) { | ||
|
|
@@ -1653,6 +1655,13 @@ export class TUI extends Container { | |
| const targetRow = Math.max(0, Math.min(cursorPos.row, totalLines - 1)); | ||
| const targetCol = Math.max(0, cursorPos.col); | ||
|
|
||
| // Skip repositioning when cursor hasn't moved and hardware cursor is hidden. | ||
| // This avoids spurious ANSI sequences that can cause viewport scroll jumps | ||
| // on terminals with Kitty keyboard protocol support. | ||
| if (!this.showHardwareCursor && targetRow === this.hardwareCursorRow && targetCol === this.hardwareCursorCol) { | ||
| return; | ||
|
Comment on lines
+1661
to
+1662
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
After a frame rewrites terminal lines, Useful? React with 👍 / 👎. |
||
| } | ||
|
|
||
| // Move cursor from current position to target | ||
| const rowDelta = targetRow - this.hardwareCursorRow; | ||
| let buffer = ""; | ||
|
|
@@ -1669,6 +1678,7 @@ export class TUI extends Container { | |
| } | ||
|
|
||
| this.hardwareCursorRow = targetRow; | ||
| this.hardwareCursorCol = targetCol; | ||
| if (this.showHardwareCursor) { | ||
| this.terminal.showCursor(); | ||
| } else { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
completedthrough tool-argument validationIn real tool calls,
preflightToolCallvalidates the provider arguments with AJV againsttool.parametersand never runsTodoListInputSchema.safeParse, so this preprocess does not normalize the raw"completed"value before validation. The JSON schema advertised from this schema still describes the inner enum (pending/in_progress/done), so a model call using the compatibility spelling is rejected beforesetTodoscan map it todone; the new test bypasses that path by invokingresolveExecutiondirectly. Please make the JSON schema acceptcompletedas well, or run the Zod parse/normalization before AJV rejects the call.Useful? React with 👍 / 👎.