1use std::{
5 fmt,
6 ops::Div as _,
7 panic::AssertUnwindSafe,
8 time::{Duration, Instant},
9};
10
11use crossbeam_channel::{Receiver, never, select};
12use ide_db::base_db::{SourceDatabase, VfsPath};
13use lsp_server::{Connection, Notification, Request};
14use lsp_types::{TextDocumentIdentifier, notification::Notification as _};
15use stdx::thread::ThreadIntent;
16use tracing::{Level, error, span};
17use vfs::{AbsPathBuf, FileId, loader::LoadingProgress};
18
19use crate::{
20 config::Config,
21 diagnostics::{DiagnosticsGeneration, NativeDiagnosticsFetchKind, fetch_native_diagnostics},
22 discover::{DiscoverArgument, DiscoverCommand, DiscoverProjectMessage},
23 flycheck::{self, ClearDiagnosticsKind, ClearScope, FlycheckMessage},
24 global_state::{
25 FetchBuildDataResponse, FetchWorkspaceRequest, FetchWorkspaceResponse, GlobalState,
26 file_id_to_url, url_to_file_id,
27 },
28 handlers::{
29 dispatch::{NotificationDispatcher, RequestDispatcher},
30 request::empty_diagnostic_report,
31 },
32 lsp::{
33 from_proto, to_proto,
34 utils::{Progress, notification_is},
35 },
36 lsp_ext,
37 reload::{BuildDataProgress, ProcMacroProgress, ProjectWorkspaceProgress},
38 test_runner::{CargoTestMessage, CargoTestOutput, TestState},
39};
40
41pub fn main_loop(config: Config, connection: Connection) -> anyhow::Result<()> {
42 tracing::info!("initial config: {:#?}", config);
43
44 #[cfg(windows)]
56 unsafe {
57 use windows_sys::Win32::System::Threading::*;
58 let thread = GetCurrentThread();
59 let thread_priority_above_normal = 1;
60 SetThreadPriority(thread, thread_priority_above_normal);
61 }
62
63 #[cfg(feature = "dhat")]
64 {
65 if let Some(dhat_output_file) = config.dhat_output_file() {
66 *crate::DHAT_PROFILER.lock().unwrap() =
67 Some(dhat::Profiler::builder().file_name(&dhat_output_file).build());
68 }
69 }
70
71 GlobalState::new(connection.sender, config).run(connection.receiver)
72}
73
74enum Event {
75 Lsp(lsp_server::Message),
76 Task(Task),
77 DeferredTask(DeferredTask),
78 Vfs(vfs::loader::Message),
79 Flycheck(FlycheckMessage),
80 TestResult(CargoTestMessage),
81 DiscoverProject(DiscoverProjectMessage),
82 FetchWorkspaces(FetchWorkspaceRequest),
83}
84
85impl fmt::Display for Event {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 match self {
88 Event::Lsp(_) => write!(f, "Event::Lsp"),
89 Event::Task(_) => write!(f, "Event::Task"),
90 Event::Vfs(_) => write!(f, "Event::Vfs"),
91 Event::Flycheck(_) => write!(f, "Event::Flycheck"),
92 Event::DeferredTask(_) => write!(f, "Event::DeferredTask"),
93 Event::TestResult(_) => write!(f, "Event::TestResult"),
94 Event::DiscoverProject(_) => write!(f, "Event::DiscoverProject"),
95 Event::FetchWorkspaces(_) => write!(f, "Event::FetchWorkspaces"),
96 }
97 }
98}
99
100#[derive(Debug)]
101pub(crate) enum DeferredTask {
102 CheckIfIndexed(lsp_types::Url),
103 CheckProcMacroSources(Vec<FileId>),
104}
105
106#[derive(Debug)]
107pub(crate) enum DiagnosticsTaskKind {
108 Syntax(DiagnosticsGeneration, Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
109 Semantic(DiagnosticsGeneration, Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
110}
111
112#[derive(Debug)]
113pub(crate) enum Task {
114 Response(lsp_server::Response),
115 DiscoverLinkedProjects(DiscoverProjectParam),
116 Retry(lsp_server::Request),
117 Diagnostics(DiagnosticsTaskKind),
118 DiscoverTest(lsp_ext::DiscoverTestResults),
119 PrimeCaches(PrimeCachesProgress),
120 FetchWorkspace(ProjectWorkspaceProgress),
121 FetchBuildData(BuildDataProgress),
122 LoadProcMacros(ProcMacroProgress),
123 BuildDepsHaveChanged,
125}
126
127#[derive(Debug)]
128pub(crate) enum DiscoverProjectParam {
129 Buildfile(AbsPathBuf),
130 Path(AbsPathBuf),
131}
132
133#[derive(Debug)]
134pub(crate) enum PrimeCachesProgress {
135 Begin,
136 Report(ide::ParallelPrimeCachesProgress),
137 End { cancelled: bool },
138}
139
140impl fmt::Debug for Event {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 let debug_non_verbose = |not: &Notification, f: &mut fmt::Formatter<'_>| {
143 f.debug_struct("Notification").field("method", ¬.method).finish()
144 };
145
146 match self {
147 Event::Lsp(lsp_server::Message::Notification(not))
148 if (notification_is::<lsp_types::notification::DidOpenTextDocument>(not)
149 || notification_is::<lsp_types::notification::DidChangeTextDocument>(not)) =>
150 {
151 return debug_non_verbose(not, f);
152 }
153 Event::Task(Task::Response(resp)) => {
154 return f
155 .debug_struct("Response")
156 .field("id", &resp.id)
157 .field("error", &resp.error)
158 .finish();
159 }
160 _ => (),
161 }
162
163 match self {
164 Event::Lsp(it) => fmt::Debug::fmt(it, f),
165 Event::Task(it) => fmt::Debug::fmt(it, f),
166 Event::DeferredTask(it) => fmt::Debug::fmt(it, f),
167 Event::Vfs(it) => fmt::Debug::fmt(it, f),
168 Event::Flycheck(it) => fmt::Debug::fmt(it, f),
169 Event::TestResult(it) => fmt::Debug::fmt(it, f),
170 Event::DiscoverProject(it) => fmt::Debug::fmt(it, f),
171 Event::FetchWorkspaces(it) => fmt::Debug::fmt(it, f),
172 }
173 }
174}
175
176impl GlobalState {
177 fn run(mut self, inbox: Receiver<lsp_server::Message>) -> anyhow::Result<()> {
178 self.update_status_or_notify();
179
180 if self.config.did_save_text_document_dynamic_registration() {
181 let additional_patterns = self
182 .config
183 .discover_workspace_config()
184 .map(|cfg| cfg.files_to_watch.clone().into_iter())
185 .into_iter()
186 .flatten()
187 .map(|f| format!("**/{f}"));
188 self.register_did_save_capability(additional_patterns);
189 }
190
191 if self.config.discover_workspace_config().is_none() {
192 self.fetch_workspaces_queue.request_op(
193 "startup".to_owned(),
194 FetchWorkspaceRequest { path: None, force_crate_graph_reload: false },
195 );
196 if let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) =
197 self.fetch_workspaces_queue.should_start_op()
198 {
199 self.fetch_workspaces(cause, path, force_crate_graph_reload);
200 }
201 }
202
203 while let Ok(event) = self.next_event(&inbox) {
204 let Some(event) = event else {
205 anyhow::bail!("client exited without proper shutdown sequence");
206 };
207 if matches!(
208 &event,
209 Event::Lsp(lsp_server::Message::Notification(Notification { method, .. }))
210 if method == lsp_types::notification::Exit::METHOD
211 ) {
212 return Ok(());
213 }
214 self.handle_event(event);
215 }
216
217 Err(anyhow::anyhow!("A receiver has been dropped, something panicked!"))
218 }
219
220 fn register_did_save_capability(&mut self, additional_patterns: impl Iterator<Item = String>) {
221 let additional_filters = additional_patterns.map(|pattern| lsp_types::DocumentFilter {
222 language: None,
223 scheme: None,
224 pattern: (Some(pattern)),
225 });
226
227 let mut selectors = vec![
228 lsp_types::DocumentFilter {
229 language: None,
230 scheme: None,
231 pattern: Some("**/*.rs".into()),
232 },
233 lsp_types::DocumentFilter {
234 language: None,
235 scheme: None,
236 pattern: Some("**/Cargo.toml".into()),
237 },
238 lsp_types::DocumentFilter {
239 language: None,
240 scheme: None,
241 pattern: Some("**/Cargo.lock".into()),
242 },
243 ];
244 selectors.extend(additional_filters);
245
246 let save_registration_options = lsp_types::TextDocumentSaveRegistrationOptions {
247 include_text: Some(false),
248 text_document_registration_options: lsp_types::TextDocumentRegistrationOptions {
249 document_selector: Some(selectors),
250 },
251 };
252
253 let registration = lsp_types::Registration {
254 id: "textDocument/didSave".to_owned(),
255 method: "textDocument/didSave".to_owned(),
256 register_options: Some(serde_json::to_value(save_registration_options).unwrap()),
257 };
258 self.send_request::<lsp_types::request::RegisterCapability>(
259 lsp_types::RegistrationParams { registrations: vec![registration] },
260 |_, _| (),
261 );
262 }
263
264 fn next_event(
265 &mut self,
266 inbox: &Receiver<lsp_server::Message>,
267 ) -> Result<Option<Event>, crossbeam_channel::RecvError> {
268 if let Ok(task) = self.fmt_pool.receiver.try_recv() {
270 return Ok(Some(Event::Task(task)));
271 }
272
273 select! {
274 recv(inbox) -> msg =>
275 return Ok(msg.ok().map(Event::Lsp)),
276
277 recv(self.task_pool.receiver) -> task =>
278 task.map(Event::Task),
279
280 recv(self.deferred_task_queue.receiver) -> task =>
281 task.map(Event::DeferredTask),
282
283 recv(self.fmt_pool.receiver) -> task =>
284 task.map(Event::Task),
285
286 recv(self.loader.receiver) -> task =>
287 task.map(Event::Vfs),
288
289 recv(self.flycheck_receiver) -> task =>
290 task.map(Event::Flycheck),
291
292 recv(self.test_run_receiver) -> task =>
293 task.map(Event::TestResult),
294
295 recv(self.discover_receiver) -> task =>
296 task.map(Event::DiscoverProject),
297
298 recv(self.fetch_ws_receiver.as_ref().map_or(&never(), |(chan, _)| chan)) -> _instant => {
299 Ok(Event::FetchWorkspaces(self.fetch_ws_receiver.take().unwrap().1))
300 },
301 }
302 .map(Some)
303 }
304
305 fn handle_event(&mut self, event: Event) {
306 let loop_start = Instant::now();
307 let _p = tracing::info_span!("GlobalState::handle_event", event = %event).entered();
308
309 let event_dbg_msg = format!("{event:?}");
310 tracing::debug!(?loop_start, ?event, "handle_event");
311 if tracing::enabled!(tracing::Level::TRACE) {
312 let task_queue_len = self.task_pool.handle.len();
313 if task_queue_len > 0 {
314 tracing::trace!("task queue len: {}", task_queue_len);
315 }
316 }
317
318 let was_quiescent = self.is_quiescent();
319 match event {
320 Event::Lsp(msg) => match msg {
321 lsp_server::Message::Request(req) => self.on_new_request(loop_start, req),
322 lsp_server::Message::Notification(not) => self.on_notification(not),
323 lsp_server::Message::Response(resp) => self.complete_request(resp),
324 },
325 Event::DeferredTask(task) => {
326 let _p = tracing::info_span!("GlobalState::handle_event/queued_task").entered();
327 self.handle_deferred_task(task);
328 while let Ok(task) = self.deferred_task_queue.receiver.try_recv() {
330 self.handle_deferred_task(task);
331 }
332 }
333 Event::Task(task) => {
334 let _p = tracing::info_span!("GlobalState::handle_event/task").entered();
335 let mut prime_caches_progress = Vec::new();
336
337 self.handle_task(&mut prime_caches_progress, task);
338 while let Ok(task) = self.task_pool.receiver.try_recv() {
340 self.handle_task(&mut prime_caches_progress, task);
341 }
342
343 let title = "Indexing";
344 let cancel_token = Some("rustAnalyzer/cachePriming".to_owned());
345
346 let mut last_report = None;
347 for progress in prime_caches_progress {
348 match progress {
349 PrimeCachesProgress::Begin => {
350 self.report_progress(
351 title,
352 Progress::Begin,
353 None,
354 Some(0.0),
355 cancel_token.clone(),
356 );
357 }
358 PrimeCachesProgress::Report(report) => {
359 let message = match &*report.crates_currently_indexing {
360 [crate_name] => Some(format!(
361 "{}/{} ({})",
362 report.crates_done,
363 report.crates_total,
364 crate_name.as_str(),
365 )),
366 [crate_name, rest @ ..] => Some(format!(
367 "{}/{} ({} + {} more)",
368 report.crates_done,
369 report.crates_total,
370 crate_name.as_str(),
371 rest.len()
372 )),
373 _ => None,
374 };
375
376 last_report = Some((
379 message,
380 Progress::fraction(report.crates_done, report.crates_total),
381 report.work_type,
382 ));
383 }
384 PrimeCachesProgress::End { cancelled } => {
385 self.analysis_host.trigger_garbage_collection();
386 self.prime_caches_queue.op_completed(());
387 if cancelled {
388 self.prime_caches_queue
389 .request_op("restart after cancellation".to_owned(), ());
390 }
391 if let Some((message, fraction, title)) = last_report.take() {
392 self.report_progress(
393 title,
394 Progress::Report,
395 message,
396 Some(fraction),
397 cancel_token.clone(),
398 );
399 }
400 self.report_progress(
401 title,
402 Progress::End,
403 None,
404 Some(1.0),
405 cancel_token.clone(),
406 );
407 }
408 };
409 }
410 if let Some((message, fraction, title)) = last_report.take() {
411 self.report_progress(
412 title,
413 Progress::Report,
414 message,
415 Some(fraction),
416 cancel_token.clone(),
417 );
418 }
419 }
420 Event::Vfs(message) => {
421 let _p = tracing::info_span!("GlobalState::handle_event/vfs").entered();
422 let mut last_progress_report = None;
423 self.handle_vfs_msg(message, &mut last_progress_report);
424 while let Ok(message) = self.loader.receiver.try_recv() {
426 self.handle_vfs_msg(message, &mut last_progress_report);
427 }
428 if let Some((message, fraction)) = last_progress_report {
429 self.report_progress(
430 "Roots Scanned",
431 Progress::Report,
432 Some(message),
433 Some(fraction),
434 None,
435 );
436 }
437 }
438 Event::Flycheck(message) => {
439 let mut cargo_finished = false;
440 self.handle_flycheck_msg(message, &mut cargo_finished);
441 while let Ok(message) = self.flycheck_receiver.try_recv() {
443 self.handle_flycheck_msg(message, &mut cargo_finished);
444 }
445 if cargo_finished {
446 self.send_request::<lsp_types::request::WorkspaceDiagnosticRefresh>(
447 (),
448 |_, _| (),
449 );
450 }
451 }
452 Event::TestResult(message) => {
453 let _p = tracing::info_span!("GlobalState::handle_event/test_result").entered();
454 self.handle_cargo_test_msg(message);
455 while let Ok(message) = self.test_run_receiver.try_recv() {
457 self.handle_cargo_test_msg(message);
458 }
459 }
460 Event::DiscoverProject(message) => {
461 self.handle_discover_msg(message);
462 while let Ok(message) = self.discover_receiver.try_recv() {
464 self.handle_discover_msg(message);
465 }
466 }
467 Event::FetchWorkspaces(req) => {
468 self.fetch_workspaces_queue.request_op("project structure change".to_owned(), req)
469 }
470 }
471 let event_handling_duration = loop_start.elapsed();
472 let (state_changed, memdocs_added_or_removed) = if self.vfs_done {
473 if let Some(cause) = self.wants_to_switch.take() {
474 self.switch_workspaces(cause);
475 }
476 (self.process_changes(), self.mem_docs.take_changes())
477 } else {
478 (false, false)
479 };
480
481 if self.is_quiescent() {
482 let became_quiescent = !was_quiescent;
483 if became_quiescent {
484 if self.config.check_on_save(None)
485 && self.config.flycheck_workspace(None)
486 && !self.fetch_build_data_queue.op_requested()
487 {
488 self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None));
490 }
491 let proc_macros_loaded = self.config.prefill_caches()
493 && (!self.config.expand_proc_macros()
494 || self.fetch_proc_macros_queue.last_op_result().copied().unwrap_or(false));
495 if proc_macros_loaded {
496 self.prime_caches_queue.request_op("became quiescent".to_owned(), ());
497 }
498 }
499
500 let client_refresh = became_quiescent || state_changed;
501 if client_refresh {
502 if self.config.semantic_tokens_refresh() {
504 self.semantic_tokens_cache.lock().clear();
505 self.send_request::<lsp_types::request::SemanticTokensRefresh>((), |_, _| ());
506 }
507
508 if self.config.code_lens_refresh() {
510 self.send_request::<lsp_types::request::CodeLensRefresh>((), |_, _| ());
511 }
512
513 if self.config.inlay_hints_refresh() {
515 self.send_request::<lsp_types::request::InlayHintRefreshRequest>((), |_, _| ());
516 }
517
518 if self.config.diagnostics_refresh() {
519 self.send_request::<lsp_types::request::WorkspaceDiagnosticRefresh>(
520 (),
521 |_, _| (),
522 );
523 }
524 }
525
526 let project_or_mem_docs_changed =
527 became_quiescent || state_changed || memdocs_added_or_removed;
528 if project_or_mem_docs_changed
529 && !self.config.text_document_diagnostic()
530 && self.config.publish_diagnostics(None)
531 {
532 self.update_diagnostics();
533 }
534 if project_or_mem_docs_changed && self.config.test_explorer() {
535 self.update_tests();
536 }
537
538 let current_revision = self.analysis_host.raw_database().nonce_and_revision().1;
539 if self.task_pool.handle.is_empty()
541 && self.fmt_pool.handle.is_empty()
542 && current_revision != self.last_gc_revision
543 {
544 self.analysis_host.trigger_garbage_collection();
545 self.last_gc_revision = current_revision;
546 }
547 }
548
549 self.cleanup_discover_handles();
550
551 if let Some(diagnostic_changes) = self.diagnostics.take_changes() {
552 for file_id in diagnostic_changes {
553 let uri = file_id_to_url(&self.vfs.read().0, file_id);
554 let version = from_proto::vfs_path(&uri)
555 .ok()
556 .and_then(|path| self.mem_docs.get(&path).map(|it| it.version));
557
558 let diagnostics =
559 self.diagnostics.diagnostics_for(file_id).cloned().collect::<Vec<_>>();
560 self.publish_diagnostics(uri, version, diagnostics);
561 }
562 }
563
564 if (self.config.cargo_autoreload_config(None)
565 || self.config.discover_workspace_config().is_some())
566 && let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) =
567 self.fetch_workspaces_queue.should_start_op()
568 {
569 self.fetch_workspaces(cause, path, force_crate_graph_reload);
570 }
571
572 if !self.fetch_workspaces_queue.op_in_progress() {
573 if let Some((cause, ())) = self.fetch_build_data_queue.should_start_op() {
574 self.fetch_build_data(cause);
575 } else if let Some((cause, (change, paths))) =
576 self.fetch_proc_macros_queue.should_start_op()
577 {
578 self.fetch_proc_macros(cause, change, paths);
579 }
580 }
581
582 if let Some((cause, ())) = self.prime_caches_queue.should_start_op() {
583 self.prime_caches(cause);
584 }
585
586 self.update_status_or_notify();
587
588 let loop_duration = loop_start.elapsed();
589 if loop_duration > Duration::from_millis(100) && was_quiescent {
590 tracing::warn!(
591 "overly long loop turn took {loop_duration:?} (event handling took {event_handling_duration:?}): {event_dbg_msg}"
592 );
593 self.poke_rust_analyzer_developer(format!(
594 "overly long loop turn took {loop_duration:?} (event handling took {event_handling_duration:?}): {event_dbg_msg}"
595 ));
596 }
597 }
598
599 fn prime_caches(&mut self, cause: String) {
600 tracing::debug!(%cause, "will prime caches");
601 let num_worker_threads = self.config.prime_caches_num_threads();
602
603 self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, {
604 let analysis = AssertUnwindSafe(self.snapshot().analysis);
605 move |sender| {
606 sender.send(Task::PrimeCaches(PrimeCachesProgress::Begin)).unwrap();
607 let res = analysis.parallel_prime_caches(num_worker_threads, |progress| {
608 let report = PrimeCachesProgress::Report(progress);
609 sender.send(Task::PrimeCaches(report)).unwrap();
610 });
611 sender
612 .send(Task::PrimeCaches(PrimeCachesProgress::End { cancelled: res.is_err() }))
613 .unwrap();
614 }
615 });
616 }
617
618 fn update_diagnostics(&mut self) {
619 let db = self.analysis_host.raw_database();
620 let generation = self.diagnostics.next_generation();
621 let subscriptions = {
622 let vfs = &self.vfs.read().0;
623 self.mem_docs
624 .iter()
625 .map(|path| vfs.file_id(path).unwrap())
626 .filter_map(|(file_id, excluded)| {
627 (excluded == vfs::FileExcluded::No).then_some(file_id)
628 })
629 .filter(|&file_id| {
630 let source_root_id = db.file_source_root(file_id).source_root_id(db);
631 let source_root = db.source_root(source_root_id).source_root(db);
632 !source_root.is_library
638 })
639 .collect::<std::sync::Arc<_>>()
640 };
641 tracing::trace!("updating notifications for {:?}", subscriptions);
642 let max_tasks = self.config.main_loop_num_threads().div(4).max(1);
645 let chunk_length = subscriptions.len() / max_tasks;
646 let remainder = subscriptions.len() % max_tasks;
647
648 let mut start = 0;
649 for task_idx in 0..max_tasks {
650 let extra = if task_idx < remainder { 1 } else { 0 };
651 let end = start + chunk_length + extra;
652 let slice = start..end;
653 if slice.is_empty() {
654 break;
655 }
656 let snapshot = self.snapshot();
659 self.task_pool.handle.spawn_with_sender(ThreadIntent::LatencySensitive, {
660 let subscriptions = subscriptions.clone();
661 let fetch_semantic = self.vfs_done
670 && self.fetch_workspaces_queue.last_op_result().is_some()
671 && (!self.config.run_build_scripts(None)
672 || (self.fetch_build_data_queue.last_op_result().is_none()
673 && !self.fetch_build_data_queue.op_in_progress()))
674 && (!self.config.expand_proc_macros()
675 || (self.fetch_proc_macros_queue.last_op_result().is_none()
676 && !self.fetch_proc_macros_queue.op_in_progress()));
677 move |sender| {
678 let snapshot = AssertUnwindSafe(&snapshot);
680 let diags = std::panic::catch_unwind(|| {
681 fetch_native_diagnostics(
682 &snapshot,
683 subscriptions.clone(),
684 slice.clone(),
685 NativeDiagnosticsFetchKind::Syntax,
686 )
687 })
688 .unwrap_or_else(|_| {
689 subscriptions.iter().map(|&id| (id, Vec::new())).collect::<Vec<_>>()
690 });
691 sender
692 .send(Task::Diagnostics(DiagnosticsTaskKind::Syntax(generation, diags)))
693 .unwrap();
694
695 if fetch_semantic {
696 let diags = std::panic::catch_unwind(|| {
697 fetch_native_diagnostics(
698 &snapshot,
699 subscriptions.clone(),
700 slice.clone(),
701 NativeDiagnosticsFetchKind::Semantic,
702 )
703 })
704 .unwrap_or_else(|_| {
705 subscriptions.iter().map(|&id| (id, Vec::new())).collect::<Vec<_>>()
706 });
707 sender
708 .send(Task::Diagnostics(DiagnosticsTaskKind::Semantic(
709 generation, diags,
710 )))
711 .unwrap();
712 }
713 }
714 });
715 start = end;
716 }
717 }
718
719 fn update_tests(&mut self) {
720 if !self.vfs_done {
721 return;
722 }
723 let db = self.analysis_host.raw_database();
724 let subscriptions = self
725 .mem_docs
726 .iter()
727 .map(|path| self.vfs.read().0.file_id(path).unwrap())
728 .filter_map(|(file_id, excluded)| {
729 (excluded == vfs::FileExcluded::No).then_some(file_id)
730 })
731 .filter(|&file_id| {
732 let source_root_id = db.file_source_root(file_id).source_root_id(db);
733 let source_root = db.source_root(source_root_id).source_root(db);
734 !source_root.is_library
735 })
736 .collect::<Vec<_>>();
737 tracing::trace!("updating tests for {:?}", subscriptions);
738
739 self.task_pool.handle.spawn(ThreadIntent::LatencySensitive, {
742 let snapshot = self.snapshot();
743 move || {
744 let tests = subscriptions
745 .iter()
746 .copied()
747 .filter_map(|f| snapshot.analysis.discover_tests_in_file(f).ok())
748 .flatten()
749 .collect::<Vec<_>>();
750
751 Task::DiscoverTest(lsp_ext::DiscoverTestResults {
752 tests: tests
753 .into_iter()
754 .filter_map(|t| {
755 let line_index = t.file.and_then(|f| snapshot.file_line_index(f).ok());
756 to_proto::test_item(&snapshot, t, line_index.as_ref())
757 })
758 .collect(),
759 scope: None,
760 scope_file: Some(
761 subscriptions
762 .into_iter()
763 .map(|f| TextDocumentIdentifier { uri: to_proto::url(&snapshot, f) })
764 .collect(),
765 ),
766 })
767 }
768 });
769 }
770
771 fn update_status_or_notify(&mut self) {
772 let status = self.current_status();
773 if self.last_reported_status != status {
774 self.last_reported_status = status.clone();
775
776 if self.config.server_status_notification() {
777 self.send_notification::<lsp_ext::ServerStatusNotification>(status);
778 } else if let (
779 health @ (lsp_ext::Health::Warning | lsp_ext::Health::Error),
780 Some(message),
781 ) = (status.health, &status.message)
782 {
783 let open_log_button = tracing::enabled!(tracing::Level::ERROR)
784 && (self.fetch_build_data_error().is_err()
785 || self.fetch_workspace_error().is_err());
786 self.show_message(
787 match health {
788 lsp_ext::Health::Ok => lsp_types::MessageType::INFO,
789 lsp_ext::Health::Warning => lsp_types::MessageType::WARNING,
790 lsp_ext::Health::Error => lsp_types::MessageType::ERROR,
791 },
792 message.clone(),
793 open_log_button,
794 );
795 }
796 }
797 }
798
799 fn handle_task(&mut self, prime_caches_progress: &mut Vec<PrimeCachesProgress>, task: Task) {
800 match task {
801 Task::Response(response) => self.respond(response),
802 Task::Retry(req) if !self.is_completed(&req) => self.on_request(req),
804 Task::Retry(_) => (),
805 Task::Diagnostics(kind) => {
806 self.diagnostics.set_native_diagnostics(kind);
807 }
808 Task::PrimeCaches(progress) => match progress {
809 PrimeCachesProgress::Begin => prime_caches_progress.push(progress),
810 PrimeCachesProgress::Report(_) => {
811 match prime_caches_progress.last_mut() {
812 Some(last @ PrimeCachesProgress::Report(_)) => {
813 *last = progress;
815 }
816 _ => prime_caches_progress.push(progress),
817 }
818 }
819 PrimeCachesProgress::End { .. } => prime_caches_progress.push(progress),
820 },
821 Task::FetchWorkspace(progress) => {
822 let (state, msg) = match progress {
823 ProjectWorkspaceProgress::Begin => (Progress::Begin, None),
824 ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)),
825 ProjectWorkspaceProgress::End(workspaces, force_crate_graph_reload) => {
826 let resp = FetchWorkspaceResponse { workspaces, force_crate_graph_reload };
827 self.fetch_workspaces_queue.op_completed(resp);
828 if let Err(e) = self.fetch_workspace_error() {
829 error!("FetchWorkspaceError: {e}");
830 }
831 self.wants_to_switch = Some("fetched workspace".to_owned());
832 self.diagnostics.clear_check_all();
833 (Progress::End, None)
834 }
835 };
836
837 self.report_progress("Fetching", state, msg, None, None);
838 }
839 Task::DiscoverLinkedProjects(arg) => {
840 if let Some(cfg) = self.config.discover_workspace_config() {
841 let command = cfg.command.clone();
842 let discover = DiscoverCommand::new(self.discover_sender.clone(), command);
843
844 let discover_path = match &arg {
845 DiscoverProjectParam::Buildfile(it) => it,
846 DiscoverProjectParam::Path(it) => it,
847 };
848 let current_dir =
849 self.config.workspace_root_for(discover_path.as_path()).clone();
850
851 let arg = match arg {
852 DiscoverProjectParam::Buildfile(it) => DiscoverArgument::Buildfile(it),
853 DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it),
854 };
855
856 match discover.spawn(arg, current_dir.as_ref()) {
857 Ok(handle) => {
858 if self.discover_jobs_active == 0 {
859 let title = &cfg.progress_label.clone();
860 self.report_progress(title, Progress::Begin, None, None, None);
861 }
862 self.discover_jobs_active += 1;
863 self.discover_handles.push(handle)
864 }
865 Err(e) => self.show_message(
866 lsp_types::MessageType::ERROR,
867 format!("Failed to spawn project discovery command: {e:#}"),
868 false,
869 ),
870 }
871 }
872 }
873 Task::FetchBuildData(progress) => {
874 let (state, msg) = match progress {
875 BuildDataProgress::Begin => (Some(Progress::Begin), None),
876 BuildDataProgress::Report(msg) => (Some(Progress::Report), Some(msg)),
877 BuildDataProgress::End((workspaces, build_scripts)) => {
878 let resp = FetchBuildDataResponse { workspaces, build_scripts };
879 self.fetch_build_data_queue.op_completed(resp);
880
881 if let Err(e) = self.fetch_build_data_error() {
882 error!("FetchBuildDataError: {e}");
883 }
884
885 if self.wants_to_switch.is_none() {
886 self.wants_to_switch = Some("fetched build data".to_owned());
887 }
888 (Some(Progress::End), None)
889 }
890 };
891
892 if let Some(state) = state {
893 self.report_progress("Building compile-time-deps", state, msg, None, None);
894 }
895 }
896 Task::LoadProcMacros(progress) => {
897 let (state, msg) = match progress {
898 ProcMacroProgress::Begin => (Some(Progress::Begin), None),
899 ProcMacroProgress::Report(msg) => (Some(Progress::Report), Some(msg)),
900 ProcMacroProgress::End(change) => {
901 self.fetch_proc_macros_queue.op_completed(true);
902 self.analysis_host.apply_change(change);
903 self.finish_loading_crate_graph();
904 (Some(Progress::End), None)
905 }
906 };
907
908 if let Some(state) = state {
909 self.report_progress("Loading proc-macros", state, msg, None, None);
910 }
911 }
912 Task::BuildDepsHaveChanged => self.build_deps_changed = true,
913 Task::DiscoverTest(tests) => {
914 self.send_notification::<lsp_ext::DiscoveredTests>(tests);
915 }
916 }
917 }
918
919 fn handle_vfs_msg(
920 &mut self,
921 message: vfs::loader::Message,
922 last_progress_report: &mut Option<(String, f64)>,
923 ) {
924 let _p = tracing::info_span!("GlobalState::handle_vfs_msg").entered();
925 let is_changed = matches!(message, vfs::loader::Message::Changed { .. });
926 match message {
927 vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => {
928 let _p = tracing::info_span!("GlobalState::handle_vfs_msg{changed/load}").entered();
929 self.debounce_workspace_fetch();
930 let vfs = &mut self.vfs.write().0;
931 for (path, contents) in files {
932 if matches!(path.name_and_extension(), Some(("minicore", Some("rs")))) {
933 self.minicore.minicore_text = contents
935 .as_ref()
936 .and_then(|contents| str::from_utf8(contents).ok())
937 .map(triomphe::Arc::from);
938 }
939
940 let path = VfsPath::from(path);
941 if !self.mem_docs.contains(&path)
944 && (is_changed || vfs.file_id(&path).is_none())
945 {
946 vfs.set_file_contents(path, contents);
947 }
948 }
949 }
950 vfs::loader::Message::Progress { n_total, n_done, dir, config_version } => {
951 let _p = span!(Level::INFO, "GlobalState::handle_vfs_msg/progress").entered();
952 stdx::always!(config_version <= self.vfs_config_version);
953
954 let (n_done, state) = match n_done {
955 LoadingProgress::Started => {
956 self.vfs_span =
957 Some(span!(Level::INFO, "vfs_load", total = n_total).entered());
958 (0, Progress::Begin)
959 }
960 LoadingProgress::Progress(n_done) => (n_done.min(n_total), Progress::Report),
961 LoadingProgress::Finished => {
962 self.vfs_span = None;
963 (n_total, Progress::End)
964 }
965 };
966
967 self.vfs_progress_config_version = config_version;
968 self.vfs_done = state == Progress::End;
969
970 let mut message = format!("{n_done}/{n_total}");
971 if let Some(dir) = dir {
972 message += &format!(
973 ": {}",
974 match dir.strip_prefix(self.config.workspace_root_for(&dir)) {
975 Some(relative_path) => relative_path.as_utf8_path(),
976 None => dir.as_ref(),
977 }
978 );
979 }
980
981 match state {
982 Progress::Begin => self.report_progress(
983 "Roots Scanned",
984 state,
985 Some(message),
986 Some(Progress::fraction(n_done, n_total)),
987 None,
988 ),
989 Progress::Report => {
992 if last_progress_report.is_none() {
993 self.report_progress(
994 "Roots Scanned",
995 state,
996 Some(message.clone()),
997 Some(Progress::fraction(n_done, n_total)),
998 None,
999 );
1000 }
1001
1002 *last_progress_report =
1003 Some((message, Progress::fraction(n_done, n_total)));
1004 }
1005 Progress::End => {
1006 last_progress_report.take();
1007 self.report_progress(
1008 "Roots Scanned",
1009 state,
1010 Some(message),
1011 Some(Progress::fraction(n_done, n_total)),
1012 None,
1013 )
1014 }
1015 }
1016 }
1017 }
1018 }
1019
1020 fn handle_deferred_task(&mut self, task: DeferredTask) {
1021 match task {
1022 DeferredTask::CheckIfIndexed(uri) => {
1023 let snap = self.snapshot();
1024
1025 self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
1026 let _p = tracing::info_span!("GlobalState::check_if_indexed").entered();
1027 tracing::debug!(?uri, "handling uri");
1028 let Some(id) = from_proto::file_id(&snap, &uri).expect("unable to get FileId")
1029 else {
1030 return;
1031 };
1032 if let Ok(crates) = &snap.analysis.crates_for(id) {
1033 if crates.is_empty() {
1034 if snap.config.discover_workspace_config().is_some() {
1035 let path =
1036 from_proto::abs_path(&uri).expect("Unable to get AbsPath");
1037 let arg = DiscoverProjectParam::Path(path);
1038 sender.send(Task::DiscoverLinkedProjects(arg)).unwrap();
1039 }
1040 } else {
1041 tracing::debug!(?uri, "is indexed");
1042 }
1043 }
1044 });
1045 }
1046 DeferredTask::CheckProcMacroSources(modified_rust_files) => {
1047 let analysis = AssertUnwindSafe(self.snapshot().analysis);
1048 self.task_pool.handle.spawn_with_sender(stdx::thread::ThreadIntent::Worker, {
1049 move |sender| {
1050 if modified_rust_files.into_iter().any(|file_id| {
1051 match analysis.crates_for(file_id) {
1053 Ok(crates) => crates.iter().any(|&krate| {
1054 analysis.is_proc_macro_crate(krate).is_ok_and(|it| it)
1055 }),
1056 _ => false,
1057 }
1058 }) {
1059 sender.send(Task::BuildDepsHaveChanged).unwrap();
1060 }
1061 }
1062 });
1063 }
1064 }
1065 }
1066
1067 fn handle_discover_msg(&mut self, message: DiscoverProjectMessage) {
1068 let title = self
1069 .config
1070 .discover_workspace_config()
1071 .map(|cfg| cfg.progress_label.clone())
1072 .expect("No title could be found; this is a bug");
1073 match message {
1074 DiscoverProjectMessage::Finished { project, buildfile } => {
1075 self.discover_jobs_active = self.discover_jobs_active.saturating_sub(1);
1076 if self.discover_jobs_active == 0 {
1077 self.report_progress(&title, Progress::End, None, None, None);
1078 }
1079
1080 let mut config = Config::clone(&*self.config);
1081 config.add_discovered_project_from_command(project, buildfile);
1082 self.update_configuration(config);
1083 }
1084 DiscoverProjectMessage::Progress { message } => {
1085 if self.discover_jobs_active > 0 {
1086 self.report_progress(&title, Progress::Report, Some(message), None, None)
1087 }
1088 }
1089 DiscoverProjectMessage::Error { error, source } => {
1090 let message = format!("Project discovery failed: {error}");
1091 self.show_and_log_error(message.clone(), source);
1092
1093 self.discover_jobs_active = self.discover_jobs_active.saturating_sub(1);
1094 if self.discover_jobs_active == 0 {
1095 self.report_progress(&title, Progress::End, Some(message), None, None)
1096 }
1097 }
1098 }
1099 }
1100
1101 fn cleanup_discover_handles(&mut self) {
1104 let mut active_handles = vec![];
1105
1106 for mut discover_handle in self.discover_handles.drain(..) {
1107 if !discover_handle.handle.has_exited() {
1108 active_handles.push(discover_handle);
1109 }
1110 }
1111 self.discover_handles = active_handles;
1112 }
1113
1114 fn handle_cargo_test_msg(&mut self, message: CargoTestMessage) {
1115 match message.output {
1116 CargoTestOutput::Test { name, state } => {
1117 let state = match state {
1118 TestState::Started => lsp_ext::TestState::Started,
1119 TestState::Ignored => lsp_ext::TestState::Skipped,
1120 TestState::Ok => lsp_ext::TestState::Passed,
1121 TestState::Failed { stdout } => lsp_ext::TestState::Failed { message: stdout },
1122 };
1123
1124 let test_id = format!("{}::{name}", message.target.target.replace('-', "_"));
1126
1127 self.send_notification::<lsp_ext::ChangeTestState>(
1128 lsp_ext::ChangeTestStateParams { test_id, state },
1129 );
1130 }
1131 CargoTestOutput::Suite => (),
1132 CargoTestOutput::Finished => {
1133 self.test_run_remaining_jobs = self.test_run_remaining_jobs.saturating_sub(1);
1134 if self.test_run_remaining_jobs == 0 {
1135 self.send_notification::<lsp_ext::EndRunTest>(());
1136 self.test_run_session = None;
1137 }
1138 }
1139 CargoTestOutput::Custom { text } => {
1140 self.send_notification::<lsp_ext::AppendOutputToRunTest>(text);
1141 }
1142 }
1143 }
1144
1145 fn handle_flycheck_msg(&mut self, message: FlycheckMessage, cargo_finished: &mut bool) {
1146 match message {
1147 FlycheckMessage::AddDiagnostic {
1148 id,
1149 generation,
1150 workspace_root,
1151 diagnostic,
1152 package_id,
1153 } => {
1154 let snap = self.snapshot();
1155 let diagnostics = crate::diagnostics::flycheck_to_proto::map_rust_diagnostic_to_lsp(
1156 &self.config.diagnostics_map(None),
1157 diagnostic,
1158 &workspace_root,
1159 &snap,
1160 );
1161 for diag in diagnostics {
1162 match url_to_file_id(&self.vfs.read().0, &diag.url) {
1163 Ok(Some(file_id)) => self.diagnostics.add_check_diagnostic(
1164 id,
1165 generation,
1166 &package_id,
1167 file_id,
1168 diag.diagnostic,
1169 diag.fix,
1170 ),
1171 Ok(None) => {}
1172 Err(err) => {
1173 error!(
1174 "flycheck {id}: File with cargo diagnostic not found in VFS: {}",
1175 err
1176 );
1177 }
1178 };
1179 }
1180 }
1181 FlycheckMessage::ClearDiagnostics {
1182 id,
1183 kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
1184 } => self.diagnostics.clear_check(id),
1185 FlycheckMessage::ClearDiagnostics {
1186 id,
1187 kind: ClearDiagnosticsKind::All(ClearScope::Package(package_id)),
1188 } => self.diagnostics.clear_check_for_package(id, package_id),
1189 FlycheckMessage::ClearDiagnostics {
1190 id,
1191 kind: ClearDiagnosticsKind::OlderThan(generation, ClearScope::Workspace),
1192 } => self.diagnostics.clear_check_older_than(id, generation),
1193 FlycheckMessage::ClearDiagnostics {
1194 id,
1195 kind: ClearDiagnosticsKind::OlderThan(generation, ClearScope::Package(package_id)),
1196 } => self.diagnostics.clear_check_older_than_for_package(id, package_id, generation),
1197 FlycheckMessage::Progress { id, progress } => {
1198 let format_with_id = |user_facing_command: String| {
1199 if self.flycheck.len() == 1 {
1202 user_facing_command
1203 } else {
1204 format!("{user_facing_command} (#{})", id + 1)
1205 }
1206 };
1207
1208 self.flycheck_formatted_commands
1209 .resize_with(self.flycheck.len().max(id + 1), || {
1210 format_with_id(self.config.flycheck(None).to_string())
1211 });
1212
1213 let (state, message) = match progress {
1214 flycheck::Progress::DidStart { user_facing_command } => {
1215 self.flycheck_formatted_commands[id] = format_with_id(user_facing_command);
1216 (Progress::Begin, None)
1217 }
1218 flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)),
1219 flycheck::Progress::DidCancel => {
1220 self.last_flycheck_error = None;
1221 *cargo_finished = true;
1222 (Progress::End, None)
1223 }
1224 flycheck::Progress::DidFailToRestart(err) => {
1225 self.last_flycheck_error =
1226 Some(format!("cargo check failed to start: {err}"));
1227 return;
1228 }
1229 flycheck::Progress::DidFinish(result) => {
1230 self.last_flycheck_error =
1231 result.err().map(|err| format!("cargo check failed to start: {err}"));
1232 *cargo_finished = true;
1233 (Progress::End, None)
1234 }
1235 };
1236
1237 let title = self.flycheck_formatted_commands[id].clone();
1239 self.report_progress(
1240 &title,
1241 state,
1242 message,
1243 None,
1244 Some(format!("rust-analyzer/flycheck/{id}")),
1245 );
1246 }
1247 }
1248 }
1249
1250 fn on_new_request(&mut self, request_received: Instant, req: Request) {
1252 let _p =
1253 span!(Level::INFO, "GlobalState::on_new_request", req.method = ?req.method).entered();
1254 self.register_request(&req, request_received);
1255 self.on_request(req);
1256 }
1257
1258 fn on_request(&mut self, req: Request) {
1260 let mut dispatcher = RequestDispatcher { req: Some(req), global_state: self };
1261 dispatcher.on_sync_mut::<lsp_types::request::Shutdown>(|s, ()| {
1262 s.shutdown_requested = true;
1263 Ok(())
1264 });
1265
1266 match &mut dispatcher {
1267 RequestDispatcher { req: Some(req), global_state: this } if this.shutdown_requested => {
1268 this.respond(lsp_server::Response::new_err(
1269 req.id.clone(),
1270 lsp_server::ErrorCode::InvalidRequest as i32,
1271 "Shutdown already requested.".to_owned(),
1272 ));
1273 return;
1274 }
1275 _ => (),
1276 }
1277
1278 use crate::handlers::request as handlers;
1279 use lsp_types::request as lsp_request;
1280
1281 const RETRY: bool = true;
1282 const NO_RETRY: bool = false;
1283
1284 #[rustfmt::skip]
1285 dispatcher
1286 .on_sync_mut::<lsp_ext::ReloadWorkspace>(handlers::handle_workspace_reload)
1289 .on_sync_mut::<lsp_ext::RebuildProcMacros>(handlers::handle_proc_macros_rebuild)
1290 .on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)
1291 .on_sync_mut::<lsp_ext::RunTest>(handlers::handle_run_test)
1292 .on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)
1295 .on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)
1296 .on_sync::<lsp_request::SelectionRangeRequest>(handlers::handle_selection_range)
1297 .on_sync::<lsp_ext::MatchingBrace>(handlers::handle_matching_brace)
1298 .on_sync::<lsp_ext::OnTypeFormatting>(handlers::handle_on_type_formatting)
1299 .on_fmt_thread::<lsp_request::Formatting>(handlers::handle_formatting)
1304 .on_fmt_thread::<lsp_request::RangeFormatting>(handlers::handle_range_formatting)
1305 .on_latency_sensitive::<RETRY, lsp_request::Completion>(handlers::handle_completion)
1311 .on_latency_sensitive::<RETRY, lsp_request::ResolveCompletionItem>(handlers::handle_completion_resolve)
1313 .on_latency_sensitive::<RETRY, lsp_request::SemanticTokensFullRequest>(handlers::handle_semantic_tokens_full)
1314 .on_latency_sensitive::<RETRY, lsp_request::SemanticTokensFullDeltaRequest>(handlers::handle_semantic_tokens_full_delta)
1315 .on_latency_sensitive::<NO_RETRY, lsp_request::SemanticTokensRangeRequest>(handlers::handle_semantic_tokens_range)
1316 .on_with_vfs_default::<lsp_request::DocumentDiagnosticRequest>(handlers::handle_document_diagnostics, empty_diagnostic_report, || lsp_server::ResponseError {
1319 code: lsp_server::ErrorCode::ServerCancelled as i32,
1320 message: "server cancelled the request".to_owned(),
1321 data: serde_json::to_value(lsp_types::DiagnosticServerCancellationData {
1322 retrigger_request: true
1323 }).ok(),
1324 })
1325 .on::<RETRY, lsp_request::DocumentSymbolRequest>(handlers::handle_document_symbol)
1326 .on::<RETRY, lsp_request::FoldingRangeRequest>(handlers::handle_folding_range)
1327 .on::<NO_RETRY, lsp_request::SignatureHelpRequest>(handlers::handle_signature_help)
1328 .on::<RETRY, lsp_request::WillRenameFiles>(handlers::handle_will_rename_files)
1329 .on::<NO_RETRY, lsp_request::GotoDefinition>(handlers::handle_goto_definition)
1330 .on::<NO_RETRY, lsp_request::GotoDeclaration>(handlers::handle_goto_declaration)
1331 .on::<NO_RETRY, lsp_request::GotoImplementation>(handlers::handle_goto_implementation)
1332 .on::<NO_RETRY, lsp_request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
1333 .on::<NO_RETRY, lsp_request::InlayHintRequest>(handlers::handle_inlay_hints)
1334 .on_identity::<NO_RETRY, lsp_request::InlayHintResolveRequest, _>(handlers::handle_inlay_hints_resolve)
1335 .on::<NO_RETRY, lsp_request::CodeLensRequest>(handlers::handle_code_lens)
1336 .on_identity::<NO_RETRY, lsp_request::CodeLensResolve, _>(handlers::handle_code_lens_resolve)
1337 .on::<NO_RETRY, lsp_request::PrepareRenameRequest>(handlers::handle_prepare_rename)
1338 .on::<NO_RETRY, lsp_request::Rename>(handlers::handle_rename)
1339 .on::<NO_RETRY, lsp_request::References>(handlers::handle_references)
1340 .on::<NO_RETRY, lsp_request::DocumentHighlightRequest>(handlers::handle_document_highlight)
1341 .on::<NO_RETRY, lsp_request::CallHierarchyPrepare>(handlers::handle_call_hierarchy_prepare)
1342 .on::<NO_RETRY, lsp_request::CallHierarchyIncomingCalls>(handlers::handle_call_hierarchy_incoming)
1343 .on::<NO_RETRY, lsp_request::CallHierarchyOutgoingCalls>(handlers::handle_call_hierarchy_outgoing)
1344 .on::<RETRY, lsp_ext::FetchDependencyList>(handlers::fetch_dependency_list)
1346 .on::<RETRY, lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
1347 .on::<RETRY, lsp_ext::ViewFileText>(handlers::handle_view_file_text)
1348 .on::<RETRY, lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph)
1349 .on::<RETRY, lsp_ext::ViewItemTree>(handlers::handle_view_item_tree)
1350 .on::<RETRY, lsp_ext::DiscoverTest>(handlers::handle_discover_test)
1351 .on::<RETRY, lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
1352 .on::<NO_RETRY, lsp_ext::Ssr>(handlers::handle_ssr)
1353 .on::<NO_RETRY, lsp_ext::ViewRecursiveMemoryLayout>(handlers::handle_view_recursive_memory_layout)
1354 .on::<NO_RETRY, lsp_ext::ViewSyntaxTree>(handlers::handle_view_syntax_tree)
1355 .on::<NO_RETRY, lsp_ext::ViewHir>(handlers::handle_view_hir)
1356 .on::<NO_RETRY, lsp_ext::ViewMir>(handlers::handle_view_mir)
1357 .on::<NO_RETRY, lsp_ext::InterpretFunction>(handlers::handle_interpret_function)
1358 .on::<NO_RETRY, lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
1359 .on::<NO_RETRY, lsp_ext::ParentModule>(handlers::handle_parent_module)
1360 .on::<NO_RETRY, lsp_ext::ChildModules>(handlers::handle_child_modules)
1361 .on::<NO_RETRY, lsp_ext::Runnables>(handlers::handle_runnables)
1362 .on::<NO_RETRY, lsp_ext::RelatedTests>(handlers::handle_related_tests)
1363 .on::<NO_RETRY, lsp_ext::CodeActionRequest>(handlers::handle_code_action)
1364 .on_identity::<RETRY, lsp_ext::CodeActionResolveRequest, _>(handlers::handle_code_action_resolve)
1365 .on::<NO_RETRY, lsp_ext::HoverRequest>(handlers::handle_hover)
1366 .on::<NO_RETRY, lsp_ext::ExternalDocs>(handlers::handle_open_docs)
1367 .on::<NO_RETRY, lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
1368 .on::<NO_RETRY, lsp_ext::MoveItem>(handlers::handle_move_item)
1369 .on::<NO_RETRY, lsp_ext::InternalTestingFetchConfig>(handlers::internal_testing_fetch_config)
1371 .on::<RETRY, lsp_ext::GetFailedObligations>(handlers::get_failed_obligations)
1372 .finish();
1373 }
1374
1375 fn on_notification(&mut self, not: Notification) {
1377 let _p =
1378 span!(Level::INFO, "GlobalState::on_notification", not.method = ?not.method).entered();
1379 use crate::handlers::notification as handlers;
1380 use lsp_types::notification as notifs;
1381
1382 NotificationDispatcher { not: Some(not), global_state: self }
1383 .on_sync_mut::<notifs::Cancel>(handlers::handle_cancel)
1384 .on_sync_mut::<notifs::WorkDoneProgressCancel>(
1385 handlers::handle_work_done_progress_cancel,
1386 )
1387 .on_sync_mut::<notifs::DidOpenTextDocument>(handlers::handle_did_open_text_document)
1388 .on_sync_mut::<notifs::DidChangeTextDocument>(handlers::handle_did_change_text_document)
1389 .on_sync_mut::<notifs::DidCloseTextDocument>(handlers::handle_did_close_text_document)
1390 .on_sync_mut::<notifs::DidSaveTextDocument>(handlers::handle_did_save_text_document)
1391 .on_sync_mut::<notifs::DidChangeConfiguration>(
1392 handlers::handle_did_change_configuration,
1393 )
1394 .on_sync_mut::<notifs::DidChangeWorkspaceFolders>(
1395 handlers::handle_did_change_workspace_folders,
1396 )
1397 .on_sync_mut::<notifs::DidChangeWatchedFiles>(handlers::handle_did_change_watched_files)
1398 .on_sync_mut::<lsp_ext::CancelFlycheck>(handlers::handle_cancel_flycheck)
1399 .on_sync_mut::<lsp_ext::ClearFlycheck>(handlers::handle_clear_flycheck)
1400 .on_sync_mut::<lsp_ext::RunFlycheck>(handlers::handle_run_flycheck)
1401 .on_sync_mut::<lsp_ext::AbortRunTest>(handlers::handle_abort_run_test)
1402 .finish();
1403 }
1404}