diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index f341bf09c90a0c270f78249133cbb7e877d66e2b..85195bfe7ae19d3540675758147d3487d144b02e 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -1913,12 +1913,13 @@ impl CodeLabel { let runs = highlight_id .map(|highlight_id| vec![(0..label_length, highlight_id)]) .unwrap_or_default(); - let text = if let Some(detail) = &item.detail { + let text = if let Some(detail) = item.detail.as_deref().filter(|detail| detail != label) { format!("{label} {detail}") } else if let Some(description) = item .label_details .as_ref() - .and_then(|label_details| label_details.description.as_ref()) + .and_then(|label_details| label_details.description.as_deref()) + .filter(|description| description != label) { format!("{label} {description}") } else { @@ -2213,4 +2214,100 @@ mod tests { // Loading an unknown language returns an error. assert!(languages.language_for_name("Unknown").await.is_err()); } + + #[gpui::test] + async fn test_completion_label_omits_duplicate_data() { + let regular_completion_item_1 = lsp::CompletionItem { + label: "regular1".to_string(), + detail: Some("detail1".to_string()), + label_details: Some(lsp::CompletionItemLabelDetails { + detail: None, + description: Some("description 1".to_string()), + }), + ..lsp::CompletionItem::default() + }; + + let regular_completion_item_2 = lsp::CompletionItem { + label: "regular2".to_string(), + label_details: Some(lsp::CompletionItemLabelDetails { + detail: None, + description: Some("description 2".to_string()), + }), + ..lsp::CompletionItem::default() + }; + + let completion_item_with_duplicate_detail_and_proper_description = lsp::CompletionItem { + detail: Some(regular_completion_item_1.label.clone()), + ..regular_completion_item_1.clone() + }; + + let completion_item_with_duplicate_detail = lsp::CompletionItem { + detail: Some(regular_completion_item_1.label.clone()), + label_details: None, + ..regular_completion_item_1.clone() + }; + + let completion_item_with_duplicate_description = lsp::CompletionItem { + label_details: Some(lsp::CompletionItemLabelDetails { + detail: None, + description: Some(regular_completion_item_2.label.clone()), + }), + ..regular_completion_item_2.clone() + }; + + assert_eq!( + CodeLabel::fallback_for_completion(®ular_completion_item_1, None).text, + format!( + "{} {}", + regular_completion_item_1.label, + regular_completion_item_1.detail.unwrap() + ), + "LSP completion items with both detail and label_details.description should prefer detail" + ); + assert_eq!( + CodeLabel::fallback_for_completion(®ular_completion_item_2, None).text, + format!( + "{} {}", + regular_completion_item_2.label, + regular_completion_item_2 + .label_details + .as_ref() + .unwrap() + .description + .as_ref() + .unwrap() + ), + "LSP completion items without detail but with label_details.description should use that" + ); + assert_eq!( + CodeLabel::fallback_for_completion( + &completion_item_with_duplicate_detail_and_proper_description, + None + ) + .text, + format!( + "{} {}", + regular_completion_item_1.label, + regular_completion_item_1 + .label_details + .as_ref() + .unwrap() + .description + .as_ref() + .unwrap() + ), + "LSP completion items with both detail and label_details.description should prefer description only if the detail duplicates the completion label" + ); + assert_eq!( + CodeLabel::fallback_for_completion(&completion_item_with_duplicate_detail, None).text, + regular_completion_item_1.label, + "LSP completion items with duplicate label and detail, should omit the detail" + ); + assert_eq!( + CodeLabel::fallback_for_completion(&completion_item_with_duplicate_description, None) + .text, + regular_completion_item_2.label, + "LSP completion items with duplicate label and detail, should omit the detail" + ); + } }