]> git.lizzy.rs Git - rust.git/blob - crates/rust-analyzer/src/main_loop.rs
Auto merge of #12808 - Veykril:check-workspace, r=Veykril
[rust.git] / crates / rust-analyzer / src / main_loop.rs
1 //! The main loop of `rust-analyzer` responsible for dispatching LSP
2 //! requests/replies and notifications back to the client.
3 use std::{
4     fmt,
5     ops::Deref,
6     sync::Arc,
7     time::{Duration, Instant},
8 };
9
10 use always_assert::always;
11 use crossbeam_channel::{select, Receiver};
12 use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath};
13 use itertools::Itertools;
14 use lsp_server::{Connection, Notification, Request};
15 use lsp_types::notification::Notification as _;
16 use vfs::{ChangeKind, FileId};
17
18 use crate::{
19     config::Config,
20     dispatch::{NotificationDispatcher, RequestDispatcher},
21     from_proto,
22     global_state::{file_id_to_url, url_to_file_id, GlobalState},
23     handlers, lsp_ext,
24     lsp_utils::{apply_document_changes, notification_is, Progress},
25     mem_docs::DocumentData,
26     reload::{self, BuildDataProgress, ProjectWorkspaceProgress},
27     Result,
28 };
29
30 pub fn main_loop(config: Config, connection: Connection) -> Result<()> {
31     tracing::info!("initial config: {:#?}", config);
32
33     // Windows scheduler implements priority boosts: if thread waits for an
34     // event (like a condvar), and event fires, priority of the thread is
35     // temporary bumped. This optimization backfires in our case: each time the
36     // `main_loop` schedules a task to run on a threadpool, the worker threads
37     // gets a higher priority, and (on a machine with fewer cores) displaces the
38     // main loop! We work-around this by marking the main loop as a
39     // higher-priority thread.
40     //
41     // https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities
42     // https://docs.microsoft.com/en-us/windows/win32/procthread/priority-boosts
43     // https://github.com/rust-lang/rust-analyzer/issues/2835
44     #[cfg(windows)]
45     unsafe {
46         use winapi::um::processthreadsapi::*;
47         let thread = GetCurrentThread();
48         let thread_priority_above_normal = 1;
49         SetThreadPriority(thread, thread_priority_above_normal);
50     }
51
52     GlobalState::new(connection.sender, config).run(connection.receiver)
53 }
54
55 enum Event {
56     Lsp(lsp_server::Message),
57     Task(Task),
58     Vfs(vfs::loader::Message),
59     Flycheck(flycheck::Message),
60 }
61
62 #[derive(Debug)]
63 pub(crate) enum Task {
64     Response(lsp_server::Response),
65     Retry(lsp_server::Request),
66     Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
67     PrimeCaches(PrimeCachesProgress),
68     FetchWorkspace(ProjectWorkspaceProgress),
69     FetchBuildData(BuildDataProgress),
70 }
71
72 #[derive(Debug)]
73 pub(crate) enum PrimeCachesProgress {
74     Begin,
75     Report(ide::ParallelPrimeCachesProgress),
76     End { cancelled: bool },
77 }
78
79 impl fmt::Debug for Event {
80     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81         let debug_verbose_not = |not: &Notification, f: &mut fmt::Formatter<'_>| {
82             f.debug_struct("Notification").field("method", &not.method).finish()
83         };
84
85         match self {
86             Event::Lsp(lsp_server::Message::Notification(not)) => {
87                 if notification_is::<lsp_types::notification::DidOpenTextDocument>(not)
88                     || notification_is::<lsp_types::notification::DidChangeTextDocument>(not)
89                 {
90                     return debug_verbose_not(not, f);
91                 }
92             }
93             Event::Task(Task::Response(resp)) => {
94                 return f
95                     .debug_struct("Response")
96                     .field("id", &resp.id)
97                     .field("error", &resp.error)
98                     .finish();
99             }
100             _ => (),
101         }
102         match self {
103             Event::Lsp(it) => fmt::Debug::fmt(it, f),
104             Event::Task(it) => fmt::Debug::fmt(it, f),
105             Event::Vfs(it) => fmt::Debug::fmt(it, f),
106             Event::Flycheck(it) => fmt::Debug::fmt(it, f),
107         }
108     }
109 }
110
111 impl GlobalState {
112     fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> {
113         if self.config.linked_projects().is_empty()
114             && self.config.detached_files().is_empty()
115             && self.config.notifications().cargo_toml_not_found
116         {
117             self.show_and_log_error("rust-analyzer failed to discover workspace".to_string(), None);
118         };
119
120         if self.config.did_save_text_document_dynamic_registration() {
121             let save_registration_options = lsp_types::TextDocumentSaveRegistrationOptions {
122                 include_text: Some(false),
123                 text_document_registration_options: lsp_types::TextDocumentRegistrationOptions {
124                     document_selector: Some(vec![
125                         lsp_types::DocumentFilter {
126                             language: None,
127                             scheme: None,
128                             pattern: Some("**/*.rs".into()),
129                         },
130                         lsp_types::DocumentFilter {
131                             language: None,
132                             scheme: None,
133                             pattern: Some("**/Cargo.toml".into()),
134                         },
135                         lsp_types::DocumentFilter {
136                             language: None,
137                             scheme: None,
138                             pattern: Some("**/Cargo.lock".into()),
139                         },
140                     ]),
141                 },
142             };
143
144             let registration = lsp_types::Registration {
145                 id: "textDocument/didSave".to_string(),
146                 method: "textDocument/didSave".to_string(),
147                 register_options: Some(serde_json::to_value(save_registration_options).unwrap()),
148             };
149             self.send_request::<lsp_types::request::RegisterCapability>(
150                 lsp_types::RegistrationParams { registrations: vec![registration] },
151                 |_, _| (),
152             );
153         }
154
155         self.fetch_workspaces_queue.request_op("startup".to_string());
156         if let Some(cause) = self.fetch_workspaces_queue.should_start_op() {
157             self.fetch_workspaces(cause);
158         }
159
160         while let Some(event) = self.next_event(&inbox) {
161             if let Event::Lsp(lsp_server::Message::Notification(not)) = &event {
162                 if not.method == lsp_types::notification::Exit::METHOD {
163                     return Ok(());
164                 }
165             }
166             self.handle_event(event)?
167         }
168
169         Err("client exited without proper shutdown sequence".into())
170     }
171
172     fn next_event(&self, inbox: &Receiver<lsp_server::Message>) -> Option<Event> {
173         select! {
174             recv(inbox) -> msg =>
175                 msg.ok().map(Event::Lsp),
176
177             recv(self.task_pool.receiver) -> task =>
178                 Some(Event::Task(task.unwrap())),
179
180             recv(self.loader.receiver) -> task =>
181                 Some(Event::Vfs(task.unwrap())),
182
183             recv(self.flycheck_receiver) -> task =>
184                 Some(Event::Flycheck(task.unwrap())),
185         }
186     }
187
188     fn handle_event(&mut self, event: Event) -> Result<()> {
189         let loop_start = Instant::now();
190         // NOTE: don't count blocking select! call as a loop-turn time
191         let _p = profile::span("GlobalState::handle_event");
192
193         tracing::debug!("handle_event({:?})", event);
194         let task_queue_len = self.task_pool.handle.len();
195         if task_queue_len > 0 {
196             tracing::info!("task queue len: {}", task_queue_len);
197         }
198
199         let was_quiescent = self.is_quiescent();
200         match event {
201             Event::Lsp(msg) => match msg {
202                 lsp_server::Message::Request(req) => self.on_new_request(loop_start, req),
203                 lsp_server::Message::Notification(not) => {
204                     self.on_notification(not)?;
205                 }
206                 lsp_server::Message::Response(resp) => self.complete_request(resp),
207             },
208             Event::Task(mut task) => {
209                 let _p = profile::span("GlobalState::handle_event/task");
210                 let mut prime_caches_progress = Vec::new();
211                 loop {
212                     match task {
213                         Task::Response(response) => self.respond(response),
214                         Task::Retry(req) => self.on_request(req),
215                         Task::Diagnostics(diagnostics_per_file) => {
216                             for (file_id, diagnostics) in diagnostics_per_file {
217                                 self.diagnostics.set_native_diagnostics(file_id, diagnostics)
218                             }
219                         }
220                         Task::PrimeCaches(progress) => match progress {
221                             PrimeCachesProgress::Begin => prime_caches_progress.push(progress),
222                             PrimeCachesProgress::Report(_) => {
223                                 match prime_caches_progress.last_mut() {
224                                     Some(last @ PrimeCachesProgress::Report(_)) => {
225                                         // Coalesce subsequent update events.
226                                         *last = progress;
227                                     }
228                                     _ => prime_caches_progress.push(progress),
229                                 }
230                             }
231                             PrimeCachesProgress::End { .. } => prime_caches_progress.push(progress),
232                         },
233                         Task::FetchWorkspace(progress) => {
234                             let (state, msg) = match progress {
235                                 ProjectWorkspaceProgress::Begin => (Progress::Begin, None),
236                                 ProjectWorkspaceProgress::Report(msg) => {
237                                     (Progress::Report, Some(msg))
238                                 }
239                                 ProjectWorkspaceProgress::End(workspaces) => {
240                                     self.fetch_workspaces_queue.op_completed(workspaces);
241
242                                     let old = Arc::clone(&self.workspaces);
243                                     self.switch_workspaces("fetched workspace".to_string());
244                                     let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);
245
246                                     if self.config.run_build_scripts() && workspaces_updated {
247                                         self.fetch_build_data_queue
248                                             .request_op(format!("workspace updated"));
249                                     }
250
251                                     (Progress::End, None)
252                                 }
253                             };
254
255                             self.report_progress("Fetching", state, msg, None);
256                         }
257                         Task::FetchBuildData(progress) => {
258                             let (state, msg) = match progress {
259                                 BuildDataProgress::Begin => (Some(Progress::Begin), None),
260                                 BuildDataProgress::Report(msg) => {
261                                     (Some(Progress::Report), Some(msg))
262                                 }
263                                 BuildDataProgress::End(build_data_result) => {
264                                     self.fetch_build_data_queue.op_completed(build_data_result);
265
266                                     self.switch_workspaces("fetched build data".to_string());
267
268                                     (Some(Progress::End), None)
269                                 }
270                             };
271
272                             if let Some(state) = state {
273                                 self.report_progress("Loading", state, msg, None);
274                             }
275                         }
276                     }
277
278                     // Coalesce multiple task events into one loop turn
279                     task = match self.task_pool.receiver.try_recv() {
280                         Ok(task) => task,
281                         Err(_) => break,
282                     };
283                 }
284
285                 for progress in prime_caches_progress {
286                     let (state, message, fraction);
287                     match progress {
288                         PrimeCachesProgress::Begin => {
289                             state = Progress::Begin;
290                             message = None;
291                             fraction = 0.0;
292                         }
293                         PrimeCachesProgress::Report(report) => {
294                             state = Progress::Report;
295
296                             message = match &report.crates_currently_indexing[..] {
297                                 [crate_name] => Some(format!(
298                                     "{}/{} ({})",
299                                     report.crates_done, report.crates_total, crate_name
300                                 )),
301                                 [crate_name, rest @ ..] => Some(format!(
302                                     "{}/{} ({} + {} more)",
303                                     report.crates_done,
304                                     report.crates_total,
305                                     crate_name,
306                                     rest.len()
307                                 )),
308                                 _ => None,
309                             };
310
311                             fraction = Progress::fraction(report.crates_done, report.crates_total);
312                         }
313                         PrimeCachesProgress::End { cancelled } => {
314                             state = Progress::End;
315                             message = None;
316                             fraction = 1.0;
317
318                             self.prime_caches_queue.op_completed(());
319                             if cancelled {
320                                 self.prime_caches_queue
321                                     .request_op("restart after cancellation".to_string());
322                             }
323                         }
324                     };
325
326                     self.report_progress("Indexing", state, message, Some(fraction));
327                 }
328             }
329             Event::Vfs(mut task) => {
330                 let _p = profile::span("GlobalState::handle_event/vfs");
331                 loop {
332                     match task {
333                         vfs::loader::Message::Loaded { files } => {
334                             let vfs = &mut self.vfs.write().0;
335                             for (path, contents) in files {
336                                 let path = VfsPath::from(path);
337                                 if !self.mem_docs.contains(&path) {
338                                     vfs.set_file_contents(path, contents);
339                                 }
340                             }
341                         }
342                         vfs::loader::Message::Progress { n_total, n_done, config_version } => {
343                             always!(config_version <= self.vfs_config_version);
344
345                             self.vfs_progress_config_version = config_version;
346                             self.vfs_progress_n_total = n_total;
347                             self.vfs_progress_n_done = n_done;
348
349                             let state = if n_done == 0 {
350                                 Progress::Begin
351                             } else if n_done < n_total {
352                                 Progress::Report
353                             } else {
354                                 assert_eq!(n_done, n_total);
355                                 Progress::End
356                             };
357                             self.report_progress(
358                                 "Roots Scanned",
359                                 state,
360                                 Some(format!("{}/{}", n_done, n_total)),
361                                 Some(Progress::fraction(n_done, n_total)),
362                             )
363                         }
364                     }
365                     // Coalesce many VFS event into a single loop turn
366                     task = match self.loader.receiver.try_recv() {
367                         Ok(task) => task,
368                         Err(_) => break,
369                     }
370                 }
371             }
372             Event::Flycheck(mut task) => {
373                 let _p = profile::span("GlobalState::handle_event/flycheck");
374                 loop {
375                     match task {
376                         flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => {
377                             let snap = self.snapshot();
378                             let diagnostics =
379                                 crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
380                                     &self.config.diagnostics_map(),
381                                     &diagnostic,
382                                     &workspace_root,
383                                     &snap,
384                                 );
385                             for diag in diagnostics {
386                                 match url_to_file_id(&self.vfs.read().0, &diag.url) {
387                                     Ok(file_id) => self.diagnostics.add_check_diagnostic(
388                                         id,
389                                         file_id,
390                                         diag.diagnostic,
391                                         diag.fix,
392                                     ),
393                                     Err(err) => {
394                                         tracing::error!(
395                                             "File with cargo diagnostic not found in VFS: {}",
396                                             err
397                                         );
398                                     }
399                                 };
400                             }
401                         }
402
403                         flycheck::Message::Progress { id, progress } => {
404                             let (state, message) = match progress {
405                                 flycheck::Progress::DidStart => {
406                                     self.diagnostics.clear_check(id);
407                                     (Progress::Begin, None)
408                                 }
409                                 flycheck::Progress::DidCheckCrate(target) => {
410                                     (Progress::Report, Some(target))
411                                 }
412                                 flycheck::Progress::DidCancel => (Progress::End, None),
413                                 flycheck::Progress::DidFinish(result) => {
414                                     if let Err(err) = result {
415                                         self.show_and_log_error(
416                                             "cargo check failed".to_string(),
417                                             Some(err.to_string()),
418                                         );
419                                     }
420                                     (Progress::End, None)
421                                 }
422                             };
423
424                             // When we're running multiple flychecks, we have to include a disambiguator in
425                             // the title, or the editor complains. Note that this is a user-facing string.
426                             let title = if self.flycheck.len() == 1 {
427                                 match self.config.flycheck() {
428                                     Some(config) => format!("{}", config),
429                                     None => "cargo check".to_string(),
430                                 }
431                             } else {
432                                 format!("cargo check (#{})", id + 1)
433                             };
434                             self.report_progress(&title, state, message, None);
435                         }
436                     }
437                     // Coalesce many flycheck updates into a single loop turn
438                     task = match self.flycheck_receiver.try_recv() {
439                         Ok(task) => task,
440                         Err(_) => break,
441                     }
442                 }
443             }
444         }
445
446         let state_changed = self.process_changes();
447         let memdocs_added_or_removed = self.mem_docs.take_changes();
448
449         if self.is_quiescent() {
450             if !was_quiescent
451                 && !self.fetch_workspaces_queue.op_requested()
452                 && !self.fetch_build_data_queue.op_requested()
453             {
454                 for flycheck in &self.flycheck {
455                     flycheck.update();
456                 }
457                 if self.config.prefill_caches() {
458                     self.prime_caches_queue.request_op("became quiescent".to_string());
459                 }
460             }
461
462             if !was_quiescent || state_changed {
463                 // Refresh semantic tokens if the client supports it.
464                 if self.config.semantic_tokens_refresh() {
465                     self.semantic_tokens_cache.lock().clear();
466                     self.send_request::<lsp_types::request::SemanticTokensRefresh>((), |_, _| ());
467                 }
468
469                 // Refresh code lens if the client supports it.
470                 if self.config.code_lens_refresh() {
471                     self.send_request::<lsp_types::request::CodeLensRefresh>((), |_, _| ());
472                 }
473             }
474
475             if !was_quiescent || state_changed || memdocs_added_or_removed {
476                 if self.config.publish_diagnostics() {
477                     self.update_diagnostics()
478                 }
479             }
480         }
481
482         if let Some(diagnostic_changes) = self.diagnostics.take_changes() {
483             for file_id in diagnostic_changes {
484                 let db = self.analysis_host.raw_database();
485                 let source_root = db.file_source_root(file_id);
486                 if db.source_root(source_root).is_library {
487                     // Only publish diagnostics for files in the workspace, not from crates.io deps
488                     // or the sysroot.
489                     // While theoretically these should never have errors, we have quite a few false
490                     // positives particularly in the stdlib, and those diagnostics would stay around
491                     // forever if we emitted them here.
492                     continue;
493                 }
494
495                 let url = file_id_to_url(&self.vfs.read().0, file_id);
496                 let mut diagnostics =
497                     self.diagnostics.diagnostics_for(file_id).cloned().collect::<Vec<_>>();
498                 // https://github.com/rust-lang/rust-analyzer/issues/11404
499                 for d in &mut diagnostics {
500                     if d.message.is_empty() {
501                         d.message = " ".to_string();
502                     }
503                     if let Some(rds) = d.related_information.as_mut() {
504                         for rd in rds {
505                             if rd.message.is_empty() {
506                                 rd.message = " ".to_string();
507                             }
508                         }
509                     }
510                 }
511                 let version = from_proto::vfs_path(&url)
512                     .map(|path| self.mem_docs.get(&path).map(|it| it.version))
513                     .unwrap_or_default();
514
515                 self.send_notification::<lsp_types::notification::PublishDiagnostics>(
516                     lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version },
517                 );
518             }
519         }
520
521         if self.config.cargo_autoreload() {
522             if let Some(cause) = self.fetch_workspaces_queue.should_start_op() {
523                 self.fetch_workspaces(cause);
524             }
525         }
526
527         if !self.fetch_workspaces_queue.op_in_progress() {
528             if let Some(cause) = self.fetch_build_data_queue.should_start_op() {
529                 self.fetch_build_data(cause);
530             }
531         }
532
533         if let Some(cause) = self.prime_caches_queue.should_start_op() {
534             tracing::debug!(%cause, "will prime caches");
535             let num_worker_threads = self.config.prime_caches_num_threads();
536
537             self.task_pool.handle.spawn_with_sender({
538                 let analysis = self.snapshot().analysis;
539                 move |sender| {
540                     sender.send(Task::PrimeCaches(PrimeCachesProgress::Begin)).unwrap();
541                     let res = analysis.parallel_prime_caches(num_worker_threads, |progress| {
542                         let report = PrimeCachesProgress::Report(progress);
543                         sender.send(Task::PrimeCaches(report)).unwrap();
544                     });
545                     sender
546                         .send(Task::PrimeCaches(PrimeCachesProgress::End {
547                             cancelled: res.is_err(),
548                         }))
549                         .unwrap();
550                 }
551             });
552         }
553
554         let status = self.current_status();
555         if self.last_reported_status.as_ref() != Some(&status) {
556             self.last_reported_status = Some(status.clone());
557
558             if let (lsp_ext::Health::Error, Some(message)) = (status.health, &status.message) {
559                 self.show_message(lsp_types::MessageType::ERROR, message.clone());
560             }
561
562             if self.config.server_status_notification() {
563                 self.send_notification::<lsp_ext::ServerStatusNotification>(status);
564             }
565         }
566
567         let loop_duration = loop_start.elapsed();
568         if loop_duration > Duration::from_millis(100) && was_quiescent {
569             tracing::warn!("overly long loop turn: {:?}", loop_duration);
570             self.poke_rust_analyzer_developer(format!(
571                 "overly long loop turn: {:?}",
572                 loop_duration
573             ));
574         }
575         Ok(())
576     }
577
578     fn on_new_request(&mut self, request_received: Instant, req: Request) {
579         self.register_request(&req, request_received);
580         self.on_request(req);
581     }
582
583     fn on_request(&mut self, req: Request) {
584         if self.shutdown_requested {
585             self.respond(lsp_server::Response::new_err(
586                 req.id,
587                 lsp_server::ErrorCode::InvalidRequest as i32,
588                 "Shutdown already requested.".to_owned(),
589             ));
590             return;
591         }
592
593         // Avoid flashing a bunch of unresolved references during initial load.
594         if self.workspaces.is_empty() && !self.is_quiescent() {
595             self.respond(lsp_server::Response::new_err(
596                 req.id,
597                 lsp_server::ErrorCode::ContentModified as i32,
598                 "waiting for cargo metadata or cargo check".to_owned(),
599             ));
600             return;
601         }
602
603         RequestDispatcher { req: Some(req), global_state: self }
604             .on_sync_mut::<lsp_types::request::Shutdown>(|s, ()| {
605                 s.shutdown_requested = true;
606                 Ok(())
607             })
608             .on_sync_mut::<lsp_ext::ReloadWorkspace>(handlers::handle_workspace_reload)
609             .on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)
610             .on_sync_mut::<lsp_ext::ShuffleCrateGraph>(handlers::handle_shuffle_crate_graph)
611             .on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)
612             .on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)
613             .on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range)
614             .on_sync::<lsp_ext::MatchingBrace>(handlers::handle_matching_brace)
615             .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
616             .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
617             .on::<lsp_ext::ViewHir>(handlers::handle_view_hir)
618             .on::<lsp_ext::ViewFileText>(handlers::handle_view_file_text)
619             .on::<lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph)
620             .on::<lsp_ext::ViewItemTree>(handlers::handle_view_item_tree)
621             .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
622             .on::<lsp_ext::ParentModule>(handlers::handle_parent_module)
623             .on::<lsp_ext::Runnables>(handlers::handle_runnables)
624             .on::<lsp_ext::RelatedTests>(handlers::handle_related_tests)
625             .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action)
626             .on::<lsp_ext::CodeActionResolveRequest>(handlers::handle_code_action_resolve)
627             .on::<lsp_ext::HoverRequest>(handlers::handle_hover)
628             .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs)
629             .on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
630             .on::<lsp_ext::MoveItem>(handlers::handle_move_item)
631             .on::<lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
632             .on::<lsp_ext::OnTypeFormatting>(handlers::handle_on_type_formatting)
633             .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)
634             .on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition)
635             .on::<lsp_types::request::GotoDeclaration>(handlers::handle_goto_declaration)
636             .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)
637             .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
638             .on::<lsp_types::request::InlayHintRequest>(handlers::handle_inlay_hints)
639             .on::<lsp_types::request::InlayHintResolveRequest>(handlers::handle_inlay_hints_resolve)
640             .on::<lsp_types::request::Completion>(handlers::handle_completion)
641             .on::<lsp_types::request::ResolveCompletionItem>(handlers::handle_completion_resolve)
642             .on::<lsp_types::request::CodeLensRequest>(handlers::handle_code_lens)
643             .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)
644             .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)
645             .on::<lsp_types::request::SignatureHelpRequest>(handlers::handle_signature_help)
646             .on::<lsp_types::request::PrepareRenameRequest>(handlers::handle_prepare_rename)
647             .on::<lsp_types::request::Rename>(handlers::handle_rename)
648             .on::<lsp_types::request::References>(handlers::handle_references)
649             .on::<lsp_types::request::Formatting>(handlers::handle_formatting)
650             .on::<lsp_types::request::RangeFormatting>(handlers::handle_range_formatting)
651             .on::<lsp_types::request::DocumentHighlightRequest>(handlers::handle_document_highlight)
652             .on::<lsp_types::request::CallHierarchyPrepare>(handlers::handle_call_hierarchy_prepare)
653             .on::<lsp_types::request::CallHierarchyIncomingCalls>(
654                 handlers::handle_call_hierarchy_incoming,
655             )
656             .on::<lsp_types::request::CallHierarchyOutgoingCalls>(
657                 handlers::handle_call_hierarchy_outgoing,
658             )
659             .on::<lsp_types::request::SemanticTokensFullRequest>(
660                 handlers::handle_semantic_tokens_full,
661             )
662             .on::<lsp_types::request::SemanticTokensFullDeltaRequest>(
663                 handlers::handle_semantic_tokens_full_delta,
664             )
665             .on::<lsp_types::request::SemanticTokensRangeRequest>(
666                 handlers::handle_semantic_tokens_range,
667             )
668             .on::<lsp_types::request::WillRenameFiles>(handlers::handle_will_rename_files)
669             .on::<lsp_ext::Ssr>(handlers::handle_ssr)
670             .finish();
671     }
672
673     fn on_notification(&mut self, not: Notification) -> Result<()> {
674         NotificationDispatcher { not: Some(not), global_state: self }
675             .on::<lsp_types::notification::Cancel>(|this, params| {
676                 let id: lsp_server::RequestId = match params.id {
677                     lsp_types::NumberOrString::Number(id) => id.into(),
678                     lsp_types::NumberOrString::String(id) => id.into(),
679                 };
680                 this.cancel(id);
681                 Ok(())
682             })?
683             .on::<lsp_types::notification::WorkDoneProgressCancel>(|_this, _params| {
684                 // Just ignore this. It is OK to continue sending progress
685                 // notifications for this token, as the client can't know when
686                 // we accepted notification.
687                 Ok(())
688             })?
689             .on::<lsp_types::notification::DidOpenTextDocument>(|this, params| {
690                 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
691                     let already_exists = this
692                         .mem_docs
693                         .insert(path.clone(), DocumentData::new(params.text_document.version))
694                         .is_err();
695                     if already_exists {
696                         tracing::error!("duplicate DidOpenTextDocument: {}", path)
697                     }
698                     this.vfs
699                         .write()
700                         .0
701                         .set_file_contents(path, Some(params.text_document.text.into_bytes()));
702                 }
703                 Ok(())
704             })?
705             .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| {
706                 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
707                     match this.mem_docs.get_mut(&path) {
708                         Some(doc) => {
709                             // The version passed in DidChangeTextDocument is the version after all edits are applied
710                             // so we should apply it before the vfs is notified.
711                             doc.version = params.text_document.version;
712                         }
713                         None => {
714                             tracing::error!("unexpected DidChangeTextDocument: {}", path);
715                             return Ok(());
716                         }
717                     };
718
719                     let vfs = &mut this.vfs.write().0;
720                     let file_id = vfs.file_id(&path).unwrap();
721                     let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap();
722                     apply_document_changes(&mut text, params.content_changes);
723
724                     vfs.set_file_contents(path, Some(text.into_bytes()));
725                 }
726                 Ok(())
727             })?
728             .on::<lsp_types::notification::DidCloseTextDocument>(|this, params| {
729                 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
730                     if this.mem_docs.remove(&path).is_err() {
731                         tracing::error!("orphan DidCloseTextDocument: {}", path);
732                     }
733
734                     this.semantic_tokens_cache.lock().remove(&params.text_document.uri);
735
736                     if let Some(path) = path.as_path() {
737                         this.loader.handle.invalidate(path.to_path_buf());
738                     }
739                 }
740                 Ok(())
741             })?
742             .on::<lsp_types::notification::DidSaveTextDocument>(|this, params| {
743                 let mut updated = false;
744                 if let Ok(vfs_path) = from_proto::vfs_path(&params.text_document.uri) {
745                     let (vfs, _) = &*this.vfs.read();
746                     if let Some(file_id) = vfs.file_id(&vfs_path) {
747                         let analysis = this.analysis_host.analysis();
748                         // Crates containing or depending on the saved file
749                         let crate_ids: Vec<_> = analysis
750                             .crate_for(file_id)?
751                             .into_iter()
752                             .flat_map(|id| {
753                                 this.analysis_host
754                                     .raw_database()
755                                     .crate_graph()
756                                     .transitive_rev_deps(id)
757                             })
758                             .sorted()
759                             .unique()
760                             .collect();
761
762                         let crate_root_paths: Vec<_> = crate_ids
763                             .iter()
764                             .filter_map(|&crate_id| {
765                                 analysis
766                                     .crate_root(crate_id)
767                                     .map(|file_id| {
768                                         vfs.file_path(file_id).as_path().map(ToOwned::to_owned)
769                                     })
770                                     .transpose()
771                             })
772                             .collect::<ide::Cancellable<_>>()?;
773                         let crate_root_paths: Vec<_> =
774                             crate_root_paths.iter().map(Deref::deref).collect();
775
776                         // Find all workspaces that have at least one target containing the saved file
777                         let workspace_ids =
778                             this.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
779                                 project_model::ProjectWorkspace::Cargo { cargo, .. } => {
780                                     cargo.packages().any(|pkg| {
781                                         cargo[pkg].targets.iter().any(|&it| {
782                                             crate_root_paths.contains(&cargo[it].root.as_path())
783                                         })
784                                     })
785                                 }
786                                 project_model::ProjectWorkspace::Json { project, .. } => project
787                                     .crates()
788                                     .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)),
789                                 project_model::ProjectWorkspace::DetachedFiles { .. } => false,
790                             });
791
792                         // Find and trigger corresponding flychecks
793                         for flycheck in &this.flycheck {
794                             for (id, _) in workspace_ids.clone() {
795                                 if id == flycheck.id() {
796                                     updated = true;
797                                     flycheck.update();
798                                     continue;
799                                 }
800                             }
801                         }
802                     }
803                     if let Some(abs_path) = vfs_path.as_path() {
804                         if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) {
805                             this.fetch_workspaces_queue
806                                 .request_op(format!("DidSaveTextDocument {}", abs_path.display()));
807                         }
808                     }
809                 }
810                 if !updated {
811                     for flycheck in &this.flycheck {
812                         flycheck.update();
813                     }
814                 }
815                 Ok(())
816             })?
817             .on::<lsp_types::notification::DidChangeConfiguration>(|this, _params| {
818                 // As stated in https://github.com/microsoft/language-server-protocol/issues/676,
819                 // this notification's parameters should be ignored and the actual config queried separately.
820                 this.send_request::<lsp_types::request::WorkspaceConfiguration>(
821                     lsp_types::ConfigurationParams {
822                         items: vec![lsp_types::ConfigurationItem {
823                             scope_uri: None,
824                             section: Some("rust-analyzer".to_string()),
825                         }],
826                     },
827                     |this, resp| {
828                         tracing::debug!("config update response: '{:?}", resp);
829                         let lsp_server::Response { error, result, .. } = resp;
830
831                         match (error, result) {
832                             (Some(err), _) => {
833                                 tracing::error!("failed to fetch the server settings: {:?}", err)
834                             }
835                             (None, Some(mut configs)) => {
836                                 if let Some(json) = configs.get_mut(0) {
837                                     // Note that json can be null according to the spec if the client can't
838                                     // provide a configuration. This is handled in Config::update below.
839                                     let mut config = Config::clone(&*this.config);
840                                     if let Err(error) = config.update(json.take()) {
841                                         this.show_message(
842                                             lsp_types::MessageType::WARNING,
843                                             error.to_string(),
844                                         );
845                                     }
846                                     this.update_configuration(config);
847                                 }
848                             }
849                             (None, None) => tracing::error!(
850                                 "received empty server settings response from the client"
851                             ),
852                         }
853                     },
854                 );
855
856                 Ok(())
857             })?
858             .on::<lsp_types::notification::DidChangeWatchedFiles>(|this, params| {
859                 for change in params.changes {
860                     if let Ok(path) = from_proto::abs_path(&change.uri) {
861                         this.loader.handle.invalidate(path);
862                     }
863                 }
864                 Ok(())
865             })?
866             .finish();
867         Ok(())
868     }
869
870     fn update_diagnostics(&mut self) {
871         let subscriptions = self
872             .mem_docs
873             .iter()
874             .map(|path| self.vfs.read().0.file_id(path).unwrap())
875             .collect::<Vec<_>>();
876
877         tracing::trace!("updating notifications for {:?}", subscriptions);
878
879         let snapshot = self.snapshot();
880         self.task_pool.handle.spawn(move || {
881             let diagnostics = subscriptions
882                 .into_iter()
883                 .filter_map(|file_id| {
884                     handlers::publish_diagnostics(&snapshot, file_id)
885                         .ok()
886                         .map(|diags| (file_id, diags))
887                 })
888                 .collect::<Vec<_>>();
889             Task::Diagnostics(diagnostics)
890         })
891     }
892 }