input: Keep highlight runs on char boundaries of the shaped text (#2777)
## Summary Fixes a crash in the editor when highlight run boundaries drift off the UTF-8 char boundaries of the line being shaped. The platform text system slices the line by run lengths (`text.split_at(run.len)` in `MacTextSystem::layout_line`) and panics inside a multi-byte character: ``` end byte index 9 is not a char boundary; it is inside '量' (bytes 8..11 of string) ``` Observed in Longbridge's quant script editor (Navi scripts with Chinese comments), crashing the whole app during prepaint. ## Root causes and fixes Two real sources of drift, plus a last line of defense: 1. **Unclipped diagnostics shift the runs coordinate space.** `DiagnosticSet::range` returns an entry straddling the viewport edge (its seek target matches any entry *containing* the offset) — and any range inside a folded region also lands between the visible line groups. `combine_highlights` then emits coverage outside the visible lines, breaking `layout_lines`' invariant that the runs vec concatenates exactly the visible lines' bytes; every later run boundary shifts by the excess byte count. `highlight_lines` now records the flushed line-group ranges and clips the composed styles back to them (`clip_styles_to_ranges`). 2. **Stale-tree styles.** While a background reparse is pending (2ms sync-parse timeout, or the >256KB `edit_tree` path), `SyntaxHighlighter::styles` serves node offsets from a stale tree; they can fall inside multi-byte characters of the *current* text. Ranges are now snapped to char boundaries with `Rope::clip_offset` (same approach as #2700 for selections). 3. **Defense in depth.** `layout_lines` snaps run boundaries to char boundaries of the exact sub-line being shaped (`align_runs_to_char_boundaries`, zero-cost when already aligned) before every `shape_line` call, so any remaining mis-aligned source degrades to slightly-off colors for a frame instead of a panic. ## Test plan - [x] `cargo test -p gpui-base --lib` (378 tests) — includes new unit tests for `align_runs_to_char_boundaries` and `clip_styles_to_ranges` - [x] `cargo test -p gpui-component --features tree-sitter-languages --lib` (486 tests) — includes `test_stale_tree_styles_snap_to_char_boundaries`, verified to fail without the fix (`style range 2..13 is not on char boundaries`) - [x] Manual repro (`crates/story/examples/cjk_diagnostic_panic.rs`, untracked): on `main` it panics right after the window opens (`end byte index 70 is not a char boundary; it is inside '例'`); on this branch it renders normally with the wavy underlines 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Y
Ylin committed
e5b8a3f496e4c812b1548229dc043ac1f72cee1f
Parent: 61f299b
Committed by GitHub <noreply@github.com>
on 8/20/2026, 8:14:43 AM