11//! The main loop of `rust-analyzer` responsible for dispatching LSP
22//! requests/replies and notifications back to the client.
3+ use crate :: lsp:: ext;
34use std:: {
45 fmt,
56 time:: { Duration , Instant } ,
@@ -56,6 +57,7 @@ pub fn main_loop(config: Config, connection: Connection) -> anyhow::Result<()> {
5657enum Event {
5758 Lsp ( lsp_server:: Message ) ,
5859 Task ( Task ) ,
60+ QueuedTask ( QueuedTask ) ,
5961 Vfs ( vfs:: loader:: Message ) ,
6062 Flycheck ( flycheck:: Message ) ,
6163}
@@ -67,13 +69,20 @@ impl fmt::Display for Event {
6769 Event :: Task ( _) => write ! ( f, "Event::Task" ) ,
6870 Event :: Vfs ( _) => write ! ( f, "Event::Vfs" ) ,
6971 Event :: Flycheck ( _) => write ! ( f, "Event::Flycheck" ) ,
72+ Event :: QueuedTask ( _) => write ! ( f, "Event::QueuedTask" ) ,
7073 }
7174 }
7275}
7376
77+ #[ derive( Debug ) ]
78+ pub ( crate ) enum QueuedTask {
79+ CheckIfIndexed ( lsp_types:: Url ) ,
80+ }
81+
7482#[ derive( Debug ) ]
7583pub ( crate ) enum Task {
7684 Response ( lsp_server:: Response ) ,
85+ ClientNotification ( ext:: UnindexedProjectParams ) ,
7786 Retry ( lsp_server:: Request ) ,
7887 Diagnostics ( Vec < ( FileId , Vec < lsp_types:: Diagnostic > ) > ) ,
7988 PrimeCaches ( PrimeCachesProgress ) ,
@@ -115,6 +124,7 @@ impl fmt::Debug for Event {
115124 match self {
116125 Event :: Lsp ( it) => fmt:: Debug :: fmt ( it, f) ,
117126 Event :: Task ( it) => fmt:: Debug :: fmt ( it, f) ,
127+ Event :: QueuedTask ( it) => fmt:: Debug :: fmt ( it, f) ,
118128 Event :: Vfs ( it) => fmt:: Debug :: fmt ( it, f) ,
119129 Event :: Flycheck ( it) => fmt:: Debug :: fmt ( it, f) ,
120130 }
@@ -193,6 +203,9 @@ impl GlobalState {
193203 recv( self . task_pool. receiver) -> task =>
194204 Some ( Event :: Task ( task. unwrap( ) ) ) ,
195205
206+ recv( self . deferred_task_queue. receiver) -> task =>
207+ Some ( Event :: QueuedTask ( task. unwrap( ) ) ) ,
208+
196209 recv( self . fmt_pool. receiver) -> task =>
197210 Some ( Event :: Task ( task. unwrap( ) ) ) ,
198211
@@ -211,7 +224,7 @@ impl GlobalState {
211224 . entered ( ) ;
212225
213226 let event_dbg_msg = format ! ( "{event:?}" ) ;
214- tracing:: debug!( "{:?} handle_event({})" , loop_start , event_dbg_msg ) ;
227+ tracing:: debug!( ?loop_start , ?event , "handle_event" ) ;
215228 if tracing:: enabled!( tracing:: Level :: INFO ) {
216229 let task_queue_len = self . task_pool . handle . len ( ) ;
217230 if task_queue_len > 0 {
@@ -226,6 +239,16 @@ impl GlobalState {
226239 lsp_server:: Message :: Notification ( not) => self . on_notification ( not) ?,
227240 lsp_server:: Message :: Response ( resp) => self . complete_request ( resp) ,
228241 } ,
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+ }
229252 Event :: Task ( task) => {
230253 let _p = tracing:: span!( tracing:: Level :: INFO , "GlobalState::handle_event/task" )
231254 . entered ( ) ;
@@ -498,6 +521,9 @@ impl GlobalState {
498521 fn handle_task ( & mut self , prime_caches_progress : & mut Vec < PrimeCachesProgress > , task : Task ) {
499522 match task {
500523 Task :: Response ( response) => self . respond ( response) ,
524+ Task :: ClientNotification ( params) => {
525+ self . send_notification :: < lsp_ext:: UnindexedProject > ( params)
526+ }
501527 // Only retry requests that haven't been cancelled. Otherwise we do unnecessary work.
502528 Task :: Retry ( req) if !self . is_completed ( & req) => self . on_request ( req) ,
503529 Task :: Retry ( _) => ( ) ,
@@ -638,6 +664,31 @@ impl GlobalState {
638664 }
639665 }
640666
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+
641692 fn handle_flycheck_msg ( & mut self , message : flycheck:: Message ) {
642693 match message {
643694 flycheck:: Message :: AddDiagnostic { id, workspace_root, diagnostic } => {
0 commit comments