From d43cc46288559f561e94268c72d61fdcb17abbb6 Mon Sep 17 00:00:00 2001
From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
Date: Tue, 23 Dec 2025 13:22:42 -0300
Subject: [PATCH] agent_ui: Add more items in the right-click context menu
(#45575)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Follow up to https://github.com/zed-industries/zed/pull/45440 adding an
item for "Open Thread as Markdown" and another for scroll to top and
scroll to bottom.
Release Notes:
- N/A
---
crates/agent_ui/src/acp/thread_view.rs | 83 +++++++++++++++++++++-----
1 file changed, 68 insertions(+), 15 deletions(-)
diff --git a/crates/agent_ui/src/acp/thread_view.rs b/crates/agent_ui/src/acp/thread_view.rs
index 21790a8f30846af573a9884d40be16aa584122ef..f8a849d1b40530c8d00c2709972bd3d64171dc7a 100644
--- a/crates/agent_ui/src/acp/thread_view.rs
+++ b/crates/agent_ui/src/acp/thread_view.rs
@@ -47,9 +47,9 @@ use terminal_view::terminal_panel::TerminalPanel;
use text::Anchor;
use theme::{AgentFontSize, ThemeSettings};
use ui::{
- Callout, CommonAnimationExt, ContextMenu, Disclosure, Divider, DividerColor, ElevationIndex,
- KeyBinding, PopoverMenuHandle, SpinnerLabel, TintColor, Tooltip, WithScrollbar, prelude::*,
- right_click_menu,
+ Callout, CommonAnimationExt, ContextMenu, ContextMenuEntry, Disclosure, Divider, DividerColor,
+ ElevationIndex, KeyBinding, PopoverMenuHandle, SpinnerLabel, TintColor, Tooltip, WithScrollbar,
+ prelude::*, right_click_menu,
};
use util::{ResultExt, size::format_file_size, time::duration_alt_display};
use workspace::{CollaboratorId, NewTerminal, Workspace};
@@ -2180,18 +2180,7 @@ impl AcpThreadView {
.when(is_last, |this| this.pb_4())
.w_full()
.text_ui(cx)
- .child(
- right_click_menu(format!("agent_context_menu-{}", entry_ix))
- .trigger(move |_, _, _| message_body)
- .menu(move |window, cx| {
- let focus = window.focused(cx);
- ContextMenu::build(window, cx, move |menu, _, _cx| {
- menu.action("Copy", Box::new(markdown::CopyAsMarkdown))
- .when_some(focus, |menu, focus| menu.context(focus))
- })
- })
- .into_any_element(),
- )
+ .child(self.render_message_context_menu(entry_ix, message_body, cx))
.into_any()
}
}
@@ -2298,6 +2287,70 @@ impl AcpThreadView {
}
}
+ fn render_message_context_menu(
+ &self,
+ entry_ix: usize,
+ message_body: AnyElement,
+ cx: &Context,
+ ) -> AnyElement {
+ let entity = cx.entity();
+ let workspace = self.workspace.clone();
+
+ right_click_menu(format!("agent_context_menu-{}", entry_ix))
+ .trigger(move |_, _, _| message_body)
+ .menu(move |window, cx| {
+ let focus = window.focused(cx);
+ let entity = entity.clone();
+ let workspace = workspace.clone();
+
+ ContextMenu::build(window, cx, move |menu, _, cx| {
+ let is_at_top = entity.read(cx).list_state.logical_scroll_top().item_ix == 0;
+
+ let scroll_item = if is_at_top {
+ ContextMenuEntry::new("Scroll to Bottom").handler({
+ let entity = entity.clone();
+ move |_, cx| {
+ entity.update(cx, |this, cx| {
+ this.scroll_to_bottom(cx);
+ });
+ }
+ })
+ } else {
+ ContextMenuEntry::new("Scroll to Top").handler({
+ let entity = entity.clone();
+ move |_, cx| {
+ entity.update(cx, |this, cx| {
+ this.scroll_to_top(cx);
+ });
+ }
+ })
+ };
+
+ let open_thread_as_markdown = ContextMenuEntry::new("Open Thread as Markdown")
+ .handler({
+ let entity = entity.clone();
+ let workspace = workspace.clone();
+ move |window, cx| {
+ if let Some(workspace) = workspace.upgrade() {
+ entity
+ .update(cx, |this, cx| {
+ this.open_thread_as_markdown(workspace, window, cx)
+ })
+ .detach_and_log_err(cx);
+ }
+ }
+ });
+
+ menu.when_some(focus, |menu, focus| menu.context(focus))
+ .action("Copy", Box::new(markdown::CopyAsMarkdown))
+ .separator()
+ .item(scroll_item)
+ .item(open_thread_as_markdown)
+ })
+ })
+ .into_any_element()
+ }
+
fn tool_card_header_bg(&self, cx: &Context) -> Hsla {
cx.theme()
.colors()