perf(tui): per-entry display-row-count cache for wrap-mode scroll bounds - #76
Merged
Conversation
- Clear row_cache when the buffer empties (clear-logs): the empty-buffer early return skipped the pruning pass, and the unwrap_or(0) fallback made retain a no-op — a large pre-clear cache lingered indefinitely. Regression test drives the buffer to empty and asserts a cleared cache. - row_cache_key second element now writes self.wrap_mode instead of a hardcoded literal true. - Reword the three 'registry entry pending (task 02)' doc comments — the REVIEW_FOCUS.md entry landed in 671ddb37. - collapsed_indicator_widths uses FRAME_INDENT_WIDTH instead of a bare 4. - debug_assert at the u16 rows insert so pathological row counts fail loudly in test builds instead of silently saturating.
…ions for row cache (#75)
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.
Closes #75.
What
In wrap mode the scroll-bounds pass (
total_lines) grapheme-walked the entire filtered buffer every frame (~20 fps) — correct since #74, but O(buffer) forever in steady state. This adds a per-entry display-row-count cache so unchanged entries cost oneHashMaplookup, plus it closes the last deferred #73-class drift (message-line link badges) and takes the small alignments deferred from #74's review.How
(content width, wrap_mode)clears the map wholesale on mismatch; every hit compares the cachedexpandedflag against the entry's current collapse state. This is sound because rendered char content depends only on immutable entry text + expanded state + link badges —leveland search decoration are style-only, andshow_timestamps/show_sourceare hardcoded (documented as future global-key inputs if ever wired to config).retain(id >= front_id)when the map outgrows2 × filtered_len + 64; a fully-emptied buffer (clear-logs) clears the cache outright in the empty early-return, which skips the pruning pass.render_innercall sites (total_lines loop + render loop) share oneentry_display_rows_cachedhelper; the cache-miss path is byte-identical to fix(tui): wrap-mode scroll bounds count wrapped stack-frame lines exactly #74's math.FRAME_INDENT_WIDTH/ASYNC_GAP_TEXT_LENderived from source instead of bare literals; collapse-visibility rules extracted into one helper shared by all three consumers;docs/REVIEW_FOCUS.mdregistry entry for the new render-written fields (per the approved-exception process), including themax_collapsed_framesassumed-constant note and the pruning-bound caveat.Tests (9 new)
Sentinel probe proving the second render reads the cache (mutation-verified: disabling the cache-read branch fails it); coherence tests for width change, wrap toggle, expand/collapse, link-mode enter/exit, and eviction (each asserting estimate == rendered ground truth); load-bearing message-badge-at-wrap-boundary test (fails if the bypass is removed); pruning threshold test; empty-buffer cache-clear regression test (verified red against the pre-fix code). All #73/#74 tests unchanged and green.
Full suites: fdemon-tui 1615, fdemon-app 3370; fmt clean; clippy
-D warningsclean on both stable 1.96 and 1.97.Docs
Plan, verified research, and review record under
workflow/plans/features/row-count-cache/andworkflow/reviews/row-count-cache/(verdict: APPROVED_WITH_CONCERNS, zero confirmed Critical/Major; all actionable minors fixed in-branch).Out of scope (pre-existing, will file separately)
Link-mode staleness:
rescan_links_if_activedoesn't run on filter changes, andDetectedLink.entry_indexis a raw buffer index that shifts on eviction — formatter and estimate are affected identically, so estimate == render still holds.