agent2: Allow expanding terminals individually (#36670)

Release Notes:

- N/A
This commit is contained in:
Bennet Bo Fenner 2025-08-21 11:25:00 +02:00 committed by Joseph T. Lyons
parent 8c6a1d143c
commit 90946aeb2a
2 changed files with 33 additions and 13 deletions

View file

@ -121,14 +121,19 @@ impl EntryViewState {
for terminal in terminals { for terminal in terminals {
views.entry(terminal.entity_id()).or_insert_with(|| { views.entry(terminal.entity_id()).or_insert_with(|| {
create_terminal( let element = create_terminal(
self.workspace.clone(), self.workspace.clone(),
self.project.clone(), self.project.clone(),
terminal.clone(), terminal.clone(),
window, window,
cx, cx,
) )
.into_any() .into_any();
cx.emit(EntryViewEvent {
entry_index: index,
view_event: ViewEvent::NewTerminal(terminal.entity_id()),
});
element
}); });
} }
@ -187,6 +192,7 @@ pub struct EntryViewEvent {
} }
pub enum ViewEvent { pub enum ViewEvent {
NewTerminal(EntityId),
MessageEditorEvent(Entity<MessageEditor>, MessageEditorEvent), MessageEditorEvent(Entity<MessageEditor>, MessageEditorEvent),
} }

View file

@ -20,11 +20,11 @@ use file_icons::FileIcons;
use fs::Fs; use fs::Fs;
use gpui::{ use gpui::{
Action, Animation, AnimationExt, AnyView, App, BorderStyle, ClickEvent, ClipboardItem, Action, Animation, AnimationExt, AnyView, App, BorderStyle, ClickEvent, ClipboardItem,
EdgesRefinement, ElementId, Empty, Entity, FocusHandle, Focusable, Hsla, Length, ListOffset, EdgesRefinement, ElementId, Empty, Entity, EntityId, FocusHandle, Focusable, Hsla, Length,
ListState, MouseButton, PlatformDisplay, SharedString, Stateful, StyleRefinement, Subscription, ListOffset, ListState, MouseButton, PlatformDisplay, SharedString, Stateful, StyleRefinement,
Task, TextStyle, TextStyleRefinement, Transformation, UnderlineStyle, WeakEntity, Window, Subscription, Task, TextStyle, TextStyleRefinement, Transformation, UnderlineStyle, WeakEntity,
WindowHandle, div, ease_in_out, linear_color_stop, linear_gradient, list, percentage, point, Window, WindowHandle, div, ease_in_out, linear_color_stop, linear_gradient, list, percentage,
prelude::*, pulsating_between, point, prelude::*, pulsating_between,
}; };
use language::Buffer; use language::Buffer;
@ -256,10 +256,10 @@ pub struct AcpThreadView {
auth_task: Option<Task<()>>, auth_task: Option<Task<()>>,
expanded_tool_calls: HashSet<acp::ToolCallId>, expanded_tool_calls: HashSet<acp::ToolCallId>,
expanded_thinking_blocks: HashSet<(usize, usize)>, expanded_thinking_blocks: HashSet<(usize, usize)>,
expanded_terminals: HashSet<EntityId>,
edits_expanded: bool, edits_expanded: bool,
plan_expanded: bool, plan_expanded: bool,
editor_expanded: bool, editor_expanded: bool,
terminal_expanded: bool,
editing_message: Option<usize>, editing_message: Option<usize>,
_cancel_task: Option<Task<()>>, _cancel_task: Option<Task<()>>,
_subscriptions: [Subscription; 3], _subscriptions: [Subscription; 3],
@ -354,11 +354,11 @@ impl AcpThreadView {
auth_task: None, auth_task: None,
expanded_tool_calls: HashSet::default(), expanded_tool_calls: HashSet::default(),
expanded_thinking_blocks: HashSet::default(), expanded_thinking_blocks: HashSet::default(),
expanded_terminals: HashSet::default(),
editing_message: None, editing_message: None,
edits_expanded: false, edits_expanded: false,
plan_expanded: false, plan_expanded: false,
editor_expanded: false, editor_expanded: false,
terminal_expanded: true,
history_store, history_store,
hovered_recent_history_item: None, hovered_recent_history_item: None,
_subscriptions: subscriptions, _subscriptions: subscriptions,
@ -677,6 +677,11 @@ impl AcpThreadView {
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
match &event.view_event { match &event.view_event {
ViewEvent::NewTerminal(terminal_id) => {
if AgentSettings::get_global(cx).expand_terminal_card {
self.expanded_terminals.insert(*terminal_id);
}
}
ViewEvent::MessageEditorEvent(_editor, MessageEditorEvent::Focus) => { ViewEvent::MessageEditorEvent(_editor, MessageEditorEvent::Focus) => {
if let Some(thread) = self.thread() if let Some(thread) = self.thread()
&& let Some(AgentThreadEntry::UserMessage(user_message)) = && let Some(AgentThreadEntry::UserMessage(user_message)) =
@ -2009,6 +2014,8 @@ impl AcpThreadView {
.map(|path| format!("{}", path.display())) .map(|path| format!("{}", path.display()))
.unwrap_or_else(|| "current directory".to_string()); .unwrap_or_else(|| "current directory".to_string());
let is_expanded = self.expanded_terminals.contains(&terminal.entity_id());
let header = h_flex() let header = h_flex()
.id(SharedString::from(format!( .id(SharedString::from(format!(
"terminal-tool-header-{}", "terminal-tool-header-{}",
@ -2142,12 +2149,19 @@ impl AcpThreadView {
"terminal-tool-disclosure-{}", "terminal-tool-disclosure-{}",
terminal.entity_id() terminal.entity_id()
)), )),
self.terminal_expanded, is_expanded,
) )
.opened_icon(IconName::ChevronUp) .opened_icon(IconName::ChevronUp)
.closed_icon(IconName::ChevronDown) .closed_icon(IconName::ChevronDown)
.on_click(cx.listener(move |this, _event, _window, _cx| { .on_click(cx.listener({
this.terminal_expanded = !this.terminal_expanded; let terminal_id = terminal.entity_id();
move |this, _event, _window, _cx| {
if is_expanded {
this.expanded_terminals.remove(&terminal_id);
} else {
this.expanded_terminals.insert(terminal_id);
}
}
})), })),
); );
@ -2156,7 +2170,7 @@ impl AcpThreadView {
.read(cx) .read(cx)
.entry(entry_ix) .entry(entry_ix)
.and_then(|entry| entry.terminal(terminal)); .and_then(|entry| entry.terminal(terminal));
let show_output = self.terminal_expanded && terminal_view.is_some(); let show_output = is_expanded && terminal_view.is_some();
v_flex() v_flex()
.mb_2() .mb_2()