lsp: Resolve completion items missing documentation on idle (#4406)
Some language servers may not send the `documentation` field if it is expensive to compute. Clients can request the missing field with a completionItem/resolve request. In this change we use the idle-timeout event to ensure that the current completion item is resolved.
This commit is contained in:
parent
17daf6ac0a
commit
d7d0d5ffb7
3 changed files with 38 additions and 4 deletions
|
@ -295,6 +295,27 @@ impl Completion {
|
|||
pub fn is_empty(&self) -> bool {
|
||||
self.popup.contents().is_empty()
|
||||
}
|
||||
|
||||
pub fn ensure_item_resolved(&mut self, cx: &mut commands::Context) -> bool {
|
||||
// > If computing full completion items is expensive, servers can additionally provide a
|
||||
// > handler for the completion item resolve request. ...
|
||||
// > A typical use case is for example: the `textDocument/completion` request doesn't fill
|
||||
// > in the `documentation` property for returned completion items since it is expensive
|
||||
// > to compute. When the item is selected in the user interface then a
|
||||
// > 'completionItem/resolve' request is sent with the selected completion item as a parameter.
|
||||
// > The returned completion item should have the documentation property filled in.
|
||||
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
|
||||
match self.popup.contents_mut().selection_mut() {
|
||||
Some(item) if item.documentation.is_none() => {
|
||||
let doc = doc!(cx.editor);
|
||||
if let Some(resolved_item) = Self::resolve_completion_item(doc, item.clone()) {
|
||||
*item = resolved_item;
|
||||
}
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Completion {
|
||||
|
|
|
@ -1097,10 +1097,15 @@ impl EditorView {
|
|||
}
|
||||
|
||||
pub fn handle_idle_timeout(&mut self, cx: &mut commands::Context) -> EventResult {
|
||||
if self.completion.is_some()
|
||||
|| cx.editor.mode != Mode::Insert
|
||||
|| !cx.editor.config().auto_completion
|
||||
{
|
||||
if let Some(completion) = &mut self.completion {
|
||||
return if completion.ensure_item_resolved(cx) {
|
||||
EventResult::Consumed(None)
|
||||
} else {
|
||||
EventResult::Ignored(None)
|
||||
};
|
||||
}
|
||||
|
||||
if cx.editor.mode != Mode::Insert || !cx.editor.config().auto_completion {
|
||||
return EventResult::Ignored(None);
|
||||
}
|
||||
|
||||
|
|
|
@ -206,6 +206,14 @@ impl<T: Item> Menu<T> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn selection_mut(&mut self) -> Option<&mut T> {
|
||||
self.cursor.and_then(|cursor| {
|
||||
self.matches
|
||||
.get(cursor)
|
||||
.map(|(index, _score)| &mut self.options[*index])
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.matches.is_empty()
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue