aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/server/src/dispatch.rs71
-rw-r--r--crates/server/src/main.rs75
-rw-r--r--crates/server/src/util.rs10
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
22impl<R: ClientRequest> Responder<R> 22impl<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
52fn parse_request_as<R: ClientRequest>(raw: RawRequest) 41fn 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
85pub fn expect_request<R: ClientRequest>(io: &mut Io, raw: RawRequest) 74pub 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
128pub fn send_notification<N>(io: &mut Io, params: N::Params) -> Result<()> 117pub 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
145fn error(io: &mut Io, id: u64, code: ErrorCode, message: &'static str) -> Result<()> { 134fn 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
151fn 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;
32use libanalysis::{WorldState, World}; 32use libanalysis::{WorldState, World};
33 33
34use ::{ 34use ::{
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
41pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 41pub 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
109type Thunk = Box<for<'a> FnBox<&'a mut Io, Result<()>>>; 109
110enum Task {
111 Respond(RawResponse),
112 Notify(RawNotification),
113 Die(::failure::Error),
114}
110 115
111fn initialized(io: &mut Io) -> Result<()> { 116fn 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>(
267fn update_file_notifications_on_threadpool( 286fn 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};
4use ::{Result}; 4use ::{Result};
5 5
6pub trait FnBox<A, R>: Send {
7 fn call_box(self: Box<Self>, a: A) -> R;
8}
9
10impl<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
16pub trait FilePath { 6pub trait FilePath {
17 fn file_path(&self) -> Result<PathBuf>; 7 fn file_path(&self) -> Result<PathBuf>;
18} 8}