Skip to content

perf(select): pre-compute preview tabs in background#935

Merged
max-sixty merged 11 commits intomainfrom
select-speed
Feb 5, 2026
Merged

perf(select): pre-compute preview tabs in background#935
max-sixty merged 11 commits intomainfrom
select-speed

Conversation

@max-sixty
Copy link
Owner

@max-sixty max-sixty commented Feb 5, 2026

Summary

  • Pre-compute all 4 preview tabs (HEAD±, log, main…±, remote⇅) in background thread
  • Cache raw git output, apply pager only at display time
  • Consolidate dimension calculation into single source of truth
  • Replace manual timeout polling loops with wait-timeout crate across codebase
  • Simplify pager config caching (store ready-to-use command with flags)

Tab switching is now near-instant since cached results are served immediately.

Test plan

  • All tests pass (cargo test)
  • Clippy clean
  • Manual test: wt select shows instant tab switching between 1/2/3/4
  • Verify pager (delta/bat) still works for diff tabs

🤖 Generated with Claude Code

max-sixty and others added 11 commits February 4, 2026 18:10
Add background pre-computation and caching for all preview modes
(HEAD±, log, main…±, remote⇅). When the selector starts, a background
thread computes previews for all worktrees while the user views the
list. Tab switching is now near-instant once pre-computation completes.

Changes:
- Add PreviewCache with compound key (branch_name, mode)
- Convert all render methods to static compute_* functions
- Extract compute_diff_preview as shared helper
- Add PREVIEW_WIDTH_PERCENT constant (consolidates 50% logic)
- Derive Hash for PreviewMode to use as DashMap key

Co-Authored-By: Claude <noreply@anthropic.com>
Cache raw git output without pager processing. Apply pager only when
displaying cached results. This enables background pre-computation to
produce the same output as foreground, making caching effective.

- Replace run_git_diff_with_pager with pipe_through_pager
- pipe_through_pager takes text input via stdin instead of running git
- Apply pager in preview_for_mode for diff modes (1, 3, 4)
- Graceful fallback returns original text on pager failure

Co-Authored-By: Claude <noreply@anthropic.com>
Address Codex review findings:
- Don't join writer thread before timeout loop (can hang if pipe fills)
- Add wait() after kill() to reap zombie processes
- Join reader thread on error paths to avoid thread leaks

Co-Authored-By: Claude <noreply@anthropic.com>
Replace manual polling loop with wait_timeout::ChildExt::wait_timeout().
Removes ~15 lines of timeout/cleanup logic while preserving behavior.

Co-Authored-By: Claude <noreply@anthropic.com>
Tests passthrough, transform, invalid command, and failing command paths.

Co-Authored-By: Claude <noreply@anthropic.com>
- Move wait-timeout to regular deps (works cross-platform)
- Simplify shell/utils.rs compinit probe timeout
- Simplify shell_exec.rs command timeout

Removes manual polling loops in favor of explicit wait_timeout() calls.

Co-Authored-By: Claude <noreply@anthropic.com>
wait_timeout reaps the process, so wait_with_output() afterward would
call wait() on an already-reaped child. Take stdout handle before
wait_timeout and read it directly after process exits.

Co-Authored-By: Claude <noreply@anthropic.com>
- shell/utils.rs: Use bytes + lossy decode instead of read_to_string
  to avoid turning invalid UTF-8 probe failures into Some(false)
- pager.rs: Cache has_explicit_pager_config() result in OnceLock
  to avoid reloading user config on every preview render

Co-Authored-By: Claude <noreply@anthropic.com>
Combine CACHED_PAGER and HAS_EXPLICIT_PAGER_CONFIG into one CachedPager
struct. Both values are derived from the same user config check, so
computing them together avoids redundant initialization.

Co-Authored-By: Claude <noreply@anthropic.com>
Move --paging=never logic into cache initialization so the stored
command is ready to use. This eliminates:
- CachedPager struct and is_explicit field
- has_explicit_pager_config() function
- Runtime check on every pipe_through_pager call

Co-Authored-By: Claude <noreply@anthropic.com>
Exercises the get_diff_pager() initialization code path to improve
codecov/patch coverage.

Co-Authored-By: Claude <noreply@anthropic.com>
@max-sixty max-sixty merged commit 50de5ff into main Feb 5, 2026
20 of 21 checks passed
@max-sixty max-sixty deleted the select-speed branch February 5, 2026 16:12
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