diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index ae209f3f..392e71b8 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -7,6 +7,7 @@ - Session naming: `/name ` command sets a display name shown in the session selector instead of the first message. Useful for distinguishing forked sessions. Extensions can use `pi.setSessionName()` and `pi.getSessionName()`. ([#650](https://github.com/badlogic/pi-mono/pull/650) by [@scutifer](https://github.com/scutifer)) - Extension example: `notify.ts` for desktop notifications via OSC 777 escape sequence ([#658](https://github.com/badlogic/pi-mono/pull/658) by [@ferologics](https://github.com/ferologics)) - Inline hint for queued messages showing the `Alt+Up` restore shortcut ([#657](https://github.com/badlogic/pi-mono/pull/657) by [@tmustier](https://github.com/tmustier)) +- Page-up/down navigation in `/resume` session selector to jump by 5 items ([#662](https://github.com/badlogic/pi-mono/pull/662) by [@aliou](https://github.com/aliou)) ### Fixed diff --git a/packages/coding-agent/src/modes/interactive/components/session-selector.ts b/packages/coding-agent/src/modes/interactive/components/session-selector.ts index 87de017e..911291da 100644 --- a/packages/coding-agent/src/modes/interactive/components/session-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/session-selector.ts @@ -227,6 +227,14 @@ class SessionList implements Component { else if (kb.matches(keyData, "selectDown")) { this.selectedIndex = Math.min(this.filteredSessions.length - 1, this.selectedIndex + 1); } + // Page up - jump up by maxVisible items + else if (kb.matches(keyData, "selectPageUp")) { + this.selectedIndex = Math.max(0, this.selectedIndex - this.maxVisible); + } + // Page down - jump down by maxVisible items + else if (kb.matches(keyData, "selectPageDown")) { + this.selectedIndex = Math.min(this.filteredSessions.length - 1, this.selectedIndex + this.maxVisible); + } // Enter else if (kb.matches(keyData, "selectConfirm")) { const selected = this.filteredSessions[this.selectedIndex]; diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index 06865c81..5e597070 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- `pageUp` and `pageDown` key support with `selectPageUp`/`selectPageDown` editor actions ([#662](https://github.com/badlogic/pi-mono/pull/662) by [@aliou](https://github.com/aliou)) + ## [0.43.0] - 2026-01-11 ### Added diff --git a/packages/tui/src/keybindings.ts b/packages/tui/src/keybindings.ts index 0252c909..41ec97df 100644 --- a/packages/tui/src/keybindings.ts +++ b/packages/tui/src/keybindings.ts @@ -26,6 +26,8 @@ export type EditorAction = // Selection/autocomplete | "selectUp" | "selectDown" + | "selectPageUp" + | "selectPageDown" | "selectConfirm" | "selectCancel" // Clipboard @@ -67,6 +69,8 @@ export const DEFAULT_EDITOR_KEYBINDINGS: Required = { // Selection/autocomplete selectUp: "up", selectDown: "down", + selectPageUp: "pageUp", + selectPageDown: "pageDown", selectConfirm: "enter", selectCancel: ["escape", "ctrl+c"], // Clipboard diff --git a/packages/tui/src/keys.ts b/packages/tui/src/keys.ts index 039946ca..f6c9c7e8 100644 --- a/packages/tui/src/keys.ts +++ b/packages/tui/src/keys.ts @@ -114,6 +114,8 @@ type SpecialKey = | "delete" | "home" | "end" + | "pageUp" + | "pageDown" | "up" | "down" | "left" @@ -164,6 +166,8 @@ export const Key = { delete: "delete" as const, home: "home" as const, end: "end" as const, + pageUp: "pageUp" as const, + pageDown: "pageDown" as const, up: "up" as const, down: "down" as const, left: "left" as const, @@ -611,6 +615,18 @@ export function matchesKey(data: string, keyId: KeyId): boolean { } return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.end, modifier); + case "pageUp": + if (modifier === 0) { + return data === "\x1b[5~" || matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageUp, 0); + } + return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageUp, modifier); + + case "pageDown": + if (modifier === 0) { + return data === "\x1b[6~" || matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageDown, 0); + } + return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageDown, modifier); + case "up": if (modifier === 0) { return data === "\x1b[A" || matchesKittySequence(data, ARROW_CODEPOINTS.up, 0); @@ -713,6 +729,8 @@ export function parseKey(data: string): string | undefined { else if (codepoint === FUNCTIONAL_CODEPOINTS.delete) keyName = "delete"; else if (codepoint === FUNCTIONAL_CODEPOINTS.home) keyName = "home"; else if (codepoint === FUNCTIONAL_CODEPOINTS.end) keyName = "end"; + else if (codepoint === FUNCTIONAL_CODEPOINTS.pageUp) keyName = "pageUp"; + else if (codepoint === FUNCTIONAL_CODEPOINTS.pageDown) keyName = "pageDown"; else if (codepoint === ARROW_CODEPOINTS.up) keyName = "up"; else if (codepoint === ARROW_CODEPOINTS.down) keyName = "down"; else if (codepoint === ARROW_CODEPOINTS.left) keyName = "left"; @@ -749,6 +767,8 @@ export function parseKey(data: string): string | undefined { if (data === "\x1b[H") return "home"; if (data === "\x1b[F") return "end"; if (data === "\x1b[3~") return "delete"; + if (data === "\x1b[5~") return "pageUp"; + if (data === "\x1b[6~") return "pageDown"; // Raw Ctrl+letter if (data.length === 1) {