Skip to content

Commit 196a68e

Browse files
committed
[ty] Render import <...> in completions when "label details" isn't supported
This fixes a bug where the `import module` part of a completion for unimported candidates would be missing. This makes it especially confusing because the user can't tell where the symbol is coming from, and there is no hint that an `import` statement will be inserted. Previously, we were using [`CompletionItemLabelDetails`] to render the `import module` part of the suggestion. But this is only supported in clients that support version 3.17 (or newer) of the LSP specification. It turns out that this support isn't widespread yet. In particular, Heliex doesn't seem to support "label details." To fix this, we take a [cue from rust-analyzer][rust-analyzer-details]. We detect if the client supports "label details," and if so, use it. Otherwise, we push the `import module` text into the completion label itself. Fixes #20439 (comment) [`CompletionItemLabelDetails`]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItemLabelDetails [rust-analyzer-details]: https://github.com/rust-lang/rust-analyzer/blob/5d905576d49233ed843bb40df4ed57e5534558f5/crates/rust-analyzer/src/lsp/to_proto.rs#L391-L404
1 parent 3490611 commit 196a68e

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

crates/ty_server/src/capabilities.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ bitflags::bitflags! {
3636
const DIAGNOSTIC_DYNAMIC_REGISTRATION = 1 << 14;
3737
const WORKSPACE_CONFIGURATION = 1 << 15;
3838
const RENAME_DYNAMIC_REGISTRATION = 1 << 16;
39+
const COMPLETION_ITEM_LABEL_DETAILS_SUPPORT = 1 << 17;
3940
}
4041
}
4142

@@ -158,6 +159,11 @@ impl ResolvedClientCapabilities {
158159
self.contains(Self::RENAME_DYNAMIC_REGISTRATION)
159160
}
160161

162+
/// Returns `true` if the client supports "label details" in completion items.
163+
pub(crate) const fn supports_completion_item_label_details(self) -> bool {
164+
self.contains(Self::COMPLETION_ITEM_LABEL_DETAILS_SUPPORT)
165+
}
166+
161167
pub(super) fn new(client_capabilities: &ClientCapabilities) -> Self {
162168
let mut flags = Self::empty();
163169

@@ -314,6 +320,15 @@ impl ResolvedClientCapabilities {
314320
flags |= Self::WORK_DONE_PROGRESS;
315321
}
316322

323+
if text_document
324+
.and_then(|text_document| text_document.completion.as_ref())
325+
.and_then(|completion| completion.completion_item.as_ref())
326+
.and_then(|completion_item| completion_item.label_details_support)
327+
.unwrap_or_default()
328+
{
329+
flags |= Self::COMPLETION_ITEM_LABEL_DETAILS_SUPPORT;
330+
}
331+
317332
flags
318333
}
319334
}

crates/ty_server/src/server/api/requests/completion.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,30 @@ impl BackgroundDocumentRequestHandler for CompletionRequestHandler {
8181
new_text: edit.content().map(ToString::to_string).unwrap_or_default(),
8282
}
8383
});
84+
85+
let name = comp.name.to_string();
86+
let import_suffix = comp.module_name.map(|name| format!(" (import {name})"));
87+
let (label, label_details) = if snapshot
88+
.resolved_client_capabilities()
89+
.supports_completion_item_label_details()
90+
{
91+
let label_details = CompletionItemLabelDetails {
92+
detail: import_suffix,
93+
description: type_display.clone(),
94+
};
95+
(name, Some(label_details))
96+
} else {
97+
let label = import_suffix
98+
.map(|suffix| format!("{name}{suffix}"))
99+
.unwrap_or_else(|| name);
100+
(label, None)
101+
};
84102
CompletionItem {
85-
label: comp.name.into(),
103+
label,
86104
kind,
87105
sort_text: Some(format!("{i:-max_index_len$}")),
88-
detail: type_display.clone(),
89-
label_details: Some(CompletionItemLabelDetails {
90-
detail: comp.module_name.map(|name| format!(" (import {name})")),
91-
description: type_display,
92-
}),
106+
detail: type_display,
107+
label_details,
93108
insert_text: comp.insert.map(String::from),
94109
additional_text_edits: import_edit.map(|edit| vec![edit]),
95110
documentation: comp

0 commit comments

Comments
 (0)