perf(tui): only render visible session rows in /sessions dialog#2830
Merged
Conversation
trungutt
approved these changes
May 20, 2026
docker-agent
left a comment
There was a problem hiding this comment.
Assessment: 🟢 APPROVE
Virtualized session-row rendering — the O(visible) rendering refactor is correct and well-structured.
What was checked:
- Negative capacity in
make([]string, 0, end-offset): Safe. AfterSetContent(nil, total)+SetScrollOffset(ScrollOffset()), the offset is clamped to[0, max(0, total−height)]. Sincetotal > 0in the else-branch andend = min(offset+visibleLines, total), we always haveend ≥ offset. No panic path. - Selected-row highlight index:
i == d.selecteduses the absolute index intod.filteredon both sides — correct for virtual windows. syncScrollbar()desync:ViewWithLinesinternally callssyncScrollbar()after theoffsetvariable is captured. BothSetScrollOffset(called inView()) andsyncScrollbaruse the same clamping formulamax(0, total−height)with the same already-updatedtotalHeight, so the read-back value is stable. No observable desync in the single-threaded TUI render path.nillines stored in scrollview:ViewWithLinesnever readsm.lines; only the oldView()path does. SinceViewWithLinesis always called in the new path, the nil value is harmless.filterSessions()double SetContent: The call infilterSessions()primestotalHeightforEnsureLineVisible; the call inView()is idempotent given the samelen(d.filtered). The scroll-reset-to-0 infilterSessions()is consistent with pre-existing behaviour.regionWidthvariable: Still used at line 358 (NewContent(regionWidth)). No dead-variable compile error.
The change cleanly delivers the stated O(visible) goal with no regressions found.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The
/sessionsdialog was visibly slow when scrolling or moving theselection with arrow keys, especially with a large session history.
Every render of
sessionBrowserDialog.View()was pre-rendering allfiltered session rows into styled lines (two
lipgloss.Style.Rendercalls plus string concatenation per row), even though the scrollview
only displays a small visible window. With hundreds of sessions, every
keystroke and scroll tick incurred hundreds of style renders before
the scrollview sliced the result down to the viewport.
The scrollview already exposes
ViewWithLines(visible)for thevirtualised case (used by
picker.goandworking_dir_picker.go).This change uses it to render only
[offset, offset+visibleHeight),making render cost O(visible rows) (~10–20) instead of O(total
sessions).
filterSessionsalso now callsSetContent(nil, len(filtered))sothe scrollview's
totalHeightis always in sync — this fixes alatent bug where
EnsureLineVisible(called on Up/Down keypress)could clamp against a stale
totalHeightbetween a filter change andthe next
View().