aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helix-lsp/src/client.rs14
-rw-r--r--helix-lsp/src/lib.rs7
-rw-r--r--helix-term/src/application.rs48
-rw-r--r--helix-term/src/commands.rs33
4 files changed, 89 insertions, 13 deletions
diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs
index 271fd9d5..f1de8752 100644
--- a/helix-lsp/src/client.rs
+++ b/helix-lsp/src/client.rs
@@ -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,16 @@ impl Client {
let response = self.request::<lsp::request::Rename>(params).await?;
Ok(response.unwrap_or_default())
}
+
+ pub fn command(&self, command: lsp::Command) -> impl Future<Output = Result<Value>> {
+ let params = lsp::ExecuteCommandParams {
+ command: command.command,
+ arguments: command.arguments.unwrap_or_default(),
+ work_done_progress_params: lsp::WorkDoneProgressParams {
+ work_done_token: None,
+ },
+ };
+
+ self.call::<lsp::request::ExecuteCommand>(params)
+ }
}
diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs
index 15cae582..8fb321bc 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 3e0b6d59..9a46a7fe 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -1,8 +1,12 @@
use helix_core::{merge_toml_values, syntax};
use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
use helix_view::{theme, Editor};
+use serde_json::json;
-use crate::{args::Args, compositor::Compositor, config::Config, job::Jobs, ui};
+use crate::{
+ args::Args, commands::apply_workspace_edit, compositor::Compositor, config::Config, job::Jobs,
+ ui,
+};
use log::{error, warn};
@@ -530,14 +534,6 @@ impl Application {
Call::MethodCall(helix_lsp::jsonrpc::MethodCall {
method, params, id, ..
}) => {
- let language_server = match self.editor.language_servers.get_by_id(server_id) {
- Some(language_server) => language_server,
- None => {
- warn!("can't find language server with id `{}`", server_id);
- return;
- }
- };
-
let call = match MethodCall::parse(&method, params) {
Some(call) => call,
None => {
@@ -567,8 +563,42 @@ impl Application {
if spinner.is_stopped() {
spinner.start();
}
+ let language_server =
+ match self.editor.language_servers.get_by_id(server_id) {
+ Some(language_server) => language_server,
+ None => {
+ warn!("can't find language server with id `{}`", server_id);
+ return;
+ }
+ };
+
tokio::spawn(language_server.reply(id, Ok(serde_json::Value::Null)));
}
+ MethodCall::ApplyWorkspaceEdit(params) => {
+ apply_workspace_edit(
+ &mut self.editor,
+ helix_lsp::OffsetEncoding::Utf8,
+ &params.edit,
+ );
+
+ let language_server =
+ match self.editor.language_servers.get_by_id(server_id) {
+ Some(language_server) => language_server,
+ None => {
+ warn!("can't find language server with id `{}`", server_id);
+ return;
+ }
+ };
+
+ tokio::spawn(language_server.reply(
+ id,
+ Ok(json!(lsp::ApplyWorkspaceEditResponse {
+ applied: true,
+ failure_reason: None,
+ failed_change: None,
+ })),
+ ));
+ }
}
}
e => unreachable!("{:?}", e),
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 297b49a1..ee6a5989 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -3277,12 +3277,19 @@ pub fn code_action(cx: &mut Context) {
move |editor, code_action, _action| match code_action {
lsp::CodeActionOrCommand::Command(command) => {
log::debug!("code action command: {:?}", command);
- editor.set_error(String::from("Handling code action command is not implemented yet, see https://github.com/helix-editor/helix/issues/183"));
+ execute_lsp_command(editor, command.clone());
}
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(command) = &code_action.command {
+ execute_lsp_command(editor, command.clone());
}
}
},
@@ -3293,6 +3300,26 @@ pub fn code_action(cx: &mut Context) {
)
}
+pub fn execute_lsp_command(editor: &mut Editor, cmd: lsp::Command) {
+ let (_view, doc) = current!(editor);
+
+ let language_server = match doc.language_server() {
+ Some(language_server) => language_server,
+ None => return,
+ };
+
+ // the command is executed on the server and communicated back
+ // to the client asynchronously using workspace edits
+ let command_future = language_server.command(cmd);
+ tokio::spawn(async move {
+ let res = command_future.await;
+
+ if let Err(e) = res {
+ log::error!("execute LSP command: {}", e);
+ }
+ });
+}
+
pub fn apply_document_resource_op(op: &lsp::ResourceOp) -> std::io::Result<()> {
use lsp::ResourceOp;
use std::fs;
@@ -3346,7 +3373,7 @@ pub fn apply_document_resource_op(op: &lsp::ResourceOp) -> std::io::Result<()> {
}
}
-fn apply_workspace_edit(
+pub fn apply_workspace_edit(
editor: &mut Editor,
offset_encoding: OffsetEncoding,
workspace_edit: &lsp::WorkspaceEdit,