From 6ab7898a5e0a83b1b936b79b2b13d625d2570681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= Date: Mon, 2 Mar 2026 12:34:01 +0000 Subject: [PATCH] agent: Add full-path tooltips to chat mentions (#50087) In text box Screenshot 2026-02-25 at 14 32 01 In chat Screenshot 2026-02-25 at 14 32 15 In chat (light theme) Screenshot 2026-02-25 at 14 35 26 Release Notes: - N/A --------- Co-authored-by: Danilo Leal --- crates/acp_thread/src/mention.rs | 35 +++++++++++++++++++++ crates/agent_ui/src/completion_provider.rs | 1 + crates/agent_ui/src/inline_prompt_editor.rs | 1 + crates/agent_ui/src/mention_set.rs | 20 ++++++++++-- crates/agent_ui/src/message_editor.rs | 4 +++ crates/agent_ui/src/ui/mention_crease.rs | 26 ++++++++++++--- 6 files changed, 80 insertions(+), 7 deletions(-) diff --git a/crates/acp_thread/src/mention.rs b/crates/acp_thread/src/mention.rs index 5769d13860f2466f95fe7dd67c1f908812e40c2d..b63eec154a40de8909d13de2a4e1bd3e9d1e06f3 100644 --- a/crates/acp_thread/src/mention.rs +++ b/crates/acp_thread/src/mention.rs @@ -254,6 +254,41 @@ impl MentionUri { } } + pub fn tooltip_text(&self) -> Option { + match self { + MentionUri::File { abs_path } | MentionUri::Directory { abs_path } => { + Some(abs_path.to_string_lossy().into_owned().into()) + } + MentionUri::Symbol { + abs_path, + line_range, + .. + } => Some( + format!( + "{}:{}-{}", + abs_path.display(), + line_range.start(), + line_range.end() + ) + .into(), + ), + MentionUri::Selection { + abs_path: Some(path), + line_range, + .. + } => Some( + format!( + "{}:{}-{}", + path.display(), + line_range.start(), + line_range.end() + ) + .into(), + ), + _ => None, + } + } + pub fn icon_path(&self, cx: &mut App) -> SharedString { match self { MentionUri::File { abs_path } => { diff --git a/crates/agent_ui/src/completion_provider.rs b/crates/agent_ui/src/completion_provider.rs index 802af37eb7f6700eec376327c19da8aab9b9416f..30778909b2c9a91dab0b20417e973b7e83ea6a17 100644 --- a/crates/agent_ui/src/completion_provider.rs +++ b/crates/agent_ui/src/completion_provider.rs @@ -617,6 +617,7 @@ impl PromptCompletionProvider { let crease = crate::mention_set::crease_for_mention( mention_uri.name().into(), mention_uri.icon_path(cx), + None, range, editor.downgrade(), ); diff --git a/crates/agent_ui/src/inline_prompt_editor.rs b/crates/agent_ui/src/inline_prompt_editor.rs index 11e8e59999c59f2ca4eeaccb17a5674a9c1757d9..0450efc4b7ebf466d0b9b13f516249a2cba0ecfa 100644 --- a/crates/agent_ui/src/inline_prompt_editor.rs +++ b/crates/agent_ui/src/inline_prompt_editor.rs @@ -1632,6 +1632,7 @@ fn insert_message_creases( crease_for_mention( crease.label.clone(), crease.icon_path.clone(), + None, start..end, cx.weak_entity(), ) diff --git a/crates/agent_ui/src/mention_set.rs b/crates/agent_ui/src/mention_set.rs index 3b2a65372de957ec57577108e4acea1ab2e9944e..58e7e4cdfc196862bb3b8936f8582ba1ad54bda5 100644 --- a/crates/agent_ui/src/mention_set.rs +++ b/crates/agent_ui/src/mention_set.rs @@ -233,6 +233,7 @@ impl MentionSet { content_len, mention_uri.name().into(), IconName::Image.path().into(), + mention_uri.tooltip_text(), Some(image), editor.clone(), window, @@ -245,6 +246,7 @@ impl MentionSet { content_len, crease_text, mention_uri.icon_path(cx), + mention_uri.tooltip_text(), None, editor.clone(), window, @@ -485,6 +487,7 @@ impl MentionSet { let crease = crease_for_mention( selection_name(abs_path.as_deref(), &line_range).into(), uri.icon_path(cx), + uri.tooltip_text(), range, editor.downgrade(), ); @@ -695,6 +698,7 @@ pub(crate) async fn insert_images_as_context( content_len, MentionUri::PastedImage.name().into(), IconName::Image.path().into(), + None, Some(Task::ready(Ok(image.clone())).shared()), editor.clone(), window, @@ -805,7 +809,7 @@ pub(crate) fn insert_crease_for_mention( content_len: usize, crease_label: SharedString, crease_icon: SharedString, - // abs_path: Option>, + crease_tooltip: Option, image: Option, String>>>>, editor: Entity, window: &mut Window, @@ -825,6 +829,7 @@ pub(crate) fn insert_crease_for_mention( render: render_mention_fold_button( crease_label.clone(), crease_icon.clone(), + crease_tooltip, start..end, rx, image, @@ -858,11 +863,12 @@ pub(crate) fn insert_crease_for_mention( pub(crate) fn crease_for_mention( label: SharedString, icon_path: SharedString, + tooltip: Option, range: Range, editor_entity: WeakEntity, ) -> Crease { let placeholder = FoldPlaceholder { - render: render_fold_icon_button(icon_path.clone(), label.clone(), editor_entity), + render: render_fold_icon_button(icon_path.clone(), label.clone(), tooltip, editor_entity), merge_adjacent: false, ..Default::default() }; @@ -876,6 +882,7 @@ pub(crate) fn crease_for_mention( fn render_fold_icon_button( icon_path: SharedString, label: SharedString, + tooltip: Option, editor: WeakEntity, ) -> Arc, &mut App) -> AnyElement> { Arc::new({ @@ -886,6 +893,9 @@ fn render_fold_icon_button( MentionCrease::new(fold_id, icon_path.clone(), label.clone()) .is_toggled(is_in_text_selection) + .when_some(tooltip.clone(), |this, tooltip_text| { + this.tooltip(tooltip_text) + }) .into_any_element() } }) @@ -1018,6 +1028,7 @@ fn render_directory_contents(entries: Vec<(Arc, String, String)>) -> St fn render_mention_fold_button( label: SharedString, icon: SharedString, + tooltip: Option, range: Range, mut loading_finished: postage::barrier::Receiver, image_task: Option, String>>>>, @@ -1037,6 +1048,7 @@ fn render_mention_fold_button( id: cx.entity_id(), label, icon, + tooltip, range, editor, loading: Some(loading), @@ -1050,6 +1062,7 @@ struct LoadingContext { id: EntityId, label: SharedString, icon: SharedString, + tooltip: Option, range: Range, editor: WeakEntity, loading: Option>, @@ -1068,6 +1081,9 @@ impl Render for LoadingContext { MentionCrease::new(id, self.icon.clone(), self.label.clone()) .is_toggled(is_in_text_selection) .is_loading(self.loading.is_some()) + .when_some(self.tooltip.clone(), |this, tooltip_text| { + this.tooltip(tooltip_text) + }) .when_some(self.image.clone(), |this, image_task| { this.image_preview(move |_, cx| { let image = image_task.peek().cloned().transpose().ok().flatten(); diff --git a/crates/agent_ui/src/message_editor.rs b/crates/agent_ui/src/message_editor.rs index bf6e753c884fa2434b4fa0f95ff7530cb0ab31bd..a24a5f5f65dae3f8bbce7d0a7b7f4988a1bd5e38 100644 --- a/crates/agent_ui/src/message_editor.rs +++ b/crates/agent_ui/src/message_editor.rs @@ -690,6 +690,7 @@ impl MessageEditor { content_len, crease_text.into(), mention_uri.icon_path(cx), + mention_uri.tooltip_text(), None, self.editor.clone(), window, @@ -800,6 +801,7 @@ impl MessageEditor { content_len, mention_uri.name().into(), mention_uri.icon_path(cx), + mention_uri.tooltip_text(), None, self.editor.clone(), window, @@ -980,6 +982,7 @@ impl MessageEditor { content_len, mention_uri.name().into(), mention_uri.icon_path(cx), + mention_uri.tooltip_text(), None, self.editor.clone(), window, @@ -1285,6 +1288,7 @@ impl MessageEditor { range.end - range.start, mention_uri.name().into(), mention_uri.icon_path(cx), + mention_uri.tooltip_text(), None, self.editor.clone(), window, diff --git a/crates/agent_ui/src/ui/mention_crease.rs b/crates/agent_ui/src/ui/mention_crease.rs index 013d6659493bd0930d132a662d374f60ca47961f..2d464039dc552203ad76979239673ec27d5568c7 100644 --- a/crates/agent_ui/src/ui/mention_crease.rs +++ b/crates/agent_ui/src/ui/mention_crease.rs @@ -3,7 +3,7 @@ use std::time::Duration; use gpui::{Animation, AnimationExt, AnyView, IntoElement, Window, pulsating_between}; use settings::Settings; use theme::ThemeSettings; -use ui::{ButtonLike, TintColor, prelude::*}; +use ui::{ButtonLike, TintColor, Tooltip, prelude::*}; #[derive(IntoElement)] pub struct MentionCrease { @@ -12,6 +12,7 @@ pub struct MentionCrease { label: SharedString, is_toggled: bool, is_loading: bool, + tooltip: Option, image_preview: Option AnyView + 'static>>, } @@ -27,6 +28,7 @@ impl MentionCrease { label: label.into(), is_toggled: false, is_loading: false, + tooltip: None, image_preview: None, } } @@ -41,6 +43,11 @@ impl MentionCrease { self } + pub fn tooltip(mut self, tooltip: impl Into) -> Self { + self.tooltip = Some(tooltip.into()); + self + } + pub fn image_preview( mut self, builder: impl Fn(&mut Window, &mut App) -> AnyView + 'static, @@ -55,6 +62,9 @@ impl RenderOnce for MentionCrease { let settings = ThemeSettings::get_global(cx); let font_size = settings.agent_buffer_font_size(cx); let buffer_font = settings.buffer_font.clone(); + let is_loading = self.is_loading; + let tooltip = self.tooltip; + let image_preview = self.image_preview; let button_height = DefiniteLength::Absolute(AbsoluteLength::Pixels( px(window.line_height().into()) - px(1.), @@ -66,9 +76,6 @@ impl RenderOnce for MentionCrease { .height(button_height) .selected_style(ButtonStyle::Tinted(TintColor::Accent)) .toggle_state(self.is_toggled) - .when_some(self.image_preview, |this, image_preview| { - this.hoverable_tooltip(image_preview) - }) .child( h_flex() .pb_px() @@ -82,7 +89,7 @@ impl RenderOnce for MentionCrease { ) .child(self.label.clone()) .map(|this| { - if self.is_loading { + if is_loading { this.with_animation( "loading-context-crease", Animation::new(Duration::from_secs(2)) @@ -96,5 +103,14 @@ impl RenderOnce for MentionCrease { } }), ) + .map(|button| { + if let Some(image_preview) = image_preview { + button.hoverable_tooltip(image_preview) + } else { + button.when_some(tooltip, |this, tooltip_text| { + this.tooltip(Tooltip::text(tooltip_text)) + }) + } + }) } }