From be742a587704f27f4e503c50f549aa9ec1527fcc Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 13 Aug 2018 02:38:34 +0300 Subject: Apply code actions --- crates/server/src/main_loop/handlers.rs | 72 +++++++++++++++++++++++++++++---- crates/server/src/main_loop/mod.rs | 46 +++++++++++++-------- 2 files changed, 93 insertions(+), 25 deletions(-) (limited to 'crates/server/src/main_loop') diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index c6db22289..d4ae2a368 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs @@ -1,15 +1,18 @@ +use std::collections::HashMap; + use languageserver_types::{ Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, - Command + Command, TextDocumentIdentifier, WorkspaceEdit }; use libanalysis::World; use libeditor; -use serde_json::to_value; +use libsyntax2::TextUnit; +use serde_json::{to_value, from_value}; use ::{ req::{self, Decoration}, Result, util::FilePath, - conv::{Conv, ConvWith}, + conv::{Conv, ConvWith, MapConvWith}, }; pub fn handle_syntax_tree( @@ -29,9 +32,9 @@ pub fn handle_extend_selection( let file = world.file_syntax(&path)?; let line_index = world.file_line_index(&path)?; let selections = params.selections.into_iter() - .map(|r| r.conv_with(&line_index)) + .map_conv_with(&line_index) .map(|r| libeditor::extend_selection(&file, r).unwrap_or(r)) - .map(|r| r.conv_with(&line_index)) + .map_conv_with(&line_index) .collect(); Ok(req::ExtendSelectionResult { selections }) } @@ -78,18 +81,71 @@ pub fn handle_code_action( let line_index = world.file_line_index(&path)?; let offset = params.range.conv_with(&line_index).start(); let ret = if libeditor::flip_comma(&file, offset).is_some() { - Some(vec![apply_code_action_cmd(ActionId::FlipComma)]) + let cmd = apply_code_action_cmd( + ActionId::FlipComma, + params.text_document, + offset, + ); + Some(vec![cmd]) } else { None }; Ok(ret) } -fn apply_code_action_cmd(id: ActionId) -> Command { +pub fn handle_execute_command( + world: World, + mut params: req::ExecuteCommandParams, +) -> Result { + if params.command.as_str() != "apply_code_action" { + bail!("unknown cmd: {:?}", params.command); + } + if params.arguments.len() != 1 { + bail!("expected single arg, got {}", params.arguments.len()); + } + let arg = params.arguments.pop().unwrap(); + let arg: ActionRequest = from_value(arg)?; + match arg.id { + ActionId::FlipComma => { + let path = arg.text_document.file_path()?; + let file = world.file_syntax(&path)?; + let line_index = world.file_line_index(&path)?; + let edit = match libeditor::flip_comma(&file, arg.offset) { + Some(edit) => edit(), + None => bail!("command not applicable"), + }; + let mut changes = HashMap::new(); + changes.insert( + arg.text_document.uri, + edit.conv_with(&line_index), + ); + let edit = WorkspaceEdit { + changes: Some(changes), + document_changes: None, + }; + + Ok(req::ApplyWorkspaceEditParams { edit }) + } + } +} + +#[derive(Serialize, Deserialize)] +struct ActionRequest { + id: ActionId, + text_document: TextDocumentIdentifier, + offset: TextUnit, +} + +fn apply_code_action_cmd(id: ActionId, doc: TextDocumentIdentifier, offset: TextUnit) -> Command { + let action_request = ActionRequest { + id, + text_document: doc, + offset, + }; Command { title: id.title().to_string(), command: "apply_code_action".to_string(), - arguments: Some(vec![to_value(id).unwrap()]), + arguments: Some(vec![to_value(action_request).unwrap()]), } } diff --git a/crates/server/src/main_loop/mod.rs b/crates/server/src/main_loop/mod.rs index 3d367f5f6..5b7093ad7 100644 --- a/crates/server/src/main_loop/mod.rs +++ b/crates/server/src/main_loop/mod.rs @@ -6,6 +6,7 @@ use threadpool::ThreadPool; use crossbeam_channel::{Sender, Receiver}; use languageserver_types::Url; use libanalysis::{World, WorldState}; +use serde_json::to_value; use { req, dispatch, @@ -19,6 +20,7 @@ use { publish_decorations, handle_document_symbol, handle_code_action, + handle_execute_command, }, }; @@ -79,7 +81,9 @@ pub(super) fn main_loop( on_notification(io, world, pool, &sender, not)? } RawMsg::Response(resp) => { - error!("unexpected response: {:?}", resp) + if !pending_requests.remove(&resp.id) { + error!("unexpected response: {:?}", resp) + } } } } @@ -107,22 +111,30 @@ fn on_request( handle_request_on_threadpool::( &mut req, pool, world, sender, handle_code_action, )?; -// dispatch::handle_request::(&mut req, |(), resp| { -// let world = world.snapshot(); -// let sender = sender.clone(); -// pool.execute(move || { -// let task = match handle_execute_command(world, params) { -// Ok(req) => Task::Request(req), -// Err(e) => Task::Die(e), -// }; -// sender.send(task) -// }); -// -// let resp = resp.into_response(Ok(()))?; -// io.send(RawMsg::Response(resp)); -// shutdown = true; -// Ok(()) -// })?; + dispatch::handle_request::(&mut req, |params, resp| { + io.send(RawMsg::Response(resp.into_response(Ok(None))?)); + + let world = world.snapshot(); + let sender = sender.clone(); + pool.execute(move || { + let task = match handle_execute_command(world, params) { + Ok(req) => match to_value(req) { + Err(e) => Task::Die(e.into()), + Ok(params) => { + let request = RawRequest { + id: 0, + method: ::METHOD.to_string(), + params, + }; + Task::Request(request) + } + }, + Err(e) => Task::Die(e), + }; + sender.send(task) + }); + Ok(()) + })?; let mut shutdown = false; dispatch::handle_request::(&mut req, |(), resp| { -- cgit v1.2.3