LSP code action commands (#1304)
* feat(lsp): codeAction commands * Don't block on command call * Fix lifetime of command execution * Fix lint issues
This commit is contained in:
parent
600ce70cf6
commit
75a8b789d2
4 changed files with 89 additions and 13 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
¶ms.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),
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue