diff options
-rw-r--r-- | crates/server/src/dispatch.rs | 71 | ||||
-rw-r--r-- | crates/server/src/main.rs | 75 | ||||
-rw-r--r-- | crates/server/src/util.rs | 10 |
3 files changed, 79 insertions, 77 deletions
diff --git a/crates/server/src/dispatch.rs b/crates/server/src/dispatch.rs index eb23ab64f..369c56b64 100644 --- a/crates/server/src/dispatch.rs +++ b/crates/server/src/dispatch.rs | |||
@@ -19,38 +19,27 @@ pub struct Responder<R: ClientRequest> { | |||
19 | ph: PhantomData<fn(R)>, | 19 | ph: PhantomData<fn(R)>, |
20 | } | 20 | } |
21 | 21 | ||
22 | impl<R: ClientRequest> Responder<R> | 22 | impl<R: ClientRequest> Responder<R> { |
23 | { | 23 | pub fn into_response(mut self, result: Result<R::Result>) -> Result<RawResponse> { |
24 | pub fn response(self, io: &mut Io, resp: Result<R::Result>) -> Result<()> { | ||
25 | match resp { | ||
26 | Ok(res) => self.result(io, res)?, | ||
27 | Err(e) => { | ||
28 | self.error(io)?; | ||
29 | return Err(e); | ||
30 | } | ||
31 | } | ||
32 | Ok(()) | ||
33 | } | ||
34 | |||
35 | pub fn result(mut self, io: &mut Io, result: R::Result) -> Result<()> { | ||
36 | self.bomb.defuse(); | 24 | self.bomb.defuse(); |
37 | io.send(RawMsg::Response(RawResponse { | 25 | let res = match result { |
38 | id: Some(self.id), | 26 | Ok(result) => { |
39 | result: serde_json::to_value(result)?, | 27 | RawResponse { |
40 | error: serde_json::Value::Null, | 28 | id: Some(self.id), |
41 | })); | 29 | result: serde_json::to_value(result)?, |
42 | Ok(()) | 30 | error: serde_json::Value::Null, |
43 | } | 31 | } |
44 | 32 | } | |
45 | pub fn error(mut self, io: &mut Io) -> Result<()> { | 33 | Err(_) => { |
46 | self.bomb.defuse(); | 34 | error_response(self.id, ErrorCode::InternalError, "internal error")? |
47 | error(io, self.id, ErrorCode::InternalError, "internal error") | 35 | } |
36 | }; | ||
37 | Ok(res) | ||
48 | } | 38 | } |
49 | } | 39 | } |
50 | 40 | ||
51 | |||
52 | fn parse_request_as<R: ClientRequest>(raw: RawRequest) | 41 | fn parse_request_as<R: ClientRequest>(raw: RawRequest) |
53 | -> Result<::std::result::Result<(R::Params, Responder<R>), RawRequest>> | 42 | -> Result<::std::result::Result<(R::Params, Responder<R>), RawRequest>> |
54 | { | 43 | { |
55 | if raw.method != R::METHOD { | 44 | if raw.method != R::METHOD { |
56 | return Ok(Err(raw)); | 45 | return Ok(Err(raw)); |
@@ -77,13 +66,13 @@ pub fn handle_request<R, F>(req: &mut Option<RawRequest>, f: F) -> Result<()> | |||
77 | Err(r) => { | 66 | Err(r) => { |
78 | *req = Some(r); | 67 | *req = Some(r); |
79 | Ok(()) | 68 | Ok(()) |
80 | }, | 69 | } |
81 | } | 70 | } |
82 | } | 71 | } |
83 | } | 72 | } |
84 | 73 | ||
85 | pub fn expect_request<R: ClientRequest>(io: &mut Io, raw: RawRequest) | 74 | pub fn expect_request<R: ClientRequest>(io: &mut Io, raw: RawRequest) |
86 | -> Result<Option<(R::Params, Responder<R>)>> | 75 | -> Result<Option<(R::Params, Responder<R>)>> |
87 | { | 76 | { |
88 | let ret = match parse_request_as::<R>(raw)? { | 77 | let ret = match parse_request_as::<R>(raw)? { |
89 | Ok(x) => Some(x), | 78 | Ok(x) => Some(x), |
@@ -120,21 +109,21 @@ pub fn handle_notification<N, F>(not: &mut Option<RawNotification>, f: F) -> Res | |||
120 | Err(n) => { | 109 | Err(n) => { |
121 | *not = Some(n); | 110 | *not = Some(n); |
122 | Ok(()) | 111 | Ok(()) |
123 | }, | 112 | } |
124 | } | 113 | } |
125 | } | 114 | } |
126 | } | 115 | } |
127 | 116 | ||
128 | pub fn send_notification<N>(io: &mut Io, params: N::Params) -> Result<()> | 117 | pub fn send_notification<N>(params: N::Params) -> RawNotification |
129 | where | 118 | where |
130 | N: Notification, | 119 | N: Notification, |
131 | N::Params: Serialize | 120 | N::Params: Serialize |
132 | { | 121 | { |
133 | io.send(RawMsg::Notification(RawNotification { | 122 | RawNotification { |
134 | method: N::METHOD.to_string(), | 123 | method: N::METHOD.to_string(), |
135 | params: serde_json::to_value(params)?, | 124 | params: serde_json::to_value(params) |
136 | })); | 125 | .unwrap(), |
137 | Ok(()) | 126 | } |
138 | } | 127 | } |
139 | 128 | ||
140 | 129 | ||
@@ -142,20 +131,26 @@ pub fn unknown_method(io: &mut Io, raw: RawRequest) -> Result<()> { | |||
142 | error(io, raw.id, ErrorCode::MethodNotFound, "unknown method") | 131 | error(io, raw.id, ErrorCode::MethodNotFound, "unknown method") |
143 | } | 132 | } |
144 | 133 | ||
145 | fn error(io: &mut Io, id: u64, code: ErrorCode, message: &'static str) -> Result<()> { | 134 | fn error_response(id: u64, code: ErrorCode, message: &'static str) -> Result<RawResponse> { |
146 | #[derive(Serialize)] | 135 | #[derive(Serialize)] |
147 | struct Error { | 136 | struct Error { |
148 | code: i32, | 137 | code: i32, |
149 | message: &'static str, | 138 | message: &'static str, |
150 | } | 139 | } |
151 | io.send(RawMsg::Response(RawResponse { | 140 | let resp = RawResponse { |
152 | id: Some(id), | 141 | id: Some(id), |
153 | result: serde_json::Value::Null, | 142 | result: serde_json::Value::Null, |
154 | error: serde_json::to_value(Error { | 143 | error: serde_json::to_value(Error { |
155 | code: code as i32, | 144 | code: code as i32, |
156 | message, | 145 | message, |
157 | })?, | 146 | })?, |
158 | })); | 147 | }; |
148 | Ok(resp) | ||
149 | } | ||
150 | |||
151 | fn error(io: &mut Io, id: u64, code: ErrorCode, message: &'static str) -> Result<()> { | ||
152 | let resp = error_response(id, code, message)?; | ||
153 | io.send(RawMsg::Response(resp)); | ||
159 | Ok(()) | 154 | Ok(()) |
160 | } | 155 | } |
161 | 156 | ||
diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs index 3ff300e3d..be63fea93 100644 --- a/crates/server/src/main.rs +++ b/crates/server/src/main.rs | |||
@@ -32,10 +32,10 @@ use languageserver_types::Url; | |||
32 | use libanalysis::{WorldState, World}; | 32 | use libanalysis::{WorldState, World}; |
33 | 33 | ||
34 | use ::{ | 34 | use ::{ |
35 | io::{Io, RawMsg, RawRequest}, | 35 | io::{Io, RawMsg, RawRequest, RawResponse, RawNotification}, |
36 | handlers::{handle_syntax_tree, handle_extend_selection, publish_diagnostics, publish_decorations, | 36 | handlers::{handle_syntax_tree, handle_extend_selection, publish_diagnostics, publish_decorations, |
37 | handle_document_symbol, handle_code_action}, | 37 | handle_document_symbol, handle_code_action}, |
38 | util::{FilePath, FnBox} | 38 | util::FilePath, |
39 | }; | 39 | }; |
40 | 40 | ||
41 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | 41 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; |
@@ -80,9 +80,9 @@ fn initialize(io: &mut Io) -> Result<()> { | |||
80 | match io.recv()? { | 80 | match io.recv()? { |
81 | RawMsg::Request(req) => { | 81 | RawMsg::Request(req) => { |
82 | if let Some((_params, resp)) = dispatch::expect_request::<req::Initialize>(io, req)? { | 82 | if let Some((_params, resp)) = dispatch::expect_request::<req::Initialize>(io, req)? { |
83 | resp.result(io, req::InitializeResult { | 83 | let res = req::InitializeResult { capabilities: caps::SERVER_CAPABILITIES }; |
84 | capabilities: caps::SERVER_CAPABILITIES | 84 | let resp = resp.into_response(Ok(res))?; |
85 | })?; | 85 | io.send(RawMsg::Response(resp)); |
86 | match io.recv()? { | 86 | match io.recv()? { |
87 | RawMsg::Notification(n) => { | 87 | RawMsg::Notification(n) => { |
88 | if n.method != "initialized" { | 88 | if n.method != "initialized" { |
@@ -106,13 +106,18 @@ fn initialize(io: &mut Io) -> Result<()> { | |||
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | type Thunk = Box<for<'a> FnBox<&'a mut Io, Result<()>>>; | 109 | |
110 | enum Task { | ||
111 | Respond(RawResponse), | ||
112 | Notify(RawNotification), | ||
113 | Die(::failure::Error), | ||
114 | } | ||
110 | 115 | ||
111 | fn initialized(io: &mut Io) -> Result<()> { | 116 | fn initialized(io: &mut Io) -> Result<()> { |
112 | { | 117 | { |
113 | let mut world = WorldState::new(); | 118 | let mut world = WorldState::new(); |
114 | let mut pool = ThreadPool::new(4); | 119 | let mut pool = ThreadPool::new(4); |
115 | let (sender, receiver) = bounded::<Thunk>(16); | 120 | let (sender, receiver) = bounded::<Task>(16); |
116 | info!("lifecycle: handshake finished, server ready to serve requests"); | 121 | info!("lifecycle: handshake finished, server ready to serve requests"); |
117 | let res = main_loop(io, &mut world, &mut pool, sender, receiver.clone()); | 122 | let res = main_loop(io, &mut world, &mut pool, sender, receiver.clone()); |
118 | info!("waiting for background jobs to finish..."); | 123 | info!("waiting for background jobs to finish..."); |
@@ -140,14 +145,14 @@ fn main_loop( | |||
140 | io: &mut Io, | 145 | io: &mut Io, |
141 | world: &mut WorldState, | 146 | world: &mut WorldState, |
142 | pool: &mut ThreadPool, | 147 | pool: &mut ThreadPool, |
143 | sender: Sender<Thunk>, | 148 | sender: Sender<Task>, |
144 | receiver: Receiver<Thunk>, | 149 | receiver: Receiver<Task>, |
145 | ) -> Result<()> { | 150 | ) -> Result<()> { |
146 | info!("server initialized, serving requests"); | 151 | info!("server initialized, serving requests"); |
147 | loop { | 152 | loop { |
148 | enum Event { | 153 | enum Event { |
149 | Msg(RawMsg), | 154 | Msg(RawMsg), |
150 | Thunk(Thunk), | 155 | Task(Task), |
151 | ReceiverDead, | 156 | ReceiverDead, |
152 | } | 157 | } |
153 | 158 | ||
@@ -156,7 +161,7 @@ fn main_loop( | |||
156 | Some(msg) => Event::Msg(msg), | 161 | Some(msg) => Event::Msg(msg), |
157 | None => Event::ReceiverDead, | 162 | None => Event::ReceiverDead, |
158 | }, | 163 | }, |
159 | recv(receiver, thunk) => Event::Thunk(thunk.unwrap()), | 164 | recv(receiver, task) => Event::Task(task.unwrap()), |
160 | }; | 165 | }; |
161 | 166 | ||
162 | let msg = match event { | 167 | let msg = match event { |
@@ -164,8 +169,15 @@ fn main_loop( | |||
164 | io.cleanup_receiver()?; | 169 | io.cleanup_receiver()?; |
165 | unreachable!(); | 170 | unreachable!(); |
166 | } | 171 | } |
167 | Event::Thunk(thunk) => { | 172 | Event::Task(task) => { |
168 | thunk.call_box(io)?; | 173 | match task { |
174 | Task::Respond(response) => | ||
175 | io.send(RawMsg::Response(response)), | ||
176 | Task::Notify(n) => | ||
177 | io.send(RawMsg::Notification(n)), | ||
178 | Task::Die(error) => | ||
179 | return Err(error), | ||
180 | } | ||
169 | continue; | 181 | continue; |
170 | } | 182 | } |
171 | Event::Msg(msg) => msg, | 183 | Event::Msg(msg) => msg, |
@@ -175,21 +187,22 @@ fn main_loop( | |||
175 | RawMsg::Request(req) => { | 187 | RawMsg::Request(req) => { |
176 | let mut req = Some(req); | 188 | let mut req = Some(req); |
177 | handle_request_on_threadpool::<req::SyntaxTree>( | 189 | handle_request_on_threadpool::<req::SyntaxTree>( |
178 | &mut req, pool, world, &sender, handle_syntax_tree | 190 | &mut req, pool, world, &sender, handle_syntax_tree, |
179 | )?; | 191 | )?; |
180 | handle_request_on_threadpool::<req::ExtendSelection>( | 192 | handle_request_on_threadpool::<req::ExtendSelection>( |
181 | &mut req, pool, world, &sender, handle_extend_selection | 193 | &mut req, pool, world, &sender, handle_extend_selection, |
182 | )?; | 194 | )?; |
183 | handle_request_on_threadpool::<req::DocumentSymbolRequest>( | 195 | handle_request_on_threadpool::<req::DocumentSymbolRequest>( |
184 | &mut req, pool, world, &sender, handle_document_symbol | 196 | &mut req, pool, world, &sender, handle_document_symbol, |
185 | )?; | 197 | )?; |
186 | handle_request_on_threadpool::<req::CodeActionRequest>( | 198 | handle_request_on_threadpool::<req::CodeActionRequest>( |
187 | &mut req, pool, world, &sender, handle_code_action | 199 | &mut req, pool, world, &sender, handle_code_action, |
188 | )?; | 200 | )?; |
189 | 201 | ||
190 | let mut shutdown = false; | 202 | let mut shutdown = false; |
191 | dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| { | 203 | dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| { |
192 | resp.result(io, ())?; | 204 | let resp = resp.into_response(Ok(()))?; |
205 | io.send(RawMsg::Response(resp)); | ||
193 | shutdown = true; | 206 | shutdown = true; |
194 | Ok(()) | 207 | Ok(()) |
195 | })?; | 208 | })?; |
@@ -227,10 +240,12 @@ fn main_loop( | |||
227 | dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| { | 240 | dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| { |
228 | let path = params.text_document.file_path()?; | 241 | let path = params.text_document.file_path()?; |
229 | world.change_overlay(path, None); | 242 | world.change_overlay(path, None); |
230 | dispatch::send_notification::<req::PublishDiagnostics>(io, req::PublishDiagnosticsParams { | 243 | let not = req::PublishDiagnosticsParams { |
231 | uri: params.text_document.uri, | 244 | uri: params.text_document.uri, |
232 | diagnostics: Vec::new(), | 245 | diagnostics: Vec::new(), |
233 | })?; | 246 | }; |
247 | let not = dispatch::send_notification::<req::PublishDiagnostics>(not); | ||
248 | io.send(RawMsg::Notification(not)); | ||
234 | Ok(()) | 249 | Ok(()) |
235 | })?; | 250 | })?; |
236 | 251 | ||
@@ -249,7 +264,7 @@ fn handle_request_on_threadpool<R: req::ClientRequest>( | |||
249 | req: &mut Option<RawRequest>, | 264 | req: &mut Option<RawRequest>, |
250 | pool: &ThreadPool, | 265 | pool: &ThreadPool, |
251 | world: &WorldState, | 266 | world: &WorldState, |
252 | sender: &Sender<Thunk>, | 267 | sender: &Sender<Task>, |
253 | f: fn(World, R::Params) -> Result<R::Result>, | 268 | f: fn(World, R::Params) -> Result<R::Result>, |
254 | ) -> Result<()> | 269 | ) -> Result<()> |
255 | { | 270 | { |
@@ -258,7 +273,11 @@ fn handle_request_on_threadpool<R: req::ClientRequest>( | |||
258 | let sender = sender.clone(); | 273 | let sender = sender.clone(); |
259 | pool.execute(move || { | 274 | pool.execute(move || { |
260 | let res = f(world, params); | 275 | let res = f(world, params); |
261 | sender.send(Box::new(|io: &mut Io| resp.response(io, res))) | 276 | let task = match resp.into_response(res) { |
277 | Ok(resp) => Task::Respond(resp), | ||
278 | Err(e) => Task::Die(e), | ||
279 | }; | ||
280 | sender.send(task); | ||
262 | }); | 281 | }); |
263 | Ok(()) | 282 | Ok(()) |
264 | }) | 283 | }) |
@@ -267,7 +286,7 @@ fn handle_request_on_threadpool<R: req::ClientRequest>( | |||
267 | fn update_file_notifications_on_threadpool( | 286 | fn update_file_notifications_on_threadpool( |
268 | pool: &ThreadPool, | 287 | pool: &ThreadPool, |
269 | world: World, | 288 | world: World, |
270 | sender: Sender<Thunk>, | 289 | sender: Sender<Task>, |
271 | uri: Url, | 290 | uri: Url, |
272 | ) { | 291 | ) { |
273 | pool.execute(move || { | 292 | pool.execute(move || { |
@@ -276,9 +295,8 @@ fn update_file_notifications_on_threadpool( | |||
276 | error!("failed to compute diagnostics: {:?}", e) | 295 | error!("failed to compute diagnostics: {:?}", e) |
277 | } | 296 | } |
278 | Ok(params) => { | 297 | Ok(params) => { |
279 | sender.send(Box::new(|io: &mut Io| { | 298 | let not = dispatch::send_notification::<req::PublishDiagnostics>(params); |
280 | dispatch::send_notification::<req::PublishDiagnostics>(io, params) | 299 | sender.send(Task::Notify(not)); |
281 | })) | ||
282 | } | 300 | } |
283 | } | 301 | } |
284 | match publish_decorations(world, uri) { | 302 | match publish_decorations(world, uri) { |
@@ -286,9 +304,8 @@ fn update_file_notifications_on_threadpool( | |||
286 | error!("failed to compute decortions: {:?}", e) | 304 | error!("failed to compute decortions: {:?}", e) |
287 | } | 305 | } |
288 | Ok(params) => { | 306 | Ok(params) => { |
289 | sender.send(Box::new(|io: &mut Io| { | 307 | let not = dispatch::send_notification::<req::PublishDecorations>(params); |
290 | dispatch::send_notification::<req::PublishDecorations>(io, params) | 308 | sender.send(Task::Notify(not)) |
291 | })) | ||
292 | } | 309 | } |
293 | } | 310 | } |
294 | }); | 311 | }); |
diff --git a/crates/server/src/util.rs b/crates/server/src/util.rs index e4c226f93..6747c20a8 100644 --- a/crates/server/src/util.rs +++ b/crates/server/src/util.rs | |||
@@ -3,16 +3,6 @@ use languageserver_types::{TextDocumentItem, VersionedTextDocumentIdentifier, | |||
3 | TextDocumentIdentifier, Url}; | 3 | TextDocumentIdentifier, Url}; |
4 | use ::{Result}; | 4 | use ::{Result}; |
5 | 5 | ||
6 | pub trait FnBox<A, R>: Send { | ||
7 | fn call_box(self: Box<Self>, a: A) -> R; | ||
8 | } | ||
9 | |||
10 | impl<A, R, F: FnOnce(A) -> R + Send> FnBox<A, R> for F { | ||
11 | fn call_box(self: Box<F>, a: A) -> R { | ||
12 | (*self)(a) | ||
13 | } | ||
14 | } | ||
15 | |||
16 | pub trait FilePath { | 6 | pub trait FilePath { |
17 | fn file_path(&self) -> Result<PathBuf>; | 7 | fn file_path(&self) -> Result<PathBuf>; |
18 | } | 8 | } |