Skip to content

perf(tui): cache file-tree flatten/filter/sort between redraws - #94

Merged
deveshctl merged 2 commits into
mainfrom
refactor/tui-tree-render-cache
Aug 3, 2026
Merged

perf(tui): cache file-tree flatten/filter/sort between redraws#94
deveshctl merged 2 commits into
mainfrom
refactor/tui-tree-render-cache

Conversation

@deveshctl

Copy link
Copy Markdown
Owner

What

The interactive file-tree browser recomputed its visible file list from scratch on every redraw — walking the entire file tree, then filtering and sorting it. A single keystroke drives that computation up to ~7 times per frame (cursor bounds, clamping, status bar, both render passes). On large images with deep trees this repeated work shows up as navigation lag.

This branch memoizes the flatten → filter → sort result per pane and reuses it until an input actually changes.

How it works

  • Each tree pane gets its own cache slot, so split-pane rendering (which asks for both trees in one frame) doesn't thrash a single slot.
  • A slot is reused only when the selected layer, filter query, sort mode, collapse state, and analysis identity are all unchanged. Any of those changing forces a recompute.
  • The cache sits behind a pointer on the model so it survives the by-value model copies made on every update.

Impact

  • Output is unchanged — same files, same order, same colouring. This is purely the removal of redundant per-frame work.
  • Roughly 6 of every 7 tree computations per keystroke become cache hits, so navigating and scrolling large trees stays responsive. The wall-clock gain scales with tree size: negligible on small images, meaningful on images with many files.

Testing

  • go build ./... and go vet ./... clean.
  • New unit tests cover each cache-invalidation path (layer change, filter, sort, diff-only toggle, collapse toggle, re-analysis), pane independence, and cache-hit slice identity.

The file tree recomputed its full flatten->filter->sort pipeline on every
call, and the render loop calls it several times per keystroke (cursor
bounds, clamp, status bar, and both render passes in split mode). On a
large image that redundant per-frame tree walk is the main source of
held-key navigation lag.

Memoize the result per pane behind a pointer field on the model, keyed on
the pipeline inputs (selected layer, filter query, diff-only, sort mode)
plus a generation counter for collapse state. A pointer is required
because the method has a value receiver and the model is copied by value
on every update, so a value field would be written to a throwaway copy.
The output is unchanged; only the redundant work is removed.
The displayTreeFor memoization keyed on layerCursor, filters, sort, and
collapse state but not on the analysis itself. If m.analysis were ever
replaced while those keys stayed put, a warm cache slot would return the
previous analysis's file nodes. Bump an analysisGen counter when
m.analysis is assigned and include it in the cache key so a replaced
analysis forces a recompute. Dormant today (analysis is set once) but
removes the latent staleness trap.
@deveshctl
deveshctl merged commit 4286bb7 into main Aug 3, 2026
13 checks passed
@deveshctl
deveshctl deleted the refactor/tui-tree-render-cache branch August 3, 2026 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant