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,6 +57,7 @@ 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
}
@@ -67,13 +69,20 @@ impl fmt::Display for Event {
67
69
Event :: Task ( _) => write ! ( f, "Event::Task" ) ,
68
70
Event :: Vfs ( _) => write ! ( f, "Event::Vfs" ) ,
69
71
Event :: Flycheck ( _) => write ! ( f, "Event::Flycheck" ) ,
72
+ Event :: QueuedTask ( _) => write ! ( f, "Event::QueuedTask" ) ,
70
73
}
71
74
}
72
75
}
73
76
77
+ #[ derive( Debug ) ]
78
+ pub ( crate ) enum QueuedTask {
79
+ CheckIfIndexed ( lsp_types:: Url ) ,
80
+ }
81
+
74
82
#[ derive( Debug ) ]
75
83
pub ( crate ) enum Task {
76
84
Response ( lsp_server:: Response ) ,
85
+ ClientNotification ( ext:: UnindexedProjectParams ) ,
77
86
Retry ( lsp_server:: Request ) ,
78
87
Diagnostics ( Vec < ( FileId , Vec < lsp_types:: Diagnostic > ) > ) ,
79
88
PrimeCaches ( PrimeCachesProgress ) ,
@@ -115,6 +124,7 @@ impl fmt::Debug for Event {
115
124
match self {
116
125
Event :: Lsp ( it) => fmt:: Debug :: fmt ( it, f) ,
117
126
Event :: Task ( it) => fmt:: Debug :: fmt ( it, f) ,
127
+ Event :: QueuedTask ( it) => fmt:: Debug :: fmt ( it, f) ,
118
128
Event :: Vfs ( it) => fmt:: Debug :: fmt ( it, f) ,
119
129
Event :: Flycheck ( it) => fmt:: Debug :: fmt ( it, f) ,
120
130
}
@@ -193,6 +203,9 @@ impl GlobalState {
193
203
recv( self . task_pool. receiver) -> task =>
194
204
Some ( Event :: Task ( task. unwrap( ) ) ) ,
195
205
206
+ recv( self . deferred_task_queue. receiver) -> task =>
207
+ Some ( Event :: QueuedTask ( task. unwrap( ) ) ) ,
208
+
196
209
recv( self . fmt_pool. receiver) -> task =>
197
210
Some ( Event :: Task ( task. unwrap( ) ) ) ,
198
211
@@ -211,7 +224,7 @@ impl GlobalState {
211
224
. entered ( ) ;
212
225
213
226
let event_dbg_msg = format ! ( "{event:?}" ) ;
214
- tracing:: debug!( "{:?} handle_event({})" , loop_start , event_dbg_msg ) ;
227
+ tracing:: debug!( ?loop_start , ?event , "handle_event" ) ;
215
228
if tracing:: enabled!( tracing:: Level :: INFO ) {
216
229
let task_queue_len = self . task_pool . handle . len ( ) ;
217
230
if task_queue_len > 0 {
@@ -226,6 +239,16 @@ impl GlobalState {
226
239
lsp_server:: Message :: Notification ( not) => self . on_notification ( not) ?,
227
240
lsp_server:: Message :: Response ( resp) => self . complete_request ( resp) ,
228
241
} ,
242
+ Event :: QueuedTask ( task) => {
243
+ let _p =
244
+ tracing:: span!( tracing:: Level :: INFO , "GlobalState::handle_event/queued_task" )
245
+ . entered ( ) ;
246
+ self . handle_queued_task ( task) ;
247
+ // Coalesce multiple task events into one loop turn
248
+ while let Ok ( task) = self . deferred_task_queue . receiver . try_recv ( ) {
249
+ self . handle_queued_task ( task) ;
250
+ }
251
+ }
229
252
Event :: Task ( task) => {
230
253
let _p = tracing:: span!( tracing:: Level :: INFO , "GlobalState::handle_event/task" )
231
254
. entered ( ) ;
@@ -498,6 +521,9 @@ impl GlobalState {
498
521
fn handle_task ( & mut self , prime_caches_progress : & mut Vec < PrimeCachesProgress > , task : Task ) {
499
522
match task {
500
523
Task :: Response ( response) => self . respond ( response) ,
524
+ Task :: ClientNotification ( params) => {
525
+ self . send_notification :: < lsp_ext:: UnindexedProject > ( params)
526
+ }
501
527
// Only retry requests that haven't been cancelled. Otherwise we do unnecessary work.
502
528
Task :: Retry ( req) if !self . is_completed ( & req) => self . on_request ( req) ,
503
529
Task :: Retry ( _) => ( ) ,
@@ -638,6 +664,31 @@ impl GlobalState {
638
664
}
639
665
}
640
666
667
+ fn handle_queued_task ( & mut self , task : QueuedTask ) {
668
+ match task {
669
+ QueuedTask :: CheckIfIndexed ( uri) => {
670
+ let snap = self . snapshot ( ) ;
671
+
672
+ self . task_pool . handle . spawn_with_sender ( ThreadIntent :: Worker , move |sender| {
673
+ let _p = tracing:: span!( tracing:: Level :: INFO , "GlobalState::check_if_indexed" )
674
+ . entered ( ) ;
675
+ tracing:: debug!( ?uri, "handling uri" ) ;
676
+ let id = from_proto:: file_id ( & snap, & uri) . expect ( "unable to get FileId" ) ;
677
+ if let Ok ( crates) = & snap. analysis . crates_for ( id) {
678
+ if crates. is_empty ( ) {
679
+ let params = ext:: UnindexedProjectParams {
680
+ text_documents : vec ! [ lsp_types:: TextDocumentIdentifier { uri } ] ,
681
+ } ;
682
+ sender. send ( Task :: ClientNotification ( params) ) . unwrap ( ) ;
683
+ } else {
684
+ tracing:: debug!( ?uri, "is indexed" ) ;
685
+ }
686
+ }
687
+ } ) ;
688
+ }
689
+ }
690
+ }
691
+
641
692
fn handle_flycheck_msg ( & mut self , message : flycheck:: Message ) {
642
693
match message {
643
694
flycheck:: Message :: AddDiagnostic { id, workspace_root, diagnostic } => {
0 commit comments