@@ -579,13 +579,6 @@ fn handle_debounced_events(
579579
580580 files_to_update_git_status. reserve ( paths_to_add_or_modify. len ( ) ) ;
581581 for path in & paths_to_add_or_modify {
582- // Double-check existence: the debouncer may deliver a Modify event
583- // for a path that was deleted between event emission and processing
584- // (Create+Remove merged into just Create by the debouncer).
585- if !path. exists ( ) {
586- picker. remove_file_by_path ( path) ;
587- continue ;
588- }
589582 if picker. handle_create_or_modify ( path) . is_some ( ) {
590583 files_to_update_git_status. push ( path. to_path_buf ( ) ) ;
591584 } else {
@@ -594,40 +587,12 @@ fn handle_debounced_events(
594587 }
595588
596589 overflow_count = picker. get_overflow_files ( ) . len ( ) ;
597-
598- // Reconcile overflow files: stat-check each live overflow file and
599- // tombstone any that no longer exist on disk. This handles deletions
600- // where the debouncer swallowed the Remove event.
601- if overflow_count > 0 {
602- let base_path = picker. base_path ( ) . to_path_buf ( ) ;
603- let stale: Vec < PathBuf > = picker
604- . get_overflow_files ( )
605- . iter ( )
606- . filter ( |f| !f. is_deleted ( ) )
607- . filter_map ( |f| {
608- let abs = f. absolute_path ( & * picker, & base_path) ;
609- ( !abs. exists ( ) ) . then_some ( abs)
610- } )
611- . collect ( ) ;
612-
613- for path in & stale {
614- picker. remove_file_by_path ( path) ;
615- }
616- if !stale. is_empty ( ) {
617- overflow_count = picker. get_overflow_files ( ) . len ( ) ;
618- }
619- }
620590 }
621591
622592 info ! (
623593 files_updated = files_to_update_git_status. len( ) ,
624594 overflow_count, "File index changes applied" ,
625595 ) ;
626-
627- // Reconcile overflow files unconditionally on every batch: stat-check
628- // each live overflow file and tombstone any that no longer exist on disk.
629- // This is the only reliable way to detect deletions when the debouncer
630- // coalesces Create+Remove for the same path into nothing.
631596 if need_full_rescan || overflow_count > MAX_OVERFLOW_FILES {
632597 info ! ( "Watcher faced limit of index overflow. Triggering rescan" ) ;
633598 if let Err ( e) = shared_picker. trigger_full_rescan_async ( shared_frecency) {
@@ -679,50 +644,47 @@ fn handle_debounced_events(
679644 }
680645 }
681646
682- // Git status updates are IO-heavy (reads .git/index, stats files) and
683- // not on the critical path for search correctness. Spawn them on the
684- // background pool so the debouncer handler returns immediately and can
685- // process the next event batch without waiting for git.
686- if need_full_git_rescan || !files_to_update_git_status. is_empty ( ) {
687- let sp = shared_picker. clone ( ) ;
688- let sf = shared_frecency. clone ( ) ;
689- let git_workdir = repo. as_ref ( ) . map ( |r| {
690- r. workdir ( )
691- . unwrap_or_else ( || r. path ( ) )
692- . to_path_buf ( )
693- } ) ;
694- let full_rescan = need_full_git_rescan;
695- let need_picker_rescan = need_full_rescan;
696- let files = files_to_update_git_status;
647+ // do not try to update the paths if we anyway going to rescan everythign from scracth
648+ if !need_full_rescan && ( need_full_git_rescan || !files_to_update_git_status. is_empty ( ) ) {
649+ let git_workdir = repo
650+ . as_ref ( )
651+ . map ( |r| r. workdir ( ) . unwrap_or_else ( || r. path ( ) ) . to_path_buf ( ) ) ;
652+
653+ let shared_picker = shared_picker. clone ( ) ;
654+ let shared_frecency = shared_frecency. clone ( ) ;
697655
656+ // git status query even with a pathspec could be really slow, if we do this syncrhronously
657+ // within the event handler, we actually risk of forming a snow ball of conflicting events
698658 crate :: file_picker:: BACKGROUND_THREAD_POOL . spawn ( move || {
699659 let Some ( git_path) = git_workdir else { return } ;
700660 let Ok ( repo) = Repository :: open ( & git_path) else {
701661 error ! ( "Failed to open git repo for async status update" ) ;
702662 return ;
703663 } ;
704664
705- if full_rescan && !need_picker_rescan {
665+ if need_full_git_rescan && !need_full_rescan {
706666 info ! ( "Async: triggering full git rescan" ) ;
707- if let Err ( e) = sp . refresh_git_status ( & sf ) {
667+ if let Err ( e) = shared_picker . refresh_git_status ( & shared_frecency ) {
708668 error ! ( "Failed to refresh git status: {:?}" , e) ;
709669 }
710670 }
711671
712- if !files. is_empty ( ) && !full_rescan {
713- info ! ( "Async: fetching git status for {} files" , files. len( ) ) ;
714- let status = match GitStatusCache :: git_status_for_paths ( & repo, & files) {
672+ if !files_to_update_git_status. is_empty ( ) {
673+ let status = match GitStatusCache :: git_status_for_paths (
674+ & repo,
675+ & files_to_update_git_status,
676+ ) {
715677 Ok ( s) => s,
716678 Err ( e) => {
717679 error ! ( "Failed to query git status: {:?}" , e) ;
718680 return ;
719681 }
720682 } ;
721683
722- if let Ok ( mut guard) = sp . write ( )
684+ if let Ok ( mut guard) = shared_picker . write ( )
723685 && let Some ( ref mut picker) = * guard
724686 {
725- if let Err ( e) = picker. update_git_statuses ( status, & sf ) {
687+ if let Err ( e) = picker. update_git_statuses ( status, & shared_frecency ) {
726688 error ! ( "Failed to update git statuses: {:?}" , e) ;
727689 } else {
728690 info ! ( "Async: git statuses updated" ) ;
0 commit comments