Closes #49662 ## Summary Fixes an index-out-of-bounds crash in `EditorElement::prepaint` that occurs when block decorations oscillate in size, exhausting the recursive prepaint budget (`MAX_PREPAINT_DEPTH = 5`). ## Root cause When block decorations resize during `render_blocks`, prepaint recurses to rebuild layout state. Previously, both `resize_blocks()` and `update_renderer_widths()` mutated the display map **before** checking `can_prepaint()`. At max depth: 1. `resize_blocks()` mutated the block map, changing the display row mapping 2. `can_prepaint()` returned false, skipping the recursive rebuild 3. All local state (`snapshot`, `start_row`, `end_row`, `line_layouts`, `row_infos`) remained stale 4. Downstream code ā particularly `layout_inline_diagnostics` which takes a **fresh** `editor.snapshot()` ā would see the new row mapping but index into the stale `line_layouts` 5. `row.minus(start_row)` produced an index exceeding `line_layouts.len()` ā panic The crash is most likely to occur when many block decorations appear or resize simultaneously (e.g., unfolding a folder containing many git repos, causing a burst of diff hunk blocks), or when `place_near` blocks oscillate between inline (height=0) and block (height>=1) mode, burning through all 5 recursion levels without converging. ## Fix Guard both mutation sites with `can_prepaint()` so the display map is NOT mutated when we cannot recurse to rebuild state: - **Block resize**: move `resize_blocks()` inside the `can_prepaint()` guard. At max depth, defer the resize to the next frame via `cx.notify()`. The resize will be re-detected because the stored height still mismatches the rendered height. https://github.com/jean-humann/zed/blob/021978ecf939723a6ba4ab9843572b6bcefe7cb7/crates/editor/src/element.rs#L10207-L10239 - **Renderer widths**: short-circuit `update_renderer_widths()` with `can_prepaint()` so fold widths are not updated at max depth. https://github.com/jean-humann/zed/blob/021978ecf939723a6ba4ab9843572b6bcefe7cb7/crates/editor/src/element.rs#L10097-L10115 In both cases the next frame starts with a fresh recursion budget (`EditorRequestLayoutState::default()` resets `prepaint_depth` to 0) and applies the deferred changes normally. The worst case is one frame of slightly wrong-sized blocks ā vastly preferable to a crash. ## Test plan - [x] `cargo check -p editor` passes - [ ] Manual testing with many open files, inline diagnostics, hover popovers, and git diff hunks Release Notes: - Fixed a crash (index out of bounds) during editor rendering when block decorations repeatedly resize, exhausting the recursive prepaint budget. š¤ Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
1 file changedLine totals unavailable