Skip to content

fix(native-chat): keep a huge unbroken paste from freezing the chat (#32355) - #36031

Merged
nwparker merged 5 commits into
mainfrom
fix/native-chat-large-paste-takeover
Oct 29, 2026
Merged

nwparker merged 5 commits into
mainfrom
fix/native-chat-large-paste-takeover

Conversation

@nwparker

@nwparker nwparker commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​127 0 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​127
Prod 5 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​221 0 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​221

Fixes #32355 (Linear STA-12531). Takeover of community PR #34501 by @thefrikidude — thank you; co-author credit on every commit.

Cause: not a regression from a specific Orca PR. Chromium re-shapes kerned text for every wrapped line of a long run with no break opportunity, so a single huge unbroken line (JSON, logs, base64) froze the composer: 1 MiB took ~19–23s.

Fix: turn off font-kerning only on runs that have no line-break opportunity and are longer than 256 characters. The freeze drops to ~0.2s, the text and DOM are unchanged, and the loss of kerning on such runs isn't visible.

  • Composer: ProseMirror inline decorations with an incremental windowed rescan. Only the edited run is rescanned and other decorations are reused.
    • 8,000 runs in one paragraph: ~0.5–0.8ms per keystroke, down from 1.4s.
    • Decorations are deferred during IME composition and rescanned on compositionend.
  • Transcript user-message fold and expanded queued card: the same rule, applied to the whole message.
  • CJK, kana, Hangul and Thai text counts as breakable, so it keeps kerning. NBSP doesn't count as a break. Supplementary-plane surrogate pairs are never split.

Unlike #34501, a long paste stays inline as text rather than being converted to a file.

Verification: adversarial review over 5 rounds by an Opus sub-agent and Codex (gpt-6.1-sol, xhigh); both final verdicts are MERGE. In independent seeded fuzzing (~65k transactions, plus 462k Unicode boundary cases), the incremental decorations matched a fresh full scan every time.

nwparker and others added 5 commits October 29, 2026 10:46
A long run with no whitespace ("xxxx…", "0000…", "abab…") wrapped with
kerning makes Chromium reshape it at every line, quadratic in run length:
128 KiB stalls 2.4 s, 1 MiB 19 s, 5 MiB never finishes. ProseMirror forces
that layout on paste and on each keystroke, so the composer freezes in
every terminal-backed chat, including paired servers and WSL. A sent
message stalls the transcript the same way: its fold clips the text but
still lays it all out (128 KiB: 2.5 s).

Runs over 256 characters now render with font-kerning: none, so prose of
any length and Shift+Enter lines keep kerning:
- composer: inline decorations, updated only for the lines a transaction
  touches (a keystroke beside 8,000 decorated lines ~1 ms, not ~190 ms)
- user messages in the transcript and expanded queued cards: the whole
  text when it holds such a run

Text, drafts and what is sent are unchanged. After: 1 MiB single line
84 ms, 5 MiB 312 ms (keystroke 248 ms), 1 MiB of 4000-char lines 50 ms
(was 2.3 s), transcript 128 KiB 80 ms. Worst case left kerned, 256-char
runs: 1 MiB 242 ms, 5 MiB 1.2 s, like 1 MiB of short lines (291 ms).

Fixes #32355

Co-authored-by: Manan Chataut <mananchataut@gmail.com>
These scripts have no spaces but Chromium can break between their
characters, so a long paragraph is not one unbreakable run. Count
ideographs, kana, Hangul and Thai as break opportunities so such text
keeps kerning.

Co-authored-by: Manan Chataut <mananchataut@gmail.com>
…itions

Splitting one run inside a block of thousands replaced every decoration
in that block, and ProseMirror's removal is quadratic: 1,411 ms for one
space in a paragraph of 8,000 long runs. A change now rescans only from
the run edge before it to the run edge after it, and removes only the
decorations that overlap: ~1 ms for the same edit.

Decorations are only mapped while an IME composition is in progress, so
the composing text node is not re-rendered. The deferred range is
rescanned with the next non-composing change, or on compositionend when
none follows.

The keystroke-timing test is replaced by deterministic ones: unaffected
decorations are reused and the result equals a full scan; a composition
defers the rescan and compositionend runs it.

Co-authored-by: Manan Chataut <mananchataut@gmail.com>
A supplementary ideograph (U+20000-U+3FFFF) broke a run at its high
surrogate only, so the decoration began on the low surrogate and split
the pair across elements. Both the run scan and the leftward edge scan
now treat the pair as one break.

NBSP joins words for Chromium's line breaker (UAX #14 class GL), so an
NBSP-joined paste is one unbreakable run and must lose kerning; drop it
from the break set. No other non-breaking characters were in it.

Drop a composer test whose coverage the decoration reuse test already
has.

Co-authored-by: Manan Chataut <mananchataut@gmail.com>
Two lone-surrogate edge cases made the incremental rescan disagree with
a full scan:
- an edit completing a pair at the window start (a lone high surrogate,
  then a pasted low surrogate and run) began the decoration on the low
  surrogate; the window now widens past the whole pair
- a lone low surrogate after any break counted as a pair end, dropping
  it from the run; that now requires a preceding high surrogate

A seeded fuzz also found inclusive decoration edges mapping across a
joined block's boundary, where ProseMirror cannot remove them; the
decorations are no longer inclusive.

Co-authored-by: Manan Chataut <mananchataut@gmail.com>
@greptile-apps

greptile-apps Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable defects were established.

Summary

This PR turns off kerning for long unbroken text without changing the saved text.

  • The composer keeps long unbroken pastes as text without costly kerning.
  • Transcript messages and expanded queued cards skip kerning for long unbroken text.

No actionable defects were established.

Reviews (1) · Last reviewed commit: "fix(native-chat): classify surrogate pai..." · Reviewed by Greptile

@coderabbitai

coderabbitai Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f926a874-180c-459c-a63d-ad928f6a7123
Commits

Reviewing files that changed from the base of the PR and between 47b324b and 1af6aee.

Files selected for processing: 7
  • src/renderer/src/components/native-chat/NativeChatPromptEditor.test.tsx
  • src/renderer/src/components/native-chat/NativeChatPromptEditor.tsx
  • src/renderer/src/components/native-chat/NativeChatQueuedMessageCard.tsx
  • src/renderer/src/components/native-chat/NativeChatUserMessageFold.tsx
  • src/renderer/src/components/native-chat/native-chat-unkerned-run-decorations.test.ts
  • src/renderer/src/components/native-chat/native-chat-unkerned-run-decorations.ts
  • src/renderer/src/components/native-chat/native-chat-unkerned-runs.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.

Walkthrough

The change adds detection for long text runs without break opportunities and disables font kerning on those runs. A ProseMirror extension applies decorations in the prompt editor and updates them after edits, including handling IME composition and surrogate-pair boundaries. The prompt editor registers the extension. Queued and folded message views conditionally apply the same CSS rule. Tests cover long pasted text, run detection, incremental edits, and composition.

Priority: Normal

Severity of issue fixed: Medium

Merge Risk: Minimal · up to 1af6a

No identified issue blocks merging this change after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title names the fix and its target: a huge unbroken paste that freezes the native chat composer. It matches the main change in the changeset, which disables kerning on long unbreakable runs. The r…
Description check Passed The description follows the template's main sections and gives a clear cause, fix, and verification. It states the mechanism, the scope (composer, transcript fold, queued card), and the test results. …
Linked Issues check Passed Issue #32355 requires the freeze caused by very long pasted text to be addressed. The new nativeChatUnkernedRuns helper identifies long runs without break opportunities, and the ProseMirror extensio…
Out of Scope Changes check Passed The reviewed changes stay within the long-text freeze fix for #32355. The run classifier, incremental decoration logic, composer integration, transcript integration, queued-card integration, and tests…
Full details: Title check

Explanation

The title names the fix and its target: a huge unbroken paste that freezes the native chat composer. It matches the main change in the changeset, which disables kerning on long unbreakable runs. The reference to #32355 adds no meaning but does not reduce accuracy.

Full details: Description check

Explanation

The description follows the template's main sections and gives a clear cause, fix, and verification. It states the mechanism, the scope (composer, transcript fold, queued card), and the test results. It links issue #32355 with a 'Fixes' line, but the template's Visual Proof, Testing checkboxes, and AI Disclosure are not filled in. The ELI5, Review, and Agent skill upstream boundary sections are also missing. The description is mostly complete, so the check passes, but the missing visual proof for a UI behavior change should be added.

Full details: Linked Issues check

Explanation

Issue #32355 requires the freeze caused by very long pasted text to be addressed. The new nativeChatUnkernedRuns helper identifies long runs without break opportunities, and the ProseMirror extension applies font-kerning: none without changing text. The composer registers the extension. The transcript and queued-card paths apply the same CSS rule. Tests cover long pasted runs, incremental rescanning, surrogate-pair boundaries, and IME composition. The issue's separate attachment idea is not a coding requirement for #32355.

Full details: Out of Scope Changes check

Explanation

The reviewed changes stay within the long-text freeze fix for #32355. The run classifier, incremental decoration logic, composer integration, transcript integration, queued-card integration, and tests all support detection or prevention of the layout slowdown. No unrelated change is demonstrated.

Full details: Docstring Coverage

Explanation

Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 9 functions across 7 files.

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nwparker
nwparker merged commit bc228ff into main Oct 29, 2026
40 checks passed
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.

[Bug]: Orca freezes when big input is pasted

1 participant