1
1
//! The main loop of `rust-analyzer` responsible for dispatching LSP
2
2
//! requests/replies and notifications back to the client.
3
+ use crate :: lsp:: ext;
3
4
use std:: {
4
5
fmt,
5
6
time:: { Duration , Instant } ,
@@ -56,10 +57,16 @@ pub fn main_loop(config: Config, connection: Connection) -> anyhow::Result<()> {
56
57
enum Event {
57
58
Lsp ( lsp_server:: Message ) ,
58
59
Task ( Task ) ,
60
+ QueuedTask ( QueuedTask ) ,
59
61
Vfs ( vfs:: loader:: Message ) ,
60
62
Flycheck ( flycheck:: Message ) ,
61
63
}
62
64
65
+ #[ derive( Debug ) ]
66
+ pub ( crate ) enum QueuedTask {
67
+ CheckIfIndexed ( lsp_types:: Url ) ,
68
+ }
69
+
63
70
#[ derive( Debug ) ]
64
71
pub ( crate ) enum Task {
65
72
Response ( lsp_server:: Response ) ,
@@ -104,6 +111,7 @@ impl fmt::Debug for Event {
104
111
match self {
105
112
Event :: Lsp ( it) => fmt:: Debug :: fmt ( it, f) ,
106
113
Event :: Task ( it) => fmt:: Debug :: fmt ( it, f) ,
114
+ Event :: QueuedTask ( it) => fmt:: Debug :: fmt ( it, f) ,
107
115
Event :: Vfs ( it) => fmt:: Debug :: fmt ( it, f) ,
108
116
Event :: Flycheck ( it) => fmt:: Debug :: fmt ( it, f) ,
109
117
}
@@ -182,6 +190,9 @@ impl GlobalState {
182
190
recv( self . task_pool. receiver) -> task =>
183
191
Some ( Event :: Task ( task. unwrap( ) ) ) ,
184
192
193
+ recv( self . deferred_task_queue. receiver) -> task =>
194
+ Some ( Event :: QueuedTask ( task. unwrap( ) ) ) ,
195
+
185
196
recv( self . fmt_pool. receiver) -> task =>
186
197
Some ( Event :: Task ( task. unwrap( ) ) ) ,
187
198
@@ -199,7 +210,7 @@ impl GlobalState {
199
210
let _p = profile:: span ( "GlobalState::handle_event" ) ;
200
211
201
212
let event_dbg_msg = format ! ( "{event:?}" ) ;
202
- tracing:: debug!( "{:?} handle_event({})" , loop_start , event_dbg_msg ) ;
213
+ tracing:: debug!( ?loop_start , ?event , "handle_event" ) ;
203
214
if tracing:: enabled!( tracing:: Level :: INFO ) {
204
215
let task_queue_len = self . task_pool . handle . len ( ) ;
205
216
if task_queue_len > 0 {
@@ -214,6 +225,14 @@ impl GlobalState {
214
225
lsp_server:: Message :: Notification ( not) => self . on_notification ( not) ?,
215
226
lsp_server:: Message :: Response ( resp) => self . complete_request ( resp) ,
216
227
} ,
228
+ Event :: QueuedTask ( task) => {
229
+ let _p = profile:: span ( "GlobalState::handle_event/queued_task" ) ;
230
+ self . handle_queued_task ( task) ;
231
+ // Coalesce multiple task events into one loop turn
232
+ while let Ok ( task) = self . deferred_task_queue . receiver . try_recv ( ) {
233
+ self . handle_queued_task ( task) ;
234
+ }
235
+ }
217
236
Event :: Task ( task) => {
218
237
let _p = profile:: span ( "GlobalState::handle_event/task" ) ;
219
238
let mut prime_caches_progress = Vec :: new ( ) ;
@@ -607,6 +626,35 @@ impl GlobalState {
607
626
}
608
627
}
609
628
629
+ fn handle_queued_task ( & mut self , task : QueuedTask ) {
630
+ match task {
631
+ QueuedTask :: CheckIfIndexed ( uri) => {
632
+ let snap = self . snapshot ( ) ;
633
+ let sender = self . sender . clone ( ) ;
634
+
635
+ self . task_pool . handle . spawn_with_sender ( ThreadIntent :: Worker , move |_| {
636
+ let _p = profile:: span ( "GlobalState::check_if_indexed" ) ;
637
+ tracing:: debug!( ?uri, "handling uri" ) ;
638
+ let id = from_proto:: file_id ( & snap, & uri) . expect ( "unable to get FileId" ) ;
639
+ if let Ok ( crates) = & snap. analysis . crates_for ( id) {
640
+ if crates. is_empty ( ) {
641
+ let not = lsp_server:: Notification :: new (
642
+ ext:: UnindexedProject :: METHOD . to_string ( ) ,
643
+ ext:: UnindexedProjectParams {
644
+ text_documents : vec ! [ lsp_types:: TextDocumentIdentifier { uri } ] ,
645
+ } ,
646
+ ) ;
647
+ sender. send ( not. into ( ) ) . expect ( "unable to send notification" ) ;
648
+ tracing:: debug!( "sent notification" ) ;
649
+ } else {
650
+ tracing:: debug!( ?uri, "is indexed" ) ;
651
+ }
652
+ }
653
+ } ) ;
654
+ }
655
+ }
656
+ }
657
+
610
658
fn handle_flycheck_msg ( & mut self , message : flycheck:: Message ) {
611
659
match message {
612
660
flycheck:: Message :: AddDiagnostic { id, workspace_root, diagnostic } => {
0 commit comments