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,13 +57,20 @@ 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 ) ,
73
+ ClientNotification ( ext:: UnindexedProjectParams ) ,
66
74
Retry ( lsp_server:: Request ) ,
67
75
Diagnostics ( Vec < ( FileId , Vec < lsp_types:: Diagnostic > ) > ) ,
68
76
PrimeCaches ( PrimeCachesProgress ) ,
@@ -104,6 +112,7 @@ impl fmt::Debug for Event {
104
112
match self {
105
113
Event :: Lsp ( it) => fmt:: Debug :: fmt ( it, f) ,
106
114
Event :: Task ( it) => fmt:: Debug :: fmt ( it, f) ,
115
+ Event :: QueuedTask ( it) => fmt:: Debug :: fmt ( it, f) ,
107
116
Event :: Vfs ( it) => fmt:: Debug :: fmt ( it, f) ,
108
117
Event :: Flycheck ( it) => fmt:: Debug :: fmt ( it, f) ,
109
118
}
@@ -182,6 +191,9 @@ impl GlobalState {
182
191
recv( self . task_pool. receiver) -> task =>
183
192
Some ( Event :: Task ( task. unwrap( ) ) ) ,
184
193
194
+ recv( self . deferred_task_queue. receiver) -> task =>
195
+ Some ( Event :: QueuedTask ( task. unwrap( ) ) ) ,
196
+
185
197
recv( self . fmt_pool. receiver) -> task =>
186
198
Some ( Event :: Task ( task. unwrap( ) ) ) ,
187
199
@@ -199,7 +211,7 @@ impl GlobalState {
199
211
let _p = profile:: span ( "GlobalState::handle_event" ) ;
200
212
201
213
let event_dbg_msg = format ! ( "{event:?}" ) ;
202
- tracing:: debug!( "{:?} handle_event({})" , loop_start , event_dbg_msg ) ;
214
+ tracing:: debug!( ?loop_start , ?event , "handle_event" ) ;
203
215
if tracing:: enabled!( tracing:: Level :: INFO ) {
204
216
let task_queue_len = self . task_pool . handle . len ( ) ;
205
217
if task_queue_len > 0 {
@@ -214,6 +226,14 @@ impl GlobalState {
214
226
lsp_server:: Message :: Notification ( not) => self . on_notification ( not) ?,
215
227
lsp_server:: Message :: Response ( resp) => self . complete_request ( resp) ,
216
228
} ,
229
+ Event :: QueuedTask ( task) => {
230
+ let _p = profile:: span ( "GlobalState::handle_event/queued_task" ) ;
231
+ self . handle_queued_task ( task) ;
232
+ // Coalesce multiple task events into one loop turn
233
+ while let Ok ( task) = self . deferred_task_queue . receiver . try_recv ( ) {
234
+ self . handle_queued_task ( task) ;
235
+ }
236
+ }
217
237
Event :: Task ( task) => {
218
238
let _p = profile:: span ( "GlobalState::handle_event/task" ) ;
219
239
let mut prime_caches_progress = Vec :: new ( ) ;
@@ -483,6 +503,9 @@ impl GlobalState {
483
503
fn handle_task ( & mut self , prime_caches_progress : & mut Vec < PrimeCachesProgress > , task : Task ) {
484
504
match task {
485
505
Task :: Response ( response) => self . respond ( response) ,
506
+ Task :: ClientNotification ( params) => {
507
+ self . send_notification :: < lsp_ext:: UnindexedProject > ( params)
508
+ }
486
509
// Only retry requests that haven't been cancelled. Otherwise we do unnecessary work.
487
510
Task :: Retry ( req) if !self . is_completed ( & req) => self . on_request ( req) ,
488
511
Task :: Retry ( _) => ( ) ,
@@ -625,6 +648,30 @@ impl GlobalState {
625
648
}
626
649
}
627
650
651
+ fn handle_queued_task ( & mut self , task : QueuedTask ) {
652
+ match task {
653
+ QueuedTask :: CheckIfIndexed ( uri) => {
654
+ let snap = self . snapshot ( ) ;
655
+
656
+ self . task_pool . handle . spawn_with_sender ( ThreadIntent :: Worker , move |sender| {
657
+ let _p = profile:: span ( "GlobalState::check_if_indexed" ) ;
658
+ tracing:: debug!( ?uri, "handling uri" ) ;
659
+ let id = from_proto:: file_id ( & snap, & uri) . expect ( "unable to get FileId" ) ;
660
+ if let Ok ( crates) = & snap. analysis . crates_for ( id) {
661
+ if crates. is_empty ( ) {
662
+ let params = ext:: UnindexedProjectParams {
663
+ text_documents : vec ! [ lsp_types:: TextDocumentIdentifier { uri } ] ,
664
+ } ;
665
+ sender. send ( Task :: ClientNotification ( params) ) . unwrap ( ) ;
666
+ } else {
667
+ tracing:: debug!( ?uri, "is indexed" ) ;
668
+ }
669
+ }
670
+ } ) ;
671
+ }
672
+ }
673
+ }
674
+
628
675
fn handle_flycheck_msg ( & mut self , message : flycheck:: Message ) {
629
676
match message {
630
677
flycheck:: Message :: AddDiagnostic { id, workspace_root, diagnostic } => {
0 commit comments