diff options
author | Aleksey Kladov <[email protected]> | 2020-06-25 16:50:47 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-06-25 17:28:58 +0100 |
commit | f5ea35a2710c78e77c81f491cc6f8abd40e33981 (patch) | |
tree | 8ba08993d86c5c93b9a0db373b22444d25bfab65 /crates/rust-analyzer/src/main_loop.rs | |
parent | 22098127c4f4b7414f0695c7788f07d0a1c43892 (diff) |
Add NotificationDispatcher
Diffstat (limited to 'crates/rust-analyzer/src/main_loop.rs')
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 114 |
1 files changed, 43 insertions, 71 deletions
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index ebc232736..c2f43df1d 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -6,8 +6,8 @@ use std::{ | |||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crossbeam_channel::{never, select, Receiver}; | 8 | use crossbeam_channel::{never, select, Receiver}; |
9 | use lsp_server::{Connection, Notification, Request, RequestId, Response}; | 9 | use lsp_server::{Connection, Notification, Request, Response}; |
10 | use lsp_types::{notification::Notification as _, request::Request as _, NumberOrString}; | 10 | use lsp_types::{notification::Notification as _, request::Request as _}; |
11 | use ra_db::VfsPath; | 11 | use ra_db::VfsPath; |
12 | use ra_ide::{Canceled, FileId}; | 12 | use ra_ide::{Canceled, FileId}; |
13 | use ra_prof::profile; | 13 | use ra_prof::profile; |
@@ -16,13 +16,12 @@ use ra_project_model::{PackageRoot, ProjectWorkspace}; | |||
16 | use crate::{ | 16 | use crate::{ |
17 | config::{Config, FilesWatcher, LinkedProject}, | 17 | config::{Config, FilesWatcher, LinkedProject}, |
18 | diagnostics::DiagnosticTask, | 18 | diagnostics::DiagnosticTask, |
19 | dispatch::RequestDispatcher, | 19 | dispatch::{NotificationDispatcher, RequestDispatcher}, |
20 | from_proto, | 20 | from_proto, |
21 | global_state::{file_id_to_url, GlobalState, Status}, | 21 | global_state::{file_id_to_url, GlobalState, Status}, |
22 | handlers, lsp_ext, | 22 | handlers, lsp_ext, |
23 | lsp_utils::{ | 23 | lsp_utils::{ |
24 | apply_document_changes, is_canceled, notification_cast, notification_is, notification_new, | 24 | apply_document_changes, is_canceled, notification_is, notification_new, show_message, |
25 | show_message, | ||
26 | }, | 25 | }, |
27 | request_metrics::RequestMetrics, | 26 | request_metrics::RequestMetrics, |
28 | Result, | 27 | Result, |
@@ -240,9 +239,7 @@ impl GlobalState { | |||
240 | } | 239 | } |
241 | 240 | ||
242 | fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> { | 241 | fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> { |
243 | let mut pool_dispatcher = | 242 | RequestDispatcher { req: Some(req), global_state: self, request_received } |
244 | RequestDispatcher { req: Some(req), global_state: self, request_received }; | ||
245 | pool_dispatcher | ||
246 | .on_sync::<lsp_ext::CollectGarbage>(|s, ()| Ok(s.collect_garbage()))? | 243 | .on_sync::<lsp_ext::CollectGarbage>(|s, ()| Ok(s.collect_garbage()))? |
247 | .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? | 244 | .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? |
248 | .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? | 245 | .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? |
@@ -298,56 +295,47 @@ impl GlobalState { | |||
298 | Ok(()) | 295 | Ok(()) |
299 | } | 296 | } |
300 | fn on_notification(&mut self, not: Notification) -> Result<()> { | 297 | fn on_notification(&mut self, not: Notification) -> Result<()> { |
301 | let not = match notification_cast::<lsp_types::notification::Cancel>(not) { | 298 | NotificationDispatcher { not: Some(not), global_state: self } |
302 | Ok(params) => { | 299 | .on::<lsp_types::notification::Cancel>(|this, params| { |
303 | let id: RequestId = match params.id { | 300 | let id: lsp_server::RequestId = match params.id { |
304 | NumberOrString::Number(id) => id.into(), | 301 | lsp_types::NumberOrString::Number(id) => id.into(), |
305 | NumberOrString::String(id) => id.into(), | 302 | lsp_types::NumberOrString::String(id) => id.into(), |
306 | }; | 303 | }; |
307 | if let Some(response) = self.req_queue.incoming.cancel(id) { | 304 | if let Some(response) = this.req_queue.incoming.cancel(id) { |
308 | self.send(response.into()) | 305 | this.send(response.into()); |
309 | } | 306 | } |
310 | return Ok(()); | 307 | Ok(()) |
311 | } | 308 | })? |
312 | Err(not) => not, | 309 | .on::<lsp_types::notification::DidOpenTextDocument>(|this, params| { |
313 | }; | ||
314 | let not = match notification_cast::<lsp_types::notification::DidOpenTextDocument>(not) { | ||
315 | Ok(params) => { | ||
316 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { | 310 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { |
317 | if !self.mem_docs.insert(path.clone()) { | 311 | if !this.mem_docs.insert(path.clone()) { |
318 | log::error!("duplicate DidOpenTextDocument: {}", path) | 312 | log::error!("duplicate DidOpenTextDocument: {}", path) |
319 | } | 313 | } |
320 | self.vfs | 314 | this.vfs |
321 | .write() | 315 | .write() |
322 | .0 | 316 | .0 |
323 | .set_file_contents(path, Some(params.text_document.text.into_bytes())); | 317 | .set_file_contents(path, Some(params.text_document.text.into_bytes())); |
324 | } | 318 | } |
325 | return Ok(()); | 319 | Ok(()) |
326 | } | 320 | })? |
327 | Err(not) => not, | 321 | .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| { |
328 | }; | ||
329 | let not = match notification_cast::<lsp_types::notification::DidChangeTextDocument>(not) { | ||
330 | Ok(params) => { | ||
331 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { | 322 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { |
332 | assert!(self.mem_docs.contains(&path)); | 323 | assert!(this.mem_docs.contains(&path)); |
333 | let vfs = &mut self.vfs.write().0; | 324 | let vfs = &mut this.vfs.write().0; |
334 | let file_id = vfs.file_id(&path).unwrap(); | 325 | let file_id = vfs.file_id(&path).unwrap(); |
335 | let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap(); | 326 | let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap(); |
336 | apply_document_changes(&mut text, params.content_changes); | 327 | apply_document_changes(&mut text, params.content_changes); |
337 | vfs.set_file_contents(path, Some(text.into_bytes())) | 328 | vfs.set_file_contents(path, Some(text.into_bytes())) |
338 | } | 329 | } |
339 | return Ok(()); | 330 | Ok(()) |
340 | } | 331 | })? |
341 | Err(not) => not, | 332 | .on::<lsp_types::notification::DidCloseTextDocument>(|this, params| { |
342 | }; | ||
343 | let not = match notification_cast::<lsp_types::notification::DidCloseTextDocument>(not) { | ||
344 | Ok(params) => { | ||
345 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { | 333 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { |
346 | if !self.mem_docs.remove(&path) { | 334 | if !this.mem_docs.remove(&path) { |
347 | log::error!("orphan DidCloseTextDocument: {}", path) | 335 | log::error!("orphan DidCloseTextDocument: {}", path) |
348 | } | 336 | } |
349 | if let Some(path) = path.as_path() { | 337 | if let Some(path) = path.as_path() { |
350 | self.loader.invalidate(path.to_path_buf()); | 338 | this.loader.invalidate(path.to_path_buf()); |
351 | } | 339 | } |
352 | } | 340 | } |
353 | let params = lsp_types::PublishDiagnosticsParams { | 341 | let params = lsp_types::PublishDiagnosticsParams { |
@@ -356,25 +344,19 @@ impl GlobalState { | |||
356 | version: None, | 344 | version: None, |
357 | }; | 345 | }; |
358 | let not = notification_new::<lsp_types::notification::PublishDiagnostics>(params); | 346 | let not = notification_new::<lsp_types::notification::PublishDiagnostics>(params); |
359 | self.send(not.into()); | 347 | this.send(not.into()); |
360 | return Ok(()); | 348 | Ok(()) |
361 | } | 349 | })? |
362 | Err(not) => not, | 350 | .on::<lsp_types::notification::DidSaveTextDocument>(|this, _params| { |
363 | }; | 351 | if let Some(flycheck) = &this.flycheck { |
364 | let not = match notification_cast::<lsp_types::notification::DidSaveTextDocument>(not) { | ||
365 | Ok(_params) => { | ||
366 | if let Some(flycheck) = &self.flycheck { | ||
367 | flycheck.0.update(); | 352 | flycheck.0.update(); |
368 | } | 353 | } |
369 | return Ok(()); | 354 | Ok(()) |
370 | } | 355 | })? |
371 | Err(not) => not, | 356 | .on::<lsp_types::notification::DidChangeConfiguration>(|this, _params| { |
372 | }; | ||
373 | let not = match notification_cast::<lsp_types::notification::DidChangeConfiguration>(not) { | ||
374 | Ok(_) => { | ||
375 | // As stated in https://github.com/microsoft/language-server-protocol/issues/676, | 357 | // As stated in https://github.com/microsoft/language-server-protocol/issues/676, |
376 | // this notification's parameters should be ignored and the actual config queried separately. | 358 | // this notification's parameters should be ignored and the actual config queried separately. |
377 | let request = self.req_queue.outgoing.register( | 359 | let request = this.req_queue.outgoing.register( |
378 | lsp_types::request::WorkspaceConfiguration::METHOD.to_string(), | 360 | lsp_types::request::WorkspaceConfiguration::METHOD.to_string(), |
379 | lsp_types::ConfigurationParams { | 361 | lsp_types::ConfigurationParams { |
380 | items: vec![lsp_types::ConfigurationItem { | 362 | items: vec![lsp_types::ConfigurationItem { |
@@ -403,30 +385,21 @@ impl GlobalState { | |||
403 | } | 385 | } |
404 | }, | 386 | }, |
405 | ); | 387 | ); |
406 | self.send(request.into()); | 388 | this.send(request.into()); |
407 | 389 | ||
408 | return Ok(()); | 390 | return Ok(()); |
409 | } | 391 | })? |
410 | Err(not) => not, | 392 | .on::<lsp_types::notification::DidChangeWatchedFiles>(|this, params| { |
411 | }; | ||
412 | let not = match notification_cast::<lsp_types::notification::DidChangeWatchedFiles>(not) { | ||
413 | Ok(params) => { | ||
414 | for change in params.changes { | 393 | for change in params.changes { |
415 | if let Ok(path) = from_proto::abs_path(&change.uri) { | 394 | if let Ok(path) = from_proto::abs_path(&change.uri) { |
416 | self.loader.invalidate(path) | 395 | this.loader.invalidate(path); |
417 | } | 396 | } |
418 | } | 397 | } |
419 | return Ok(()); | 398 | Ok(()) |
420 | } | 399 | })? |
421 | Err(not) => not, | 400 | .finish(); |
422 | }; | ||
423 | if not.method.starts_with("$/") { | ||
424 | return Ok(()); | ||
425 | } | ||
426 | log::error!("unhandled notification: {:?}", not); | ||
427 | Ok(()) | 401 | Ok(()) |
428 | } | 402 | } |
429 | // TODO | ||
430 | pub(crate) fn on_task(&mut self, task: Task) { | 403 | pub(crate) fn on_task(&mut self, task: Task) { |
431 | match task { | 404 | match task { |
432 | Task::Respond(response) => { | 405 | Task::Respond(response) => { |
@@ -481,7 +454,6 @@ impl GlobalState { | |||
481 | } | 454 | } |
482 | } | 455 | } |
483 | 456 | ||
484 | // TODO | ||
485 | #[derive(Debug)] | 457 | #[derive(Debug)] |
486 | pub(crate) enum Task { | 458 | pub(crate) enum Task { |
487 | Respond(Response), | 459 | Respond(Response), |