Optimize terminal rendering when clipped by parent containers#45537
Merged
nathansobo merged 1 commit intomainfrom Dec 26, 2025
Merged
Optimize terminal rendering when clipped by parent containers#45537nathansobo merged 1 commit intomainfrom
nathansobo merged 1 commit intomainfrom
Conversation
This brings the terminal element's viewport culling in line with the editor optimization in PR #44995 and the fix in PR #45077. ## Problem When a terminal is inside a scrollable container (e.g., the Agent Panel thread view), it would render ALL cells during prepaint, even when the terminal was entirely outside the viewport. This caused unnecessary CPU usage when multiple terminal tool outputs existed in the Agent Panel. ## Solution Calculate the intersection of the terminal's bounds with the current content_mask (the visible viewport after all parent clipping). If the intersection has zero area, skip all cell processing entirely. ### Important distinction between content modes: - **ContentMode::Scrollable**: Cells use the terminal's internal coordinate system with negative line numbers for scrollback history. We cannot filter cells by screen-space row numbers, so we render all cells when visible. The early-exit for zero intersection handles the offscreen case. - **ContentMode::Inline**: Cells use 0-based line numbers (no scrollback). We can filter cells to only those in the visible row range, using the same logic that existed before but now extracted into a helper function with proper bounds clamping to prevent the hang bug from PR #45077. ## Testing Added comprehensive unit tests for: - compute_visible_row_range edge cases - Cell filtering logic for Inline mode - Line/i32 comparison behavior Manually verified: - Terminal fully visible (no clipping) - Terminal clipped from top/bottom - Terminal completely outside viewport (renders nothing) - Scrollable terminals with scrollback history work correctly Release Notes: - Improved Agent Panel performance when terminals are scrolled offscreen.
CherryWorm
pushed a commit
to CherryWorm/zed
that referenced
this pull request
Dec 30, 2025
…dustries#45537) This brings the terminal element's viewport culling in line with the editor optimization in PR zed-industries#44995 and the fix in PR zed-industries#45077. ## Problem When a terminal is inside a scrollable container (e.g., the Agent Panel thread view), it would render ALL cells during prepaint, even when the terminal was entirely outside the viewport. This caused unnecessary CPU usage when multiple terminal tool outputs existed in the Agent Panel. ## Solution Calculate the intersection of the terminal's bounds with the current content_mask (the visible viewport after all parent clipping). If the intersection has zero area, skip all cell processing entirely. ### Three code paths 1. **Offscreen** (`intersection.size <= 0`): Early exit, process 0 cells 2. **Fully visible** (`intersection == bounds`): Fast path, stream cells directly (no allocation) 3. **Partially clipped**: Group cells by line, skip/take visible rows only ### Key insight: filter by screen position, not buffer coordinates The previous approach tried to filter cells by `cell.point.line` (terminal buffer coordinates), which breaks in Scrollable mode where cells can have negative line numbers for scrollback history. The new approach filters by **screen position** using `chunk_by(line).skip(N).take(M)`, which works regardless of the actual line numbers because we're filtering on enumerated line group index. ## Testing Added comprehensive unit tests for: - Screen-position filtering with positive lines (Inline mode) - Screen-position filtering with negative lines (Scrollable mode with scrollback) - Edge cases (skip all, positioning math) - Unified filtering works for both modes Manually verified: - Terminal fully visible (no clipping) ✓ - Terminal clipped from top/bottom ✓ - Terminal completely outside viewport ✓ - Scrollable terminals with scrollback history ✓ - Selection/interaction still works ✓ Release Notes: - Improved Agent Panel performance when terminals are scrolled offscreen. /cc @as-cii
rtfeldman
pushed a commit
that referenced
this pull request
Jan 5, 2026
This brings the terminal element's viewport culling in line with the editor optimization in PR #44995 and the fix in PR #45077. ## Problem When a terminal is inside a scrollable container (e.g., the Agent Panel thread view), it would render ALL cells during prepaint, even when the terminal was entirely outside the viewport. This caused unnecessary CPU usage when multiple terminal tool outputs existed in the Agent Panel. ## Solution Calculate the intersection of the terminal's bounds with the current content_mask (the visible viewport after all parent clipping). If the intersection has zero area, skip all cell processing entirely. ### Three code paths 1. **Offscreen** (`intersection.size <= 0`): Early exit, process 0 cells 2. **Fully visible** (`intersection == bounds`): Fast path, stream cells directly (no allocation) 3. **Partially clipped**: Group cells by line, skip/take visible rows only ### Key insight: filter by screen position, not buffer coordinates The previous approach tried to filter cells by `cell.point.line` (terminal buffer coordinates), which breaks in Scrollable mode where cells can have negative line numbers for scrollback history. The new approach filters by **screen position** using `chunk_by(line).skip(N).take(M)`, which works regardless of the actual line numbers because we're filtering on enumerated line group index. ## Testing Added comprehensive unit tests for: - Screen-position filtering with positive lines (Inline mode) - Screen-position filtering with negative lines (Scrollable mode with scrollback) - Edge cases (skip all, positioning math) - Unified filtering works for both modes Manually verified: - Terminal fully visible (no clipping) ✓ - Terminal clipped from top/bottom ✓ - Terminal completely outside viewport ✓ - Scrollable terminals with scrollback history ✓ - Selection/interaction still works ✓ Release Notes: - Improved Agent Panel performance when terminals are scrolled offscreen. /cc @as-cii
LivioGama
pushed a commit
to LivioGama/zed
that referenced
this pull request
Jan 20, 2026
…dustries#45537) This brings the terminal element's viewport culling in line with the editor optimization in PR zed-industries#44995 and the fix in PR zed-industries#45077. ## Problem When a terminal is inside a scrollable container (e.g., the Agent Panel thread view), it would render ALL cells during prepaint, even when the terminal was entirely outside the viewport. This caused unnecessary CPU usage when multiple terminal tool outputs existed in the Agent Panel. ## Solution Calculate the intersection of the terminal's bounds with the current content_mask (the visible viewport after all parent clipping). If the intersection has zero area, skip all cell processing entirely. ### Three code paths 1. **Offscreen** (`intersection.size <= 0`): Early exit, process 0 cells 2. **Fully visible** (`intersection == bounds`): Fast path, stream cells directly (no allocation) 3. **Partially clipped**: Group cells by line, skip/take visible rows only ### Key insight: filter by screen position, not buffer coordinates The previous approach tried to filter cells by `cell.point.line` (terminal buffer coordinates), which breaks in Scrollable mode where cells can have negative line numbers for scrollback history. The new approach filters by **screen position** using `chunk_by(line).skip(N).take(M)`, which works regardless of the actual line numbers because we're filtering on enumerated line group index. ## Testing Added comprehensive unit tests for: - Screen-position filtering with positive lines (Inline mode) - Screen-position filtering with negative lines (Scrollable mode with scrollback) - Edge cases (skip all, positioning math) - Unified filtering works for both modes Manually verified: - Terminal fully visible (no clipping) ✓ - Terminal clipped from top/bottom ✓ - Terminal completely outside viewport ✓ - Scrollable terminals with scrollback history ✓ - Selection/interaction still works ✓ Release Notes: - Improved Agent Panel performance when terminals are scrolled offscreen. /cc @as-cii
LivioGama
pushed a commit
to LivioGama/zed
that referenced
this pull request
Jan 20, 2026
…dustries#45537) This brings the terminal element's viewport culling in line with the editor optimization in PR zed-industries#44995 and the fix in PR zed-industries#45077. ## Problem When a terminal is inside a scrollable container (e.g., the Agent Panel thread view), it would render ALL cells during prepaint, even when the terminal was entirely outside the viewport. This caused unnecessary CPU usage when multiple terminal tool outputs existed in the Agent Panel. ## Solution Calculate the intersection of the terminal's bounds with the current content_mask (the visible viewport after all parent clipping). If the intersection has zero area, skip all cell processing entirely. ### Three code paths 1. **Offscreen** (`intersection.size <= 0`): Early exit, process 0 cells 2. **Fully visible** (`intersection == bounds`): Fast path, stream cells directly (no allocation) 3. **Partially clipped**: Group cells by line, skip/take visible rows only ### Key insight: filter by screen position, not buffer coordinates The previous approach tried to filter cells by `cell.point.line` (terminal buffer coordinates), which breaks in Scrollable mode where cells can have negative line numbers for scrollback history. The new approach filters by **screen position** using `chunk_by(line).skip(N).take(M)`, which works regardless of the actual line numbers because we're filtering on enumerated line group index. ## Testing Added comprehensive unit tests for: - Screen-position filtering with positive lines (Inline mode) - Screen-position filtering with negative lines (Scrollable mode with scrollback) - Edge cases (skip all, positioning math) - Unified filtering works for both modes Manually verified: - Terminal fully visible (no clipping) ✓ - Terminal clipped from top/bottom ✓ - Terminal completely outside viewport ✓ - Scrollable terminals with scrollback history ✓ - Selection/interaction still works ✓ Release Notes: - Improved Agent Panel performance when terminals are scrolled offscreen. /cc @as-cii
LivioGama
pushed a commit
to LivioGama/zed
that referenced
this pull request
Feb 15, 2026
…dustries#45537) This brings the terminal element's viewport culling in line with the editor optimization in PR zed-industries#44995 and the fix in PR zed-industries#45077. ## Problem When a terminal is inside a scrollable container (e.g., the Agent Panel thread view), it would render ALL cells during prepaint, even when the terminal was entirely outside the viewport. This caused unnecessary CPU usage when multiple terminal tool outputs existed in the Agent Panel. ## Solution Calculate the intersection of the terminal's bounds with the current content_mask (the visible viewport after all parent clipping). If the intersection has zero area, skip all cell processing entirely. ### Three code paths 1. **Offscreen** (`intersection.size <= 0`): Early exit, process 0 cells 2. **Fully visible** (`intersection == bounds`): Fast path, stream cells directly (no allocation) 3. **Partially clipped**: Group cells by line, skip/take visible rows only ### Key insight: filter by screen position, not buffer coordinates The previous approach tried to filter cells by `cell.point.line` (terminal buffer coordinates), which breaks in Scrollable mode where cells can have negative line numbers for scrollback history. The new approach filters by **screen position** using `chunk_by(line).skip(N).take(M)`, which works regardless of the actual line numbers because we're filtering on enumerated line group index. ## Testing Added comprehensive unit tests for: - Screen-position filtering with positive lines (Inline mode) - Screen-position filtering with negative lines (Scrollable mode with scrollback) - Edge cases (skip all, positioning math) - Unified filtering works for both modes Manually verified: - Terminal fully visible (no clipping) ✓ - Terminal clipped from top/bottom ✓ - Terminal completely outside viewport ✓ - Scrollable terminals with scrollback history ✓ - Selection/interaction still works ✓ Release Notes: - Improved Agent Panel performance when terminals are scrolled offscreen. /cc @as-cii
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This brings the terminal element's viewport culling in line with the editor optimization in PR #44995 and the fix in PR #45077.
Problem
When a terminal is inside a scrollable container (e.g., the Agent Panel thread view), it would render ALL cells during prepaint, even when the terminal was entirely outside the viewport. This caused unnecessary CPU usage when multiple terminal tool outputs existed in the Agent Panel.
Solution
Calculate the intersection of the terminal's bounds with the current content_mask (the visible viewport after all parent clipping). If the intersection has zero area, skip all cell processing entirely.
Three code paths
intersection.size <= 0): Early exit, process 0 cellsintersection == bounds): Fast path, stream cells directly (no allocation)Key insight: filter by screen position, not buffer coordinates
The previous approach tried to filter cells by
cell.point.line(terminal buffer coordinates), which breaks in Scrollable mode where cells can have negative line numbers for scrollback history.The new approach filters by screen position using
chunk_by(line).skip(N).take(M), which works regardless of the actual line numbers because we're filtering on enumerated line group index.Testing
Added comprehensive unit tests for:
Manually verified:
Release Notes:
/cc @as-cii