From 8977123f25baba838d2d16f8a40e78563c4ebf4a Mon Sep 17 00:00:00 2001
From: sigmaSd <bedisnbiba@gmail.com>
Date: Fri, 21 Jul 2023 20:50:08 +0100
Subject: [PATCH] feat: resolve code action (#7677)

---
 helix-lsp/src/client.rs        | 29 +++++++++++++++++++++++++++--
 helix-term/src/commands/lsp.rs | 15 ++++++++++++++-
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs
index a3711317ae9c..92ab03db7539 100644
--- a/helix-lsp/src/client.rs
+++ b/helix-lsp/src/client.rs
@@ -7,8 +7,9 @@ use crate::{
 use helix_core::{find_workspace, path, syntax::LanguageServerFeature, ChangeSet, Rope};
 use helix_loader::{self, VERSION_AND_GIT_HASH};
 use lsp::{
-    notification::DidChangeWorkspaceFolders, DidChangeWorkspaceFoldersParams, OneOf,
-    PositionEncodingKind, WorkspaceFolder, WorkspaceFoldersChangeEvent,
+    notification::DidChangeWorkspaceFolders, CodeActionCapabilityResolveSupport,
+    DidChangeWorkspaceFoldersParams, OneOf, PositionEncodingKind, WorkspaceFolder,
+    WorkspaceFoldersChangeEvent,
 };
 use lsp_types as lsp;
 use parking_lot::Mutex;
@@ -609,6 +610,12 @@ impl Client {
                                 .collect(),
                             },
                         }),
+                        is_preferred_support: Some(true),
+                        disabled_support: Some(true),
+                        data_support: Some(true),
+                        resolve_support: Some(CodeActionCapabilityResolveSupport {
+                            properties: vec!["edit".to_owned(), "command".to_owned()],
+                        }),
                         ..Default::default()
                     }),
                     publish_diagnostics: Some(lsp::PublishDiagnosticsClientCapabilities {
@@ -954,6 +961,24 @@ impl Client {
         Some(self.call::<lsp::request::ResolveCompletionItem>(completion_item))
     }
 
+    pub fn resolve_code_action(
+        &self,
+        code_action: lsp::CodeAction,
+    ) -> Option<impl Future<Output = Result<Value>>> {
+        let capabilities = self.capabilities.get().unwrap();
+
+        // Return early if the server does not support resolving code action.
+        match capabilities.completion_provider {
+            Some(lsp::CompletionOptions {
+                resolve_provider: Some(true),
+                ..
+            }) => (),
+            _ => return None,
+        }
+
+        Some(self.call::<lsp::request::CodeActionResolveRequest>(code_action))
+    }
+
     pub fn text_document_signature_help(
         &self,
         text_document: lsp::TextDocumentIdentifier,
diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs
index 145bddd0f51c..1f592118014e 100644
--- a/helix-term/src/commands/lsp.rs
+++ b/helix-term/src/commands/lsp.rs
@@ -743,7 +743,20 @@ pub fn code_action(cx: &mut Context) {
                     }
                     lsp::CodeActionOrCommand::CodeAction(code_action) => {
                         log::debug!("code action: {:?}", code_action);
-                        if let Some(ref workspace_edit) = code_action.edit {
+                        // we support lsp "codeAction/resolve" for `edit` and `command` fields
+                        let mut resolved_code_action = None;
+                        if code_action.edit.is_none() || code_action.command.is_none() {
+                            if let Some(future) = language_server.resolve_code_action(code_action.clone()) {
+                                if let Ok(response) = helix_lsp::block_on(future) {
+                                    if let Ok(code_action) = serde_json::from_value::<CodeAction>(response) {
+                                        resolved_code_action = Some(code_action);
+                                    }
+                                }
+                            }
+                        }
+                        let resolved_code_action = resolved_code_action.as_ref().unwrap_or(code_action);
+
+                        if let Some(ref workspace_edit) = resolved_code_action.edit {
                             log::debug!("edit: {:?}", workspace_edit);
                             let _ = apply_workspace_edit(editor, offset_encoding, workspace_edit);
                         }