Skip to content

perf(tui): cut redundant redraws and diff re-tokenization - #9

Merged
jinyeow merged 2 commits into
mainfrom
claude/feature-roadmap-ikwcxg
Jul 13, 2026
Merged

jinyeow merged 2 commits into
mainfrom
claude/feature-roadmap-ikwcxg

Conversation

@jinyeow

@jinyeow jinyeow commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Why

The TUI felt laggy on navigation. Two investigations converged on the same conclusion: the cost is redraw frequency and re-tokenization on the UI thread, not blocked async — the sync-over-async audit came back clean (the ADO client is fully async and never called from a key handler). This PR fixes the three highest-impact, low-risk redraw paths.

What changed

A — Diff review re-tokenization storm (biggest win). The background stats prefetch raised the content-level Changed event after every file, so the currently-open file was fully re-tokenized and recomposed once per file in the PR (an N-file PR → N re-tokenizes) while the reviewer tried to scroll. A new StatsChanged event is split from Changed: prefetch provably never changes the selected file / CurrentDiff, so the view now refreshes only the title totals and file-row stats and skips the diff-pane rebuild.

B — Whole-app redraw on every status message. CobaltShell.RefreshChrome ran a full-app LayoutAndDraw to update one fixed-layout label. It now marks just the chrome labels dirty and lets the run loop repaint them.

C — PR-list comment-count burst. Each per-PR comment-count arrival re-formatted every row and reset the list source (O(rows²) over a load of 50–200 PRs). The burst now coalesces into a single re-render.

Deliberately not included: the per-keystroke LayoutAndDraw(true) on the main lists — it is intentionally true per ADR 0016 to avoid the "needs a second keypress" symptom under a multiplexer, and changing it needs a real-terminal UAT.

Tests

  • PrDiffViewModelTests — prefetch raises StatsChanged per file and never raises the content-level Changed.
  • DiffReviewDialogKeyTests — a stats refresh leaves the diff pane's data source instance in place (no rebuild).

Fixes B/C are behavior-preserving redraw optimizations covered by the existing suite.

Note: the change author could not run the clean CI build locally (no .NET SDK available in the working environment), so this PR relies on CI for the "0 errors + green tests" gate.

🤖 Generated with Claude Code


Generated by Claude Code

claude added 2 commits July 13, 2026 15:35
The TUI felt laggy under a few over-frequent redraw paths, all on the UI
thread. No blocking async was involved — the cost was redraw frequency and
re-tokenization, not per-cell render work.

- Diff review: the background stats prefetch raised the content-level Changed
  event after every file, so the *currently open* file was re-tokenized and
  recomposed once per file in the PR (N-file PR → N re-tokenizes) while the
  reviewer tried to scroll. Split a StatsChanged event from Changed:
  prefetch never alters the selected file/CurrentDiff, so the view now
  refreshes only the title totals and file-row stats and skips the diff-pane
  rebuild.
- Shell chrome: a routine status/log message ran a whole-app LayoutAndDraw to
  update one fixed-layout label. Mark the chrome labels dirty and let the run
  loop repaint them instead.
- PR list: a burst of per-PR comment-count arrivals re-formatted every row and
  reset the source once per count (O(rows^2) over a load of 50–200 PRs).
  Coalesce the burst into a single re-render.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018R2B8VAVaMVc8LK7EfKRBb
The two prefetch tests observed/cancelled on vm.Changed, which the stats
prefetch no longer raises (it now raises StatsChanged, leaving the displayed
diff untouched). Point them at StatsChanged and assert the prefetch does not
raise the content-level Changed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018R2B8VAVaMVc8LK7EfKRBb
@jinyeow
jinyeow merged commit fd36e1b into main Jul 13, 2026
5 checks passed
@jinyeow
jinyeow deleted the claude/feature-roadmap-ikwcxg branch July 13, 2026 16:04
jinyeow added a commit that referenced this pull request Jul 18, 2026
* origin/main:
  perf(round-2): diff-render, transport & input hot-path optimizations (#18)
  chore(tui): clear two CodeQL quality alerts in TextInputDialog (#12)
  perf(pr): make PR review feel local — and fix four wrong-file bugs found on the way (#11)
  feat(tui): lazygit-style shell chrome — context keybar, showcmd, real tab strips (#27)
  perf(tui): cut redundant redraws and diff re-tokenization (#9)
  docs: add CLAUDE.md project guidance for Claude Code
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.

2 participants