Merge pull request #3744 from mastertyko/fix/3721-tui-autocomplete-ghost-lines
fix(pi-tui): clear autocomplete rows from content bottom
This commit is contained in:
commit
f9a6cac958
2 changed files with 88 additions and 1 deletions
|
|
@ -616,9 +616,10 @@ 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;
|
||||
const computeLineDiff = (targetRow: number): number => {
|
||||
const currentScreenRow = hardwareCursorRow - prevViewportTop;
|
||||
const currentScreenRow = contentCursorRow - prevViewportTop;
|
||||
const targetScreenRow = targetRow - viewportTop;
|
||||
return targetScreenRow - currentScreenRow;
|
||||
};
|
||||
|
|
@ -805,6 +806,7 @@ export class TUI extends Container {
|
|||
buffer += "\r\n".repeat(scroll);
|
||||
prevViewportTop += scroll;
|
||||
viewportTop += scroll;
|
||||
contentCursorRow = moveTargetRow;
|
||||
hardwareCursorRow = moveTargetRow;
|
||||
}
|
||||
|
||||
|
|
|
|||
85
src/tests/tui-autocomplete-ghost-lines.test.ts
Normal file
85
src/tests/tui-autocomplete-ghost-lines.test.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { CURSOR_MARKER, TUI, type Component, type Terminal } from "@gsd/pi-tui";
|
||||
|
||||
class MockTTYTerminal implements Terminal {
|
||||
public writtenData: string[] = [];
|
||||
|
||||
readonly isTTY = true;
|
||||
|
||||
start(_onInput: (data: string) => void, _onResize: () => void): void {}
|
||||
stop(): void {}
|
||||
async drainInput(_maxMs?: number, _idleMs?: number): Promise<void> {}
|
||||
|
||||
write(data: string): void {
|
||||
this.writtenData.push(data);
|
||||
}
|
||||
|
||||
get columns(): number {
|
||||
return 80;
|
||||
}
|
||||
|
||||
get rows(): number {
|
||||
return 24;
|
||||
}
|
||||
|
||||
get kittyProtocolActive(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
moveBy(_lines: number): void {}
|
||||
hideCursor(): void {}
|
||||
showCursor(): void {}
|
||||
clearLine(): void {}
|
||||
clearFromCursor(): void {}
|
||||
clearScreen(): void {}
|
||||
setTitle(_title: string): void {}
|
||||
}
|
||||
|
||||
class DynamicLinesComponent implements Component {
|
||||
public lines: string[];
|
||||
|
||||
constructor(lines: string[]) {
|
||||
this.lines = lines;
|
||||
}
|
||||
|
||||
render(_width: number): string[] {
|
||||
return this.lines;
|
||||
}
|
||||
|
||||
invalidate(): void {}
|
||||
}
|
||||
|
||||
describe("TUI autocomplete shrink clearing (#3721)", () => {
|
||||
it("clears deleted autocomplete rows relative to the content bottom, not the IME cursor row", () => {
|
||||
const terminal = new MockTTYTerminal();
|
||||
const tui = new TUI(terminal, false);
|
||||
const component = new DynamicLinesComponent([
|
||||
"top border",
|
||||
`prompt${CURSOR_MARKER}`,
|
||||
"editor body",
|
||||
"autocomplete row 1",
|
||||
"autocomplete row 2",
|
||||
"autocomplete row 3",
|
||||
]);
|
||||
|
||||
tui.addChild(component);
|
||||
(tui as any).doRender();
|
||||
|
||||
terminal.writtenData = [];
|
||||
component.lines = [
|
||||
"top border",
|
||||
`prompt${CURSOR_MARKER}`,
|
||||
"editor body",
|
||||
"autocomplete row 1",
|
||||
];
|
||||
|
||||
(tui as any).doRender();
|
||||
|
||||
assert.ok(terminal.writtenData.length >= 1, "shrink render should write a differential buffer");
|
||||
assert.ok(
|
||||
terminal.writtenData[0].startsWith("\x1b[?2026h\x1b[2A\r"),
|
||||
`expected shrink diff to move up from prior content bottom, got ${JSON.stringify(terminal.writtenData[0])}`,
|
||||
);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue