aboutsummaryrefslogtreecommitdiff
path: root/crates/server/src/main_loop
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-13 00:38:34 +0100
committerAleksey Kladov <[email protected]>2018-08-13 00:38:34 +0100
commitbe742a587704f27f4e503c50f549aa9ec1527fcc (patch)
treefb15d3dd05c64c441c9cddbbce6aee3776d6ddd1 /crates/server/src/main_loop
parent25aebb5225da91d34a2cb946f93435f9f7e82a47 (diff)
Apply code actions
Diffstat (limited to 'crates/server/src/main_loop')
-rw-r--r--crates/server/src/main_loop/handlers.rs72
-rw-r--r--crates/server/src/main_loop/mod.rs46
2 files changed, 93 insertions, 25 deletions
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 @@
1use std::collections::HashMap;
2
1use languageserver_types::{ 3use languageserver_types::{
2 Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, 4 Diagnostic, DiagnosticSeverity, Url, DocumentSymbol,
3 Command 5 Command, TextDocumentIdentifier, WorkspaceEdit
4}; 6};
5use libanalysis::World; 7use libanalysis::World;
6use libeditor; 8use libeditor;
7use serde_json::to_value; 9use libsyntax2::TextUnit;
10use serde_json::{to_value, from_value};
8 11
9use ::{ 12use ::{
10 req::{self, Decoration}, Result, 13 req::{self, Decoration}, Result,
11 util::FilePath, 14 util::FilePath,
12 conv::{Conv, ConvWith}, 15 conv::{Conv, ConvWith, MapConvWith},
13}; 16};
14 17
15pub fn handle_syntax_tree( 18pub fn handle_syntax_tree(
@@ -29,9 +32,9 @@ pub fn handle_extend_selection(
29 let file = world.file_syntax(&path)?; 32 let file = world.file_syntax(&path)?;
30 let line_index = world.file_line_index(&path)?; 33 let line_index = world.file_line_index(&path)?;
31 let selections = params.selections.into_iter() 34 let selections = params.selections.into_iter()
32 .map(|r| r.conv_with(&line_index)) 35 .map_conv_with(&line_index)
33 .map(|r| libeditor::extend_selection(&file, r).unwrap_or(r)) 36 .map(|r| libeditor::extend_selection(&file, r).unwrap_or(r))
34 .map(|r| r.conv_with(&line_index)) 37 .map_conv_with(&line_index)
35 .collect(); 38 .collect();
36 Ok(req::ExtendSelectionResult { selections }) 39 Ok(req::ExtendSelectionResult { selections })
37} 40}
@@ -78,18 +81,71 @@ pub fn handle_code_action(
78 let line_index = world.file_line_index(&path)?; 81 let line_index = world.file_line_index(&path)?;
79 let offset = params.range.conv_with(&line_index).start(); 82 let offset = params.range.conv_with(&line_index).start();
80 let ret = if libeditor::flip_comma(&file, offset).is_some() { 83 let ret = if libeditor::flip_comma(&file, offset).is_some() {
81 Some(vec![apply_code_action_cmd(ActionId::FlipComma)]) 84 let cmd = apply_code_action_cmd(
85 ActionId::FlipComma,
86 params.text_document,
87 offset,
88 );
89 Some(vec![cmd])
82 } else { 90 } else {
83 None 91 None
84 }; 92 };
85 Ok(ret) 93 Ok(ret)
86} 94}
87 95
88fn apply_code_action_cmd(id: ActionId) -> Command { 96pub fn handle_execute_command(
97 world: World,
98 mut params: req::ExecuteCommandParams,
99) -> Result<req::ApplyWorkspaceEditParams> {
100 if params.command.as_str() != "apply_code_action" {
101 bail!("unknown cmd: {:?}", params.command);
102 }
103 if params.arguments.len() != 1 {
104 bail!("expected single arg, got {}", params.arguments.len());
105 }
106 let arg = params.arguments.pop().unwrap();
107 let arg: ActionRequest = from_value(arg)?;
108 match arg.id {
109 ActionId::FlipComma => {
110 let path = arg.text_document.file_path()?;
111 let file = world.file_syntax(&path)?;
112 let line_index = world.file_line_index(&path)?;
113 let edit = match libeditor::flip_comma(&file, arg.offset) {
114 Some(edit) => edit(),
115 None => bail!("command not applicable"),
116 };
117 let mut changes = HashMap::new();
118 changes.insert(
119 arg.text_document.uri,
120 edit.conv_with(&line_index),
121 );
122 let edit = WorkspaceEdit {
123 changes: Some(changes),
124 document_changes: None,
125 };
126
127 Ok(req::ApplyWorkspaceEditParams { edit })
128 }
129 }
130}
131
132#[derive(Serialize, Deserialize)]
133struct ActionRequest {
134 id: ActionId,
135 text_document: TextDocumentIdentifier,
136 offset: TextUnit,
137}
138
139fn apply_code_action_cmd(id: ActionId, doc: TextDocumentIdentifier, offset: TextUnit) -> Command {
140 let action_request = ActionRequest {
141 id,
142 text_document: doc,
143 offset,
144 };
89 Command { 145 Command {
90 title: id.title().to_string(), 146 title: id.title().to_string(),
91 command: "apply_code_action".to_string(), 147 command: "apply_code_action".to_string(),
92 arguments: Some(vec![to_value(id).unwrap()]), 148 arguments: Some(vec![to_value(action_request).unwrap()]),
93 } 149 }
94} 150}
95 151
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;
6use crossbeam_channel::{Sender, Receiver}; 6use crossbeam_channel::{Sender, Receiver};
7use languageserver_types::Url; 7use languageserver_types::Url;
8use libanalysis::{World, WorldState}; 8use libanalysis::{World, WorldState};
9use serde_json::to_value;
9 10
10use { 11use {
11 req, dispatch, 12 req, dispatch,
@@ -19,6 +20,7 @@ use {
19 publish_decorations, 20 publish_decorations,
20 handle_document_symbol, 21 handle_document_symbol,
21 handle_code_action, 22 handle_code_action,
23 handle_execute_command,
22 }, 24 },
23}; 25};
24 26
@@ -79,7 +81,9 @@ pub(super) fn main_loop(
79 on_notification(io, world, pool, &sender, not)? 81 on_notification(io, world, pool, &sender, not)?
80 } 82 }
81 RawMsg::Response(resp) => { 83 RawMsg::Response(resp) => {
82 error!("unexpected response: {:?}", resp) 84 if !pending_requests.remove(&resp.id) {
85 error!("unexpected response: {:?}", resp)
86 }
83 } 87 }
84 } 88 }
85 } 89 }
@@ -107,22 +111,30 @@ fn on_request(
107 handle_request_on_threadpool::<req::CodeActionRequest>( 111 handle_request_on_threadpool::<req::CodeActionRequest>(
108 &mut req, pool, world, sender, handle_code_action, 112 &mut req, pool, world, sender, handle_code_action,
109 )?; 113 )?;
110// dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |(), resp| { 114 dispatch::handle_request::<req::ExecuteCommand, _>(&mut req, |params, resp| {
111// let world = world.snapshot(); 115 io.send(RawMsg::Response(resp.into_response(Ok(None))?));
112// let sender = sender.clone(); 116
113// pool.execute(move || { 117 let world = world.snapshot();
114// let task = match handle_execute_command(world, params) { 118 let sender = sender.clone();
115// Ok(req) => Task::Request(req), 119 pool.execute(move || {
116// Err(e) => Task::Die(e), 120 let task = match handle_execute_command(world, params) {
117// }; 121 Ok(req) => match to_value(req) {
118// sender.send(task) 122 Err(e) => Task::Die(e.into()),
119// }); 123 Ok(params) => {
120// 124 let request = RawRequest {
121// let resp = resp.into_response(Ok(()))?; 125 id: 0,
122// io.send(RawMsg::Response(resp)); 126 method: <req::ApplyWorkspaceEdit as req::ClientRequest>::METHOD.to_string(),
123// shutdown = true; 127 params,
124// Ok(()) 128 };
125// })?; 129 Task::Request(request)
130 }
131 },
132 Err(e) => Task::Die(e),
133 };
134 sender.send(task)
135 });
136 Ok(())
137 })?;
126 138
127 let mut shutdown = false; 139 let mut shutdown = false;
128 dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| { 140 dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| {