aboutsummaryrefslogtreecommitdiff
path: root/helix-term
diff options
context:
space:
mode:
authorMichael Davis2022-10-22 01:04:50 +0000
committerGitHub2022-10-22 01:04:50 +0000
commitd7d0d5ffb79b6f2e09c6ab8af6e112c41e6f73e8 (patch)
tree5078c81ef786f29d9739ec4cd65d87eae83b2e71 /helix-term
parent17daf6ac0a1a7ef4a44078ef11cc150a8fa41ff0 (diff)
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.
Diffstat (limited to 'helix-term')
-rw-r--r--helix-term/src/ui/completion.rs21
-rw-r--r--helix-term/src/ui/editor.rs13
-rw-r--r--helix-term/src/ui/menu.rs8
3 files changed, 38 insertions, 4 deletions
diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs
index 7348dcf4..a21767f9 100644
--- a/helix-term/src/ui/completion.rs
+++ b/helix-term/src/ui/completion.rs
@@ -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 {
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index 43b1e7a0..b1bb02c7 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -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);
}
diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs
index 4b1155e3..75769b90 100644
--- a/helix-term/src/ui/menu.rs
+++ b/helix-term/src/ui/menu.rs
@@ -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()
}