agent_ui: Add file name and line number to symbol completions (#40508)

Paweł Kondzior created

Symbol completions in the context picker now show "SymbolName
filename.txt L123" instead of just "SymbolName". This helps distinguish
between symbols with the same name in different files.

## Motivation

I noticed that the message prompt editor only showed symbol names
without any context, making it hard to use in large projects with many
symbols sharing the same name. The inline prompt editor already includes
file context for symbol completions, so I brought that same UX
improvement to the message prompt editor. I've decided to match the
highlighting style with directory completion entries from the message
editor.

## Changes

- Extract file name from both InProject and OutsideProject symbol
locations
- Add `build_symbol_label` helper to format labels with file context
- Update test expectation for new label format

## Screenshots
Inline Prompt Editor
<img width="843" height="334" alt="Screenshot 2025-10-17 at 17 47 52"
src="https://github.com/user-attachments/assets/16752e1a-0b8c-4f58-a0b2-25ae5130f18c"
/>
Old Message Editor:
<img width="466" height="363" alt="Screenshot 2025-10-17 at 17 31 44"
src="https://github.com/user-attachments/assets/900659f3-0632-4dff-bc9a-ab2dad351964"
/>
New Message Editor:
<img width="482" height="359" alt="Screenshot 2025-10-17 at 17 31 23"
src="https://github.com/user-attachments/assets/bf382167-f88b-4f3d-ba3e-1e251a8df962"
/>


Release Notes:

- Added file names and line numbers to symbol completions in the agent
panel

Change summary

crates/agent_ui/src/acp/completion_provider.rs | 30 +++++++++++++++----
crates/agent_ui/src/acp/message_editor.rs      |  2 
2 files changed, 24 insertions(+), 8 deletions(-)

Detailed changes

crates/agent_ui/src/acp/completion_provider.rs 🔗

@@ -253,17 +253,22 @@ impl ContextPickerCompletionProvider {
     ) -> Option<Completion> {
         let project = workspace.read(cx).project().clone();
 
-        let label = CodeLabel::plain(symbol.name.clone(), None);
-
-        let abs_path = match &symbol.path {
-            SymbolLocation::InProject(project_path) => {
-                project.read(cx).absolute_path(&project_path, cx)?
-            }
+        let (abs_path, file_name) = match &symbol.path {
+            SymbolLocation::InProject(project_path) => (
+                project.read(cx).absolute_path(&project_path, cx)?,
+                project_path.path.file_name()?.to_string().into(),
+            ),
             SymbolLocation::OutsideProject {
                 abs_path,
                 signature: _,
-            } => PathBuf::from(abs_path.as_ref()),
+            } => (
+                PathBuf::from(abs_path.as_ref()),
+                abs_path.file_name().map(|f| f.to_string_lossy())?,
+            ),
         };
+
+        let label = build_symbol_label(&symbol.name, &file_name, symbol.range.start.0.row + 1, cx);
+
         let uri = MentionUri::Symbol {
             abs_path,
             name: symbol.name.clone(),
@@ -674,6 +679,17 @@ impl ContextPickerCompletionProvider {
     }
 }
 
+fn build_symbol_label(symbol_name: &str, file_name: &str, line: u32, cx: &App) -> CodeLabel {
+    let comment_id = cx.theme().syntax().highlight_id("comment").map(HighlightId);
+    let mut label = CodeLabelBuilder::default();
+
+    label.push_str(symbol_name, None);
+    label.push_str(" ", None);
+    label.push_str(&format!("{} L{}", file_name, line), comment_id);
+
+    label.build()
+}
+
 fn build_code_label_for_full_path(file_name: &str, directory: Option<&str>, cx: &App) -> CodeLabel {
     let comment_id = cx.theme().syntax().highlight_id("comment").map(HighlightId);
     let mut label = CodeLabelBuilder::default();

crates/agent_ui/src/acp/message_editor.rs 🔗

@@ -2473,7 +2473,7 @@ mod tests {
                 format!("Lorem [@one.txt]({url_one})  Ipsum [@eight.txt]({url_eight}) @symbol ")
             );
             assert!(editor.has_visible_completions_menu());
-            assert_eq!(current_completion_labels(editor), &["MySymbol"]);
+            assert_eq!(current_completion_labels(editor), &["MySymbol one.txt L1"]);
         });
 
         editor.update_in(&mut cx, |editor, window, cx| {