Skip to content

Commit

Permalink
lsp: Resolve completion items missing documentation on idle (helix-ed…
Browse files Browse the repository at this point in the history
…itor#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.
  • Loading branch information
the-mikedavis authored and Shekhinah Memmel committed Dec 11, 2022
1 parent b1b672b commit 3a7ac80
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 4 deletions.
21 changes: 21 additions & 0 deletions helix-term/src/ui/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
13 changes: 9 additions & 4 deletions helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1099,10 +1099,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);
}

Expand Down
8 changes: 8 additions & 0 deletions helix-term/src/ui/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down

0 comments on commit 3a7ac80

Please sign in to comment.