/** * Reading back through the transcript. * * The TUI owns the mechanism — a pinned window over the line buffer, painted on * the alternate screen, described in `tui.ts` under `scrollOffset`. This file * owns the two things the TUI cannot know: which keys mean what, and what the * indicator on the bottom row should look like in the user's theme. * * ## Two scopes, and why the split is where it is * * At the prompt only four keys are live — page up, page down, and the two ends. * They are the keys every pager already taught, and none of them is a key the * prompt has any use for, so nothing is taken away to make room. Anything more * would be: the arrows walk prompt history, and a reader who loses that to * scrolling has traded one surprise for another. * * Once the view is pinned it captures keys, exactly as a picker does, and the * fuller set comes alive — line steps on the arrows, escape back to live. The * prompt is not in front of you at that point, so its keys are free. * * The capture is an input listener rather than editor actions because it has to * beat the focused editor to the arrows: an editor action runs only after the * editor has already decided the key was history navigation. * * ## Leaving * * Anything that is not a scroll key un-pins the view and then does what it * always did. That is one rule rather than a list of exceptions, and it is the * one that matches what people actually do — you stop reading by starting to * type, not by remembering to press escape first. Without it, typing into a * pinned view would echo into a prompt that is scrolled off-screen, which is * the exact class of "where did my keystroke go" this whole change exists to * remove. */ import { type Component, type Container, type EditorComponent, type Keybinding, type TUI } from "@kolisachint/hoocode-tui"; import type { KeybindingsManager } from "../../core/keybindings.js"; /** * Pin the view to the previous or next thing the user said. * * The landmarks people navigate a session by are their own messages — "where * did I ask about the renderer" — and they are sparse enough that a few presses * cross a long transcript. Agent replies and tool blocks are deliberately not * stops: in a tool-heavy session they are dense enough that the key degrades * into paging with extra steps. * * The rows come from the render memo rather than from a re-render: a message's * offset inside the chat container, plus that container's offset at the root, * is its absolute row in the buffer the viewport windows over. Both are already * cached from the last frame, so a jump is a walk over line-array lengths. */ export declare function jumpToUserMessage(ui: TUI, chat: Container, direction: "previous" | "next", isUserMessage: (child: Component) => boolean): boolean; /** * Wire scrolling into a running interactive mode. * * Takes the mode's own `KeybindingsManager` rather than reading the process-wide * one: the keys have to resolve the same way here as they do inside the editor a * line above, and a listener that silently matched nothing — which is what the * unconfigured global resolves every `app.*` id to — would hand the pinned view's * keys back to the prompt without saying so. * * Returns the teardown for the input listener, matching the other listeners the * mode installs; the editor actions live as long as the editor does. */ export declare function installScrollView(ui: TUI, editor: EditorComponent & { onAction(action: Keybinding, handler: () => void): void; }, keybindings: KeybindingsManager, turns: { chat: Container; isUserMessage: (child: Component) => boolean; }): () => void; //# sourceMappingURL=scroll-view.d.ts.map