aboutsummaryrefslogtreecommitdiff
path: root/crates/server/src/main.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-12 20:08:14 +0100
committerAleksey Kladov <[email protected]>2018-08-12 20:08:14 +0100
commit196236980613249f25ccb2968a214922f7db10f1 (patch)
tree515e3a7476fffffc17b69c4929451a399f2113ee /crates/server/src/main.rs
parentacd7552698d374fbf95b08f55cf9eba3e4ff863d (diff)
more modules
Diffstat (limited to 'crates/server/src/main.rs')
-rw-r--r--crates/server/src/main.rs184
1 files changed, 5 insertions, 179 deletions
diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs
index fe94e901e..fccfe9b3b 100644
--- a/crates/server/src/main.rs
+++ b/crates/server/src/main.rs
@@ -21,21 +21,17 @@ mod io;
21mod caps; 21mod caps;
22mod req; 22mod req;
23mod dispatch; 23mod dispatch;
24mod handlers;
25mod util; 24mod util;
26mod conv; 25mod conv;
26mod main_loop;
27 27
28use threadpool::ThreadPool; 28use threadpool::ThreadPool;
29use crossbeam_channel::{bounded, Sender, Receiver}; 29use crossbeam_channel::bounded;
30use flexi_logger::Logger; 30use flexi_logger::Logger;
31use languageserver_types::Url; 31use libanalysis::WorldState;
32use libanalysis::{WorldState, World};
33 32
34use ::{ 33use ::{
35 io::{Io, RawMsg, RawRequest, RawResponse, RawNotification}, 34 io::{Io, RawMsg, RawResponse, RawNotification}
36 handlers::{handle_syntax_tree, handle_extend_selection, publish_diagnostics, publish_decorations,
37 handle_document_symbol, handle_code_action},
38 util::FilePath,
39}; 35};
40 36
41pub type Result<T> = ::std::result::Result<T, ::failure::Error>; 37pub type Result<T> = ::std::result::Result<T, ::failure::Error>;
@@ -121,7 +117,7 @@ fn initialized(io: &mut Io) -> Result<()> {
121 let mut pool = ThreadPool::new(4); 117 let mut pool = ThreadPool::new(4);
122 let (sender, receiver) = bounded::<Task>(16); 118 let (sender, receiver) = bounded::<Task>(16);
123 info!("lifecycle: handshake finished, server ready to serve requests"); 119 info!("lifecycle: handshake finished, server ready to serve requests");
124 let res = main_loop(io, &mut world, &mut pool, sender, receiver.clone()); 120 let res = main_loop::main_loop(io, &mut world, &mut pool, sender, receiver.clone());
125 info!("waiting for background jobs to finish..."); 121 info!("waiting for background jobs to finish...");
126 receiver.for_each(drop); 122 receiver.for_each(drop);
127 pool.join(); 123 pool.join();
@@ -142,173 +138,3 @@ fn initialized(io: &mut Io) -> Result<()> {
142 } 138 }
143 } 139 }
144} 140}
145
146fn main_loop(
147 io: &mut Io,
148 world: &mut WorldState,
149 pool: &mut ThreadPool,
150 sender: Sender<Task>,
151 receiver: Receiver<Task>,
152) -> Result<()> {
153 info!("server initialized, serving requests");
154 loop {
155 enum Event {
156 Msg(RawMsg),
157 Task(Task),
158 ReceiverDead,
159 }
160
161 let event = select! {
162 recv(io.receiver(), msg) => match msg {
163 Some(msg) => Event::Msg(msg),
164 None => Event::ReceiverDead,
165 },
166 recv(receiver, task) => Event::Task(task.unwrap()),
167 };
168
169 let msg = match event {
170 Event::ReceiverDead => {
171 io.cleanup_receiver()?;
172 unreachable!();
173 }
174 Event::Task(task) => {
175 match task {
176 Task::Respond(response) =>
177 io.send(RawMsg::Response(response)),
178 Task::Notify(n) =>
179 io.send(RawMsg::Notification(n)),
180 Task::Die(error) =>
181 return Err(error),
182 }
183 continue;
184 }
185 Event::Msg(msg) => msg,
186 };
187
188 match msg {
189 RawMsg::Request(req) => {
190 let mut req = Some(req);
191 handle_request_on_threadpool::<req::SyntaxTree>(
192 &mut req, pool, world, &sender, handle_syntax_tree,
193 )?;
194 handle_request_on_threadpool::<req::ExtendSelection>(
195 &mut req, pool, world, &sender, handle_extend_selection,
196 )?;
197 handle_request_on_threadpool::<req::DocumentSymbolRequest>(
198 &mut req, pool, world, &sender, handle_document_symbol,
199 )?;
200 handle_request_on_threadpool::<req::CodeActionRequest>(
201 &mut req, pool, world, &sender, handle_code_action,
202 )?;
203
204 let mut shutdown = false;
205 dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| {
206 let resp = resp.into_response(Ok(()))?;
207 io.send(RawMsg::Response(resp));
208 shutdown = true;
209 Ok(())
210 })?;
211 if shutdown {
212 info!("lifecycle: initiating shutdown");
213 drop(sender);
214 return Ok(());
215 }
216 if let Some(req) = req {
217 error!("unknown method: {:?}", req);
218 dispatch::unknown_method(io, req)?;
219 }
220 }
221 RawMsg::Notification(not) => {
222 let mut not = Some(not);
223 dispatch::handle_notification::<req::DidOpenTextDocument, _>(&mut not, |params| {
224 let path = params.text_document.file_path()?;
225 world.change_overlay(path, Some(params.text_document.text));
226 update_file_notifications_on_threadpool(
227 pool, world.snapshot(), sender.clone(), params.text_document.uri,
228 );
229 Ok(())
230 })?;
231 dispatch::handle_notification::<req::DidChangeTextDocument, _>(&mut not, |mut params| {
232 let path = params.text_document.file_path()?;
233 let text = params.content_changes.pop()
234 .ok_or_else(|| format_err!("empty changes"))?
235 .text;
236 world.change_overlay(path, Some(text));
237 update_file_notifications_on_threadpool(
238 pool, world.snapshot(), sender.clone(), params.text_document.uri,
239 );
240 Ok(())
241 })?;
242 dispatch::handle_notification::<req::DidCloseTextDocument, _>(&mut not, |params| {
243 let path = params.text_document.file_path()?;
244 world.change_overlay(path, None);
245 let not = req::PublishDiagnosticsParams {
246 uri: params.text_document.uri,
247 diagnostics: Vec::new(),
248 };
249 let not = dispatch::send_notification::<req::PublishDiagnostics>(not);
250 io.send(RawMsg::Notification(not));
251 Ok(())
252 })?;
253
254 if let Some(not) = not {
255 error!("unhandled notification: {:?}", not)
256 }
257 }
258 msg => {
259 eprintln!("msg = {:?}", msg);
260 }
261 }
262 }
263}
264
265fn handle_request_on_threadpool<R: req::ClientRequest>(
266 req: &mut Option<RawRequest>,
267 pool: &ThreadPool,
268 world: &WorldState,
269 sender: &Sender<Task>,
270 f: fn(World, R::Params) -> Result<R::Result>,
271) -> Result<()>
272{
273 dispatch::handle_request::<R, _>(req, |params, resp| {
274 let world = world.snapshot();
275 let sender = sender.clone();
276 pool.execute(move || {
277 let res = f(world, params);
278 let task = match resp.into_response(res) {
279 Ok(resp) => Task::Respond(resp),
280 Err(e) => Task::Die(e),
281 };
282 sender.send(task);
283 });
284 Ok(())
285 })
286}
287
288fn update_file_notifications_on_threadpool(
289 pool: &ThreadPool,
290 world: World,
291 sender: Sender<Task>,
292 uri: Url,
293) {
294 pool.execute(move || {
295 match publish_diagnostics(world.clone(), uri.clone()) {
296 Err(e) => {
297 error!("failed to compute diagnostics: {:?}", e)
298 }
299 Ok(params) => {
300 let not = dispatch::send_notification::<req::PublishDiagnostics>(params);
301 sender.send(Task::Notify(not));
302 }
303 }
304 match publish_decorations(world, uri) {
305 Err(e) => {
306 error!("failed to compute decorations: {:?}", e)
307 }
308 Ok(params) => {
309 let not = dispatch::send_notification::<req::PublishDecorations>(params);
310 sender.send(Task::Notify(not))
311 }
312 }
313 });
314}