From 5a32d79d81550f2d41447f452e0278d212defeee Mon Sep 17 00:00:00 2001 From: roboomp Date: Tue, 14 Jul 2026 19:55:16 +0000 Subject: [PATCH] fix(tui): stop PageUp/PageDown stepping prompt history at idle PageUp/PageDown on an empty editor aliased to prompt-history navigation, identical to Up/Down, so idle page keys loaded the previous prompt instead of paging. They now only page the editor viewport (a no-op on a short draft) and never touch prompt history. Fixes #4754 --- packages/tui/CHANGELOG.md | 4 ++++ packages/tui/src/components/editor.ts | 19 ++++++------------- packages/tui/test/editor.test.ts | 21 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index b6d4864c9..dd0c4c178 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed PageUp/PageDown on an idle (empty) prompt editor stepping through prompt history like the Up/Down arrows instead of paging the draft. The paging keys now only scroll the editor viewport (a no-op on a short draft) and never touch prompt history ([#4754](https://github.com/can1357/oh-my-pi/issues/4754)). + ## [16.3.10] - 2026-07-06 ### Fixed diff --git a/packages/tui/src/components/editor.ts b/packages/tui/src/components/editor.ts index 8a631d790..312a78d6f 100644 --- a/packages/tui/src/components/editor.ts +++ b/packages/tui/src/components/editor.ts @@ -1357,21 +1357,14 @@ export class Editor implements Component, Focusable { } else if (kb.matches(data, "tui.editor.cursorLineEnd")) { this.#moveToLineEnd(); } - // Page navigation (PageUp/PageDown) + // Page navigation (PageUp/PageDown): page the editor viewport only. On a + // short draft this is a no-op — it never steps prompt history (that stays + // on Up/Down), so an idle empty editor swallows the keys instead of + // surprising the user by loading the previous prompt (#4754). else if (kb.matches(data, "tui.editor.pageUp")) { - if (this.#isEditorEmpty()) { - this.#navigateHistory(-1); - } else if (this.#historyIndex > -1 && this.#isOnFirstVisualLine()) { - this.#navigateHistory(-1); - } else { - this.#pageScroll(-1); - } + this.#pageScroll(-1); } else if (kb.matches(data, "tui.editor.pageDown")) { - if (this.#historyIndex > -1 && this.#isOnLastVisualLine()) { - this.#navigateHistory(1); - } else { - this.#pageScroll(1); - } + this.#pageScroll(1); } // Forward delete (Fn+Backspace or Delete key, including Shift+Delete) else if (kb.matches(data, "tui.editor.deleteCharForward") || matchesKey(data, "shift+delete")) { diff --git a/packages/tui/test/editor.test.ts b/packages/tui/test/editor.test.ts index d451c758e..278f391b9 100644 --- a/packages/tui/test/editor.test.ts +++ b/packages/tui/test/editor.test.ts @@ -1936,6 +1936,27 @@ describe("Editor component", () => { expect(editor.getCursor()).toEqual({ line: 6, col: 2 }); }); + it("PageUp/PageDown on an idle editor never step prompt history (#4754)", () => { + const editor = new Editor(defaultEditorTheme); + + editor.addToHistory("first prompt"); + editor.addToHistory("second prompt"); + editor.render(80); + expect(editor.getText()).toBe(""); + + editor.handleInput("\x1b[5~"); // PageUp on empty editor + expect(editor.getText()).toBe(""); + + editor.handleInput("\x1b[6~"); // PageDown on empty editor + expect(editor.getText()).toBe(""); + + // While browsing history (entered via Up), PageUp must not advance it. + editor.handleInput("\x1b[A"); // Up - shows "second prompt" + expect(editor.getText()).toBe("second prompt"); + editor.handleInput("\x1b[5~"); // PageUp - stays put + expect(editor.getText()).toBe("second prompt"); + }); + it("moves correctly through wrapped visual lines without getting stuck", () => { const editor = new Editor(defaultEditorTheme);