rust_analyzer/
main_loop.rs

1//! The main loop of `rust-analyzer` responsible for dispatching LSP
2//! requests/replies and notifications back to the client.
3
4use 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    // Windows scheduler implements priority boosts: if thread waits for an
45    // event (like a condvar), and event fires, priority of the thread is
46    // temporary bumped. This optimization backfires in our case: each time the
47    // `main_loop` schedules a task to run on a threadpool, the worker threads
48    // gets a higher priority, and (on a machine with fewer cores) displaces the
49    // main loop! We work around this by marking the main loop as a
50    // higher-priority thread.
51    //
52    // https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities
53    // https://docs.microsoft.com/en-us/windows/win32/procthread/priority-boosts
54    // https://github.com/rust-lang/rust-analyzer/issues/2835
55    #[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    // FIXME: Remove this in favor of a more general QueuedTask, see `handle_did_save_text_document`
124    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", &not.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        // Make sure we reply to formatting requests ASAP so the editor doesn't block
270        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                // Coalesce multiple deferred task events into one loop turn
330                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                // Coalesce multiple task events into one loop turn
340                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                            // Don't send too many notifications while batching, sending progress reports
378                            // serializes notifications on the mainthread at the moment which slows us down
379                            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                // Coalesce many VFS event into a single loop turn
426                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                // Coalesce many flycheck updates into a single loop turn
443                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                // Coalesce many test result event into a single loop turn
457                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                // Coalesce many project discovery events into a single loop turn.
464                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                    // Project has loaded properly, kick off initial flycheck
490                    self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None));
491                }
492                // delay initial cache priming until proc macros are loaded, or we will load up a bunch of garbage into salsa
493                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                // Refresh semantic tokens if the client supports it.
504                if self.config.semantic_tokens_refresh() {
505                    self.semantic_tokens_cache.lock().clear();
506                    self.send_request::<lsp_types::request::SemanticTokensRefresh>((), |_, _| ());
507                }
508
509                // Refresh code lens if the client supports it.
510                if self.config.code_lens_refresh() {
511                    self.send_request::<lsp_types::request::CodeLensRefresh>((), |_, _| ());
512                }
513
514                // Refresh inlay hints if the client supports it.
515                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                    // Only publish diagnostics for files in the workspace, not from crates.io deps
624                    // or the sysroot.
625                    // While theoretically these should never have errors, we have quite a few false
626                    // positives particularly in the stdlib, and those diagnostics would stay around
627                    // forever if we emitted them here.
628                    !source_root.is_library
629                })
630                .collect::<std::sync::Arc<_>>()
631        };
632        tracing::trace!("updating notifications for {:?}", subscriptions);
633        // Split up the work on multiple threads, but we don't wanna fill the entire task pool with
634        // diagnostic tasks, so we limit the number of tasks to a quarter of the total thread pool.
635        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            // Diagnostics are triggered by the user typing
648            // so we run them on a latency sensitive thread.
649            let snapshot = self.snapshot();
650            self.task_pool.handle.spawn_with_sender(ThreadIntent::LatencySensitive, {
651                let subscriptions = subscriptions.clone();
652                // Do not fetch semantic diagnostics (and populate query results) if we haven't even
653                // loaded the initial workspace yet.
654                let fetch_semantic =
655                    self.vfs_done && self.fetch_workspaces_queue.last_op_result().is_some();
656                move |sender| {
657                    // We aren't observing the semantics token cache here
658                    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        // Updating tests are triggered by the user typing
717        // so we run them on a latency sensitive thread.
718        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            // Only retry requests that haven't been cancelled. Otherwise we do unnecessary work.
780            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                            // Coalesce subsequent update events.
791                            *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                    // the clone is unfortunately necessary to avoid a borrowck error when
819                    // `self.report_progress` is called later
820                    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                        // Not a lot of bad can happen from mistakenly identifying `minicore`, so proceed with that.
908                        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 the file is in mem docs, it's managed by the client via notifications
915                    // so only set it if its not in there
916                    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                    // Don't send too many notifications while batching, sending progress reports
963                    // serializes notifications on the mainthread at the moment which slows us down
964                    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                            // FIXME: Check whether these files could be build script related
1025                            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    /// Drop any discover command processes that have exited, due to
1075    /// finishing or erroring.
1076    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                // The notification requires the namespace form (with underscores) of the target
1098                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                // When we're running multiple flychecks, we have to include a disambiguator in
1193                // the title, or the editor complains. Note that this is a user-facing string.
1194                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    /// Registers and handles a request. This should only be called once per incoming request.
1211    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    /// Handles a request.
1219    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            // Request handlers that must run on the main thread
1247            // because they mutate GlobalState:
1248            .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            // Request handlers which are related to the user typing
1253            // are run on the main thread to reduce latency:
1254            .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            // Formatting should be done immediately as the editor might wait on it, but we can't
1260            // put it on the main thread as we do not want the main thread to block on rustfmt.
1261            // So we have an extra thread just for formatting requests to make sure it gets handled
1262            // as fast as possible.
1263            .on_fmt_thread::<lsp_request::Formatting>(handlers::handle_formatting)
1264            .on_fmt_thread::<lsp_request::RangeFormatting>(handlers::handle_range_formatting)
1265            // We can’t run latency-sensitive request handlers which do semantic
1266            // analysis on the main thread because that would block other
1267            // requests. Instead, we run these request handlers on higher priority
1268            // threads in the threadpool.
1269            // FIXME: Retrying can make the result of this stale?
1270            .on_latency_sensitive::<RETRY, lsp_request::Completion>(handlers::handle_completion)
1271            // FIXME: Retrying can make the result of this stale
1272            .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            // FIXME: Some of these NO_RETRY could be retries if the file they are interested didn't change.
1277            // All other request handlers
1278            .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            // All other request handlers (lsp extension)
1305            .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            //
1330            .on::<NO_RETRY, lsp_ext::InternalTestingFetchConfig>(handlers::internal_testing_fetch_config)
1331            .finish();
1332    }
1333
1334    /// Handles an incoming notification.
1335    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}