Repository navigation
fix(tui): compensate scroll on message prune - #41247
Lauri-Nomme wants to merge 1 commit into
Conversation
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
|
hi, @kommander @simonklee could you please have a look? |
|
Automated PR Cleanup Thank you for contributing to opencode. Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions. This PR was closed because it matched the following cleanup criteria:
PRs created within the last month are not affected by this cleanup. If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate. Thanks again for taking the time to contribute. |
Issue for this PR
Closes #41243
Type of change
What does this PR do?
While the agent is producing output, a user can scroll up to read earlier messages. Once a session exceeds 100 messages, every new message prunes the oldest one off the top of the message store (
packages/tui/src/context/sync.tsx). The scrollbox holdsscrollTopfixed while scrolled up, so removing content above the reading position drifts the viewport down the transcript on every new message.This PR compensates the scroll position when the oldest messages are pruned, keeping the reading position stable while the user is scrolled up:
packages/tui/src/util/scroll.ts:compensatePruneScrollTopreturns ascrollTopmoved up by the height of content that disappeared above the first surviving message, computed from the layout captured before the prune.packages/tui/src/routes/session/index.tsx: runs it in acreateComputedwatching the message list, so it executes before the list re-renders while the pre-prune child layout is still available. Sticky-bottom following is untouched — when the user is at the bottom, compensation is skipped and the scrollbox re-sticks as usual.AssistantMessagenow wraps its parts in<box id={message.id}>so every message (user and assistant) renders an identifiable box. Previously only user messages carried an id, so pruned assistant messages could not be measured.How did you verify your code works?
Added
packages/tui/test/util/scroll-prune.test.tsx: unit tests forcompensatePruneScrollTopplus a render test (testRenderfrom@opentui/solid) mirroring the session wiring. It fills 100 alternating user/assistant messages, scrolls up 10 lines, then simulates thesync.tsxprune on each new message and asserts the message pinned at the top of the viewport stays at the same viewport line — without the fix it drifts fromy = 2toy = -22across 6 prunes.Verified
bun typecheck(packages/tui) passes and the fullpackages/tuisuite passes (200 tests, 8 snapshots unchanged).Screenshots / recordings
N/A (terminal UI; no recording).
Checklist