aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helix-lsp/src/client.rs7
-rw-r--r--helix-term/src/ui/completion.rs48
-rw-r--r--helix-term/src/ui/menu.rs11
3 files changed, 52 insertions, 14 deletions
diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs
index 50c4b87f..424cbabf 100644
--- a/helix-lsp/src/client.rs
+++ b/helix-lsp/src/client.rs
@@ -650,12 +650,11 @@ impl Client {
self.call::<lsp::request::Completion>(params)
}
- pub async fn resolve_completion_item(
+ pub fn resolve_completion_item(
&self,
completion_item: lsp::CompletionItem,
- ) -> Result<lsp::CompletionItem> {
- self.request::<lsp::request::ResolveCompletionItem>(completion_item)
- .await
+ ) -> impl Future<Output = Result<Value>> {
+ self.call::<lsp::request::ResolveCompletionItem>(completion_item)
}
pub fn text_document_signature_help(
diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs
index 229dcda1..4e6ee424 100644
--- a/helix-term/src/ui/completion.rs
+++ b/helix-term/src/ui/completion.rs
@@ -257,7 +257,7 @@ impl Completion {
let future = language_server.resolve_completion_item(completion_item);
let response = helix_lsp::block_on(future);
match response {
- Ok(completion_item) => Some(completion_item),
+ Ok(value) => serde_json::from_value(value).ok(),
Err(err) => {
log::error!("execute LSP command: {}", err);
None
@@ -304,6 +304,12 @@ impl Completion {
self.popup.contents().is_empty()
}
+ fn replace_item(&mut self, old_item: lsp::CompletionItem, new_item: lsp::CompletionItem) {
+ self.popup.contents_mut().replace_option(old_item, new_item);
+ }
+
+ /// Asynchronously requests that the currently selection completion item is
+ /// resolved through LSP `completionItem/resolve`.
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. ...
@@ -313,16 +319,38 @@ impl Completion {
// > '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;
+ let current_item = match self.popup.contents().selection() {
+ Some(item) if item.documentation.is_none() => item.clone(),
+ _ => return false,
+ };
+
+ let language_server = match doc!(cx.editor).language_server() {
+ Some(language_server) => language_server,
+ None => return false,
+ };
+
+ // This method should not block the compositor so we handle the response asynchronously.
+ let future = language_server.resolve_completion_item(current_item.clone());
+
+ cx.callback(
+ future,
+ move |_editor, compositor, response: Option<lsp::CompletionItem>| {
+ let resolved_item = match response {
+ Some(item) => item,
+ None => return,
+ };
+
+ if let Some(completion) = &mut compositor
+ .find::<crate::ui::EditorView>()
+ .unwrap()
+ .completion
+ {
+ completion.replace_item(current_item, resolved_item);
}
- true
- }
- _ => false,
- }
+ },
+ );
+
+ true
}
}
diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs
index 961b7451..b9c1f9de 100644
--- a/helix-term/src/ui/menu.rs
+++ b/helix-term/src/ui/menu.rs
@@ -224,6 +224,17 @@ impl<T: Item> Menu<T> {
}
}
+impl<T: Item + PartialEq> Menu<T> {
+ pub fn replace_option(&mut self, old_option: T, new_option: T) {
+ for option in &mut self.options {
+ if old_option == *option {
+ *option = new_option;
+ break;
+ }
+ }
+ }
+}
+
use super::PromptEvent as MenuEvent;
impl<T: Item + 'static> Component for Menu<T> {