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