Improve handling of large output in embedded terminals (#32416)

#31922 made embedded terminals automatically grow to fit the content. We
since found some issues with large output which this PR addresses by:

- Only shaping / laying out lines that are visible in the viewport
(based on `window.content_mask`)
- Falling back to embedded scrolling after 1K lines. The perf fix above
actually makes it possible to handle a lot of lines, but:
- Alacrity uses a `u16` for rows internally, so we needed a limit to
prevent overflow.
- Scrolling through thousands of lines to get to the other side of a
terminal tool call isn't great UX, so we might as well set the limit
low.
- We can consider raising the limit when we make card headers sticky.

Release Notes:

- Agent: Improve handling of large terminal output
This commit is contained in:
Agus Zubiaga 2025-06-09 14:11:31 -07:00 committed by GitHub
parent ab70e524c8
commit b103d7621b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 199 additions and 87 deletions

View file

@ -638,29 +638,36 @@ impl ToolCard for TerminalToolCard {
.bg(cx.theme().colors().editor_background)
.rounded_b_md()
.text_ui_sm(cx)
.child(
ToolOutputPreview::new(
terminal.clone().into_any_element(),
terminal.entity_id(),
)
.with_total_lines(self.content_line_count)
.toggle_state(!terminal.read(cx).is_content_limited(window))
.on_toggle({
let terminal = terminal.clone();
move |is_expanded, _, cx| {
terminal.update(cx, |terminal, cx| {
terminal.set_embedded_mode(
if is_expanded {
None
} else {
Some(COLLAPSED_LINES)
},
cx,
);
});
}
}),
),
.child({
let content_mode = terminal.read(cx).content_mode(window, cx);
if content_mode.is_scrollable() {
div().h_72().child(terminal.clone()).into_any_element()
} else {
ToolOutputPreview::new(
terminal.clone().into_any_element(),
terminal.entity_id(),
)
.with_total_lines(self.content_line_count)
.toggle_state(!content_mode.is_limited())
.on_toggle({
let terminal = terminal.clone();
move |is_expanded, _, cx| {
terminal.update(cx, |terminal, cx| {
terminal.set_embedded_mode(
if is_expanded {
None
} else {
Some(COLLAPSED_LINES)
},
cx,
);
});
}
})
.into_any_element()
}
}),
)
},
)