Skip to content

fix(ui): restore threaded rendering on macOS#539

Open
benvinegar wants to merge 1 commit into
mainfrom
fix/kitty-startup-regression
Open

fix(ui): restore threaded rendering on macOS#539
benvinegar wants to merge 1 commit into
mainfrom
fix/kitty-startup-regression

Conversation

@benvinegar

@benvinegar benvinegar commented Jul 14, 2026

Copy link
Copy Markdown
Member

Summary

  • stop forcing OpenTUI's renderer thread off on every platform
  • restore OpenTUI's default: threaded rendering on macOS, with OpenTUI continuing to disable it on Linux
  • keep this change isolated from the older Unicode-width work so the Kitty result has a clear A/B cause

Why

Hunk enters the alternate screen before React builds and emits the first complete review frame. That makes the issue's long blank-screen interval consistent with first-frame renderer work blocking the main thread rather than Git loading.

OpenTUI 0.4.3 defaults useThread to true, then explicitly turns it off on Linux. Hunk currently passes useThread: false, overriding the optimized macOS default. Removing that override delegates the platform choice back to OpenTUI and should move macOS renderer output off the main thread again.

This PR deliberately does not change code-column measurement or claim to explain the older v0.14 regression. It addresses the clear v0.17-era macOS threading regression independently so it can be tested in the reporter's Kitty environment.

Validation

  • bun run typecheck
  • bun run lint
  • bun run format:check
  • bun run test:integration
  • bun run test:tty-smoke

Linux is unchanged because OpenTUI disables threaded rendering there. Final validation therefore requires comparing this branch against v0.17.0 in Kitty on macOS.

Refs #534

This PR description was generated by Pi using OpenAI GPT-5.4

@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR addresses two compounding startup-latency regressions introduced across v0.14–v0.17. The first fix removes the explicit useThread: false override in createCliRenderer, allowing OpenTUI to apply its own platform-safe default (threaded on macOS, non-threaded on Linux). The second introduces a fast measurement path for ASCII-only patches: a single regex check against the raw patch string (simplePatchTextRegex) gates whether measureSimpleCodeLineWidth (using .length after tab expansion) can substitute for the full Unicode measureTextWidth scan on every rendered line.

  • src/main.tsx: one-line deletion restoring OpenTUI's threading default; guarded by a clarifying comment. Straightforward and targeted.
  • src/ui/diff/codeColumns.ts: adds hasOnlySimpleCodeLines, measureSimpleCodeLineWidth, and two compiled regexes; when the patch is non-empty the regex runs once on the raw patch string, otherwise falls back to per-line checks; tab expansion and CJK/emoji correctness are preserved.
  • src/ui/diff/codeColumns.test.ts: fixture factory now carries patch: widestLine to exercise the new fast path; a new tab-expansion test is added; the 100k-line fixture now exercises the fast path rather than the slow Unicode path.

Confidence Score: 4/5

Safe to merge; both changes are narrow and conservative — the renderer default is restored to a previously working state, and the measurement fast path always falls back to the existing Unicode scanner when the patch contains any non-ASCII content.

The logic in hasOnlySimpleCodeLines is sound: the raw patch string is a superset of all code-line content, so an ASCII-clean patch guarantees ASCII-clean lines. The only gap is that the large-fixture test (100k lines) now exercises the cheap .length path exclusively, leaving the measureTextWidth call chain untested at scale. The macOS threaded-renderer path cannot be validated in Linux CI, but the PR description explicitly calls this out as a required post-merge check.

src/ui/diff/codeColumns.test.ts — the large fixture now only stress-tests the fast ASCII path; src/main.tsx — the threaded-renderer behavior requires macOS + Kitty validation that CI cannot provide.

Important Files Changed

Filename Overview
src/main.tsx Removes the explicit useThread: false override from createCliRenderer, restoring OpenTUI's platform-safe default (threaded on macOS, non-threaded on Linux).
src/ui/diff/codeColumns.ts Adds a fast ASCII measurement path via hasOnlySimpleCodeLines + measureSimpleCodeLineWidth, bypassing per-character Unicode scanning when the patch contains only printable ASCII, tabs, and newlines. Logic is sound but the fallback branch (empty patch, line-by-line scan) has no dedicated test.
src/ui/diff/codeColumns.test.ts Updates the fixture factory to set patch: widestLine (was ""), shifting the large-fixture test onto the fast ASCII path; adds a tab-expansion test for the simple measurement path; the slow Unicode path is only exercised with 2 lines (CJK test), not the 100k-line fixture.
.changeset/faster-first-diff-frame.md New changeset entry describing the performance fix; accurate and complete.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[maxFileCodeLineWidth called] --> B{Cached?}
    B -- yes --> C[Return cached width]
    B -- no --> D[Fetch deletionLines & additionLines]
    D --> E{hasOnlySimpleCodeLines}
    E --> F{file.patch non-empty?}
    F -- yes --> G{simplePatchTextRegex test\nASCII + tab + newline only?}
    G -- yes --> H[measureLine = measureSimpleCodeLineWidth\nuse .length after tab expansion]
    G -- no --> I[measureLine = measureRenderedCodeLineWidth\nmeasureTextWidth Unicode scan]
    F -- no --> J{every deletionLine\npasses simpleCodeLineRegex?}
    J -- yes --> K{every additionLine\npasses simpleCodeLineRegex?}
    K -- yes --> H
    K -- no --> I
    J -- no --> I
    H --> L[Iterate deletionLines & additionLines\ntrack maxWidth]
    I --> L
    L --> M[Cache & return maxWidth]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[maxFileCodeLineWidth called] --> B{Cached?}
    B -- yes --> C[Return cached width]
    B -- no --> D[Fetch deletionLines & additionLines]
    D --> E{hasOnlySimpleCodeLines}
    E --> F{file.patch non-empty?}
    F -- yes --> G{simplePatchTextRegex test\nASCII + tab + newline only?}
    G -- yes --> H[measureLine = measureSimpleCodeLineWidth\nuse .length after tab expansion]
    G -- no --> I[measureLine = measureRenderedCodeLineWidth\nmeasureTextWidth Unicode scan]
    F -- no --> J{every deletionLine\npasses simpleCodeLineRegex?}
    J -- yes --> K{every additionLine\npasses simpleCodeLineRegex?}
    K -- yes --> H
    K -- no --> I
    J -- no --> I
    H --> L[Iterate deletionLines & additionLines\ntrack maxWidth]
    I --> L
    L --> M[Cache & return maxWidth]
Loading

Comments Outside Diff (1)

  1. src/ui/diff/codeColumns.test.ts, line 27-31 (link)

    P2 Large-fixture test no longer covers the slow Unicode measurement path

    The fixture factory now sets patch: widestLine (ASCII), so hasOnlySimpleCodeLines short-circuits on the patch regex and routes all 100 000 lines through measureSimpleCodeLineWidth. The test name "measures large generated fixtures without overflowing the call stack" implied it was stress-testing the measureRenderedCodeLineWidthmeasureTextWidth call chain at scale. That path is now only exercised by the two-line CJK test, so a future regression in measureTextWidth under a large non-ASCII workload wouldn't be caught by the existing suite. Adding a second large-fixture case with a CJK widestLine would restore that coverage.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/ui/diff/codeColumns.test.ts
    Line: 27-31
    
    Comment:
    **Large-fixture test no longer covers the slow Unicode measurement path**
    
    The fixture factory now sets `patch: widestLine` (ASCII), so `hasOnlySimpleCodeLines` short-circuits on the patch regex and routes all 100 000 lines through `measureSimpleCodeLineWidth`. The test name "measures large generated fixtures without overflowing the call stack" implied it was stress-testing the `measureRenderedCodeLineWidth``measureTextWidth` call chain at scale. That path is now only exercised by the two-line CJK test, so a future regression in `measureTextWidth` under a large non-ASCII workload wouldn't be caught by the existing suite. Adding a second large-fixture case with a CJK `widestLine` would restore that coverage.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
src/ui/diff/codeColumns.test.ts:27-31
**Large-fixture test no longer covers the slow Unicode measurement path**

The fixture factory now sets `patch: widestLine` (ASCII), so `hasOnlySimpleCodeLines` short-circuits on the patch regex and routes all 100 000 lines through `measureSimpleCodeLineWidth`. The test name "measures large generated fixtures without overflowing the call stack" implied it was stress-testing the `measureRenderedCodeLineWidth``measureTextWidth` call chain at scale. That path is now only exercised by the two-line CJK test, so a future regression in `measureTextWidth` under a large non-ASCII workload wouldn't be caught by the existing suite. Adding a second large-fixture case with a CJK `widestLine` would restore that coverage.

Reviews (1): Last reviewed commit: "fix(ui): restore fast interactive startu..." | Re-trigger Greptile

@benvinegar
benvinegar force-pushed the fix/kitty-startup-regression branch from acefd26 to 977f179 Compare July 15, 2026 09:23
@benvinegar benvinegar changed the title fix(ui): restore fast interactive startup fix(ui): restore threaded rendering on macOS Jul 15, 2026
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