acp: Allow collapsing edit file tool calls (#36675)

Release Notes:

- N/A
This commit is contained in:
Bennet Bo Fenner 2025-08-21 13:05:41 +02:00 committed by GitHub
parent f435af2fde
commit ad64a71f04
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 31 additions and 21 deletions

View file

@ -1,6 +1,7 @@
use std::ops::Range; use std::ops::Range;
use acp_thread::{AcpThread, AgentThreadEntry}; use acp_thread::{AcpThread, AgentThreadEntry};
use agent_client_protocol::ToolCallId;
use agent2::HistoryStore; use agent2::HistoryStore;
use collections::HashMap; use collections::HashMap;
use editor::{Editor, EditorMode, MinimapVisibility}; use editor::{Editor, EditorMode, MinimapVisibility};
@ -106,6 +107,7 @@ impl EntryViewState {
} }
} }
AgentThreadEntry::ToolCall(tool_call) => { AgentThreadEntry::ToolCall(tool_call) => {
let id = tool_call.id.clone();
let terminals = tool_call.terminals().cloned().collect::<Vec<_>>(); let terminals = tool_call.terminals().cloned().collect::<Vec<_>>();
let diffs = tool_call.diffs().cloned().collect::<Vec<_>>(); let diffs = tool_call.diffs().cloned().collect::<Vec<_>>();
@ -131,16 +133,21 @@ impl EntryViewState {
.into_any(); .into_any();
cx.emit(EntryViewEvent { cx.emit(EntryViewEvent {
entry_index: index, entry_index: index,
view_event: ViewEvent::NewTerminal(terminal.entity_id()), view_event: ViewEvent::NewTerminal(id.clone()),
}); });
element element
}); });
} }
for diff in diffs { for diff in diffs {
views views.entry(diff.entity_id()).or_insert_with(|| {
.entry(diff.entity_id()) let element = create_editor_diff(diff.clone(), window, cx).into_any();
.or_insert_with(|| create_editor_diff(diff.clone(), window, cx).into_any()); cx.emit(EntryViewEvent {
entry_index: index,
view_event: ViewEvent::NewDiff(id.clone()),
});
element
});
} }
} }
AgentThreadEntry::AssistantMessage(_) => { AgentThreadEntry::AssistantMessage(_) => {
@ -192,7 +199,8 @@ pub struct EntryViewEvent {
} }
pub enum ViewEvent { pub enum ViewEvent {
NewTerminal(EntityId), NewDiff(ToolCallId),
NewTerminal(ToolCallId),
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, EntityId, FocusHandle, Focusable, Hsla, Length, EdgesRefinement, ElementId, Empty, Entity, FocusHandle, Focusable, Hsla, Length, ListOffset,
ListOffset, ListState, MouseButton, PlatformDisplay, SharedString, Stateful, StyleRefinement, ListState, MouseButton, PlatformDisplay, SharedString, Stateful, StyleRefinement, Subscription,
Subscription, Task, TextStyle, TextStyleRefinement, Transformation, UnderlineStyle, WeakEntity, Task, TextStyle, TextStyleRefinement, Transformation, UnderlineStyle, WeakEntity, Window,
Window, WindowHandle, div, ease_in_out, linear_color_stop, linear_gradient, list, percentage, WindowHandle, div, ease_in_out, linear_color_stop, linear_gradient, list, percentage, point,
point, prelude::*, pulsating_between, prelude::*, pulsating_between,
}; };
use language::Buffer; use language::Buffer;
@ -256,7 +256,6 @@ 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,
@ -354,7 +353,6 @@ 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,
@ -677,9 +675,14 @@ impl AcpThreadView {
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
match &event.view_event { match &event.view_event {
ViewEvent::NewTerminal(terminal_id) => { ViewEvent::NewDiff(tool_call_id) => {
if AgentSettings::get_global(cx).expand_edit_card {
self.expanded_tool_calls.insert(tool_call_id.clone());
}
}
ViewEvent::NewTerminal(tool_call_id) => {
if AgentSettings::get_global(cx).expand_terminal_card { if AgentSettings::get_global(cx).expand_terminal_card {
self.expanded_terminals.insert(*terminal_id); self.expanded_tool_calls.insert(tool_call_id.clone());
} }
} }
ViewEvent::MessageEditorEvent(_editor, MessageEditorEvent::Focus) => { ViewEvent::MessageEditorEvent(_editor, MessageEditorEvent::Focus) => {
@ -1559,10 +1562,9 @@ impl AcpThreadView {
matches!(tool_call.kind, acp::ToolKind::Edit) || tool_call.diffs().next().is_some(); matches!(tool_call.kind, acp::ToolKind::Edit) || tool_call.diffs().next().is_some();
let use_card_layout = needs_confirmation || is_edit; let use_card_layout = needs_confirmation || is_edit;
let is_collapsible = !tool_call.content.is_empty() && !use_card_layout; let is_collapsible = !tool_call.content.is_empty() && !needs_confirmation;
let is_open = let is_open = needs_confirmation || self.expanded_tool_calls.contains(&tool_call.id);
needs_confirmation || is_edit || self.expanded_tool_calls.contains(&tool_call.id);
let gradient_overlay = |color: Hsla| { let gradient_overlay = |color: Hsla| {
div() div()
@ -2014,7 +2016,7 @@ 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 is_expanded = self.expanded_tool_calls.contains(&tool_call.id);
let header = h_flex() let header = h_flex()
.id(SharedString::from(format!( .id(SharedString::from(format!(
@ -2154,12 +2156,12 @@ impl AcpThreadView {
.opened_icon(IconName::ChevronUp) .opened_icon(IconName::ChevronUp)
.closed_icon(IconName::ChevronDown) .closed_icon(IconName::ChevronDown)
.on_click(cx.listener({ .on_click(cx.listener({
let terminal_id = terminal.entity_id(); let id = tool_call.id.clone();
move |this, _event, _window, _cx| { move |this, _event, _window, _cx| {
if is_expanded { if is_expanded {
this.expanded_terminals.remove(&terminal_id); this.expanded_tool_calls.remove(&id);
} else { } else {
this.expanded_terminals.insert(terminal_id); this.expanded_tool_calls.insert(id.clone());
} }
} }
})), })),