Add better labels for completions for ty lsp (#42233)

Caleb Van Dyke created

Verified that this works locally. I modeled it after how basedpyright
and pyright work. Here is a screenshot of what it looks like (issue has
screenshots of the old state):

<img width="593" height="258" alt="Screenshot 2025-11-07 at 2 40 50 PM"
src="https://github.com/user-attachments/assets/5d2371fc-360b-422f-ba59-0a95f2083c87"
/>

Closes #42232

Release Notes:

- python/ty: Code completion menu now shows packages that will be
imported when a given entry is accepted.

Change summary

crates/languages/src/python.rs | 39 ++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)

Detailed changes

crates/languages/src/python.rs 🔗

@@ -163,6 +163,45 @@ impl LspAdapter for TyLspAdapter {
         Self::SERVER_NAME
     }
 
+    async fn label_for_completion(
+        &self,
+        item: &lsp::CompletionItem,
+        language: &Arc<language::Language>,
+    ) -> Option<language::CodeLabel> {
+        let label = &item.label;
+        let label_len = label.len();
+        let grammar = language.grammar()?;
+        let highlight_id = match item.kind? {
+            lsp::CompletionItemKind::METHOD => grammar.highlight_id_for_name("function.method"),
+            lsp::CompletionItemKind::FUNCTION => grammar.highlight_id_for_name("function"),
+            lsp::CompletionItemKind::CLASS => grammar.highlight_id_for_name("type"),
+            lsp::CompletionItemKind::CONSTANT => grammar.highlight_id_for_name("constant"),
+            lsp::CompletionItemKind::VARIABLE => grammar.highlight_id_for_name("variable"),
+            _ => {
+                return None;
+            }
+        };
+
+        let mut text = label.clone();
+        if let Some(completion_details) = item
+            .label_details
+            .as_ref()
+            .and_then(|details| details.detail.as_ref())
+        {
+            write!(&mut text, " {}", completion_details).ok();
+        }
+
+        Some(language::CodeLabel::filtered(
+            text,
+            label_len,
+            item.filter_text.as_deref(),
+            highlight_id
+                .map(|id| (0..label_len, id))
+                .into_iter()
+                .collect(),
+        ))
+    }
+
     async fn workspace_configuration(
         self: Arc<Self>,
         delegate: &Arc<dyn LspAdapterDelegate>,