Fix infinite loop when worktree is deleted (#39637)

Andrew Farkas and Conrad Irwin created

Closes #39442

Release Notes:

- Fixed infinite loop when worktree is deleted

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>

Change summary

crates/project/src/worktree_store.rs |  2 
crates/worktree/src/worktree.rs      | 36 ++++++++++++++---------------
2 files changed, 18 insertions(+), 20 deletions(-)

Detailed changes

crates/project/src/worktree_store.rs 🔗

@@ -395,7 +395,7 @@ impl WorktreeStore {
                                 // Otherwise, the FS watcher would do it on the `RootUpdated` event,
                                 // but with a noticeable delay, so we handle it proactively.
                                 local.update_abs_path_and_refresh(
-                                    Some(SanitizedPath::new_arc(&abs_new_path)),
+                                    SanitizedPath::new_arc(&abs_new_path),
                                     cx,
                                 );
                                 Task::ready(Ok(this.root_entry().cloned()))

crates/worktree/src/worktree.rs 🔗

@@ -331,7 +331,7 @@ enum ScanState {
         scanning: bool,
     },
     RootUpdated {
-        new_path: Option<Arc<SanitizedPath>>,
+        new_path: Arc<SanitizedPath>,
     },
 }
 
@@ -1769,21 +1769,19 @@ impl LocalWorktree {
 
     pub fn update_abs_path_and_refresh(
         &mut self,
-        new_path: Option<Arc<SanitizedPath>>,
+        new_path: Arc<SanitizedPath>,
         cx: &Context<Worktree>,
     ) {
-        if let Some(new_path) = new_path {
-            self.snapshot.git_repositories = Default::default();
-            self.snapshot.ignores_by_parent_abs_path = Default::default();
-            let root_name = new_path
-                .as_path()
-                .file_name()
-                .and_then(|f| f.to_str())
-                .map_or(RelPath::empty().into(), |f| {
-                    RelPath::unix(f).unwrap().into()
-                });
-            self.snapshot.update_abs_path(new_path, root_name);
-        }
+        self.snapshot.git_repositories = Default::default();
+        self.snapshot.ignores_by_parent_abs_path = Default::default();
+        let root_name = new_path
+            .as_path()
+            .file_name()
+            .and_then(|f| f.to_str())
+            .map_or(RelPath::empty().into(), |f| {
+                RelPath::unix(f).unwrap().into()
+            });
+        self.snapshot.update_abs_path(new_path, root_name);
         self.restart_background_scanners(cx);
     }
 }
@@ -3775,18 +3773,18 @@ impl BackgroundScanner {
                     .map(|path| SanitizedPath::new_arc(&path))
                     .filter(|new_path| *new_path != root_path);
 
-                if let Some(new_path) = new_path.as_ref() {
+                if let Some(new_path) = new_path {
                     log::info!(
                         "root renamed from {} to {}",
                         root_path.as_path().display(),
                         new_path.as_path().display()
-                    )
+                    );
+                    self.status_updates_tx
+                        .unbounded_send(ScanState::RootUpdated { new_path })
+                        .ok();
                 } else {
                     log::warn!("root path could not be canonicalized: {}", err);
                 }
-                self.status_updates_tx
-                    .unbounded_send(ScanState::RootUpdated { new_path })
-                    .ok();
                 return;
             }
         };