From b86781f2fafff334cdfe61786d5e07c991ab2fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Dzivjak?= Date: Sun, 19 Dec 2021 14:10:44 +0100 Subject: [PATCH] feat(lsp): codeAction commands --- helix-lsp/src/client.rs | 21 +++++++++++++++++---- helix-lsp/src/lib.rs | 7 +++++++ helix-term/src/application.rs | 10 ++++++++++ helix-term/src/commands.rs | 26 +++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 271fd9d59da0..6908d1dd30d7 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -188,11 +188,11 @@ impl Client { } /// Reply to a language server RPC call. - pub fn reply( + pub fn reply( &self, id: jsonrpc::Id, - result: core::result::Result, - ) -> impl Future> { + result: core::result::Result, + ) -> impl Future> where R: serde::Serialize { use jsonrpc::{Failure, Output, Success, Version}; let server_tx = self.server_tx.clone(); @@ -202,7 +202,7 @@ impl Client { Ok(result) => Output::Success(Success { jsonrpc: Some(Version::V2), id, - result, + result: serde_json::to_value(result)?, }), Err(error) => Output::Failure(Failure { jsonrpc: Some(Version::V2), @@ -800,4 +800,17 @@ impl Client { let response = self.request::(params).await?; Ok(response.unwrap_or_default()) } + + pub async fn command(&self, command: lsp::Command) -> anyhow::Result> { + let params = lsp::ExecuteCommandParams { + command: command.command, + arguments: command.arguments.unwrap_or_default(), + work_done_progress_params: lsp::WorkDoneProgressParams { + work_done_token: None, + }, + }; + + let response = self.call::(params).await?; + Ok(Some(response)) + } } diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 15cae582b608..8fb321bcc202 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -203,6 +203,7 @@ pub mod util { #[derive(Debug, PartialEq, Clone)] pub enum MethodCall { WorkDoneProgressCreate(lsp::WorkDoneProgressCreateParams), + ApplyWorkspaceEdit(lsp::ApplyWorkspaceEditParams), } impl MethodCall { @@ -215,6 +216,12 @@ impl MethodCall { .expect("Failed to parse WorkDoneCreate params"); Self::WorkDoneProgressCreate(params) } + lsp::request::ApplyWorkspaceEdit::METHOD => { + let params: lsp::ApplyWorkspaceEditParams = params + .parse() + .expect("Failed to parse ApplyWorkspaceEdit params"); + Self::ApplyWorkspaceEdit(params) + } _ => { log::warn!("unhandled lsp request: {}", method); return None; diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 3e0b6d59217a..7cff190b4a1d 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -569,6 +569,16 @@ impl Application { } tokio::spawn(language_server.reply(id, Ok(serde_json::Value::Null))); } + MethodCall::ApplyWorkspaceEdit(params) => { + log::debug!("Received workspace/applyEdit from LSP: {:?}", params); + // TODO: handle the edits + let resp = lsp::ApplyWorkspaceEditResponse { + applied: true, + failure_reason: None, + failed_change: None, + }; + tokio::spawn(language_server.reply(id, Ok(resp))); + } } } e => unreachable!("{:?}", e), diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index cd566720d498..bf9c6b96f7fd 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3282,7 +3282,31 @@ 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 { - apply_workspace_edit(editor, offset_encoding, workspace_edit) + log::debug!("edit: {:?}", workspace_edit); + apply_workspace_edit(editor, offset_encoding, workspace_edit); + } + // if code action provides both edit and command first the edit + // should be applied and then the command + if let Some(ref command) = code_action.command { + log::debug!("command: {:?}", command); + let (_, doc) = current!(editor); + + let language_server = match doc.language_server() { + Some(language_server) => language_server, + None => return, + }; + + // command is executed on the server, in most cases the server + // creates workspace edit so we just block here and wait + // for the outbound workspace edit to resolve + match block_on(language_server.command(command.clone())) { + Ok(ref edit) => { + log::debug!("command edit: {:?}", edit); + }, + Err(e) => { + log::error!("call LSP command: {:?}", e); + }, + } } } },