Fix the tests

Kirill Bulatov created

Change summary

crates/project/src/worktree.rs            |  74 +++++++------
crates/project_panel/src/project_panel.rs | 126 ++++++++++++++++++++++++
2 files changed, 165 insertions(+), 35 deletions(-)

Detailed changes

crates/project/src/worktree.rs 🔗

@@ -2464,21 +2464,30 @@ impl BackgroundScannerState {
 
         // Remove any git repositories whose .git entry no longer exists.
         let snapshot = &mut self.snapshot;
-        // TODO kb stop cleaning those up here?
-        let mut repositories = mem::take(&mut snapshot.git_repositories);
-        let mut repository_entries = mem::take(&mut snapshot.repository_entries);
-        repositories.retain(|_, entry| {
-            // TODO kb use fs
-            snapshot.abs_path().join(&entry.git_dir_path).exists()
-            // snapshot
-            //     .entry_for_id(*work_directory_id)
-            //     .map_or(false, |entry| {
-            //         snapshot.entry_for_path(entry.path.join(*DOT_GIT)).is_some()
-            //     })
-        });
-        repository_entries.retain(|_, entry| repositories.get(&entry.work_directory.0).is_some());
-        snapshot.git_repositories = repositories;
-        snapshot.repository_entries = repository_entries;
+        let mut ids_to_preserve = HashSet::default();
+        for (&work_directory_id, entry) in snapshot.git_repositories.iter() {
+            let exists_in_snapshot = snapshot
+                .entry_for_id(work_directory_id)
+                .map_or(false, |entry| {
+                    snapshot.entry_for_path(entry.path.join(*DOT_GIT)).is_some()
+                });
+            if exists_in_snapshot {
+                ids_to_preserve.insert(work_directory_id);
+            } else {
+                let git_dir_abs_path = snapshot.abs_path().join(&entry.git_dir_path);
+                if snapshot.is_abs_path_excluded(&git_dir_abs_path)
+                    && !matches!(smol::block_on(fs.metadata(&git_dir_abs_path)), Ok(None))
+                {
+                    ids_to_preserve.insert(work_directory_id);
+                }
+            }
+        }
+        snapshot
+            .git_repositories
+            .retain(|work_directory_id, _| ids_to_preserve.contains(work_directory_id));
+        snapshot
+            .repository_entries
+            .retain(|_, entry| ids_to_preserve.contains(&entry.work_directory.0));
     }
 
     fn build_git_repository(
@@ -3320,20 +3329,22 @@ impl BackgroundScanner {
                         return false;
                     };
 
-                let parent_dir_is_loaded = relative_path.parent().map_or(true, |parent| {
-                    snapshot
-                        .entry_for_path(parent)
-                        .map_or(false, |entry| entry.kind == EntryKind::Dir)
-                });
-                if !parent_dir_is_loaded && !is_git_related(&abs_path) {
-                    log::debug!("ignoring event {relative_path:?} within unloaded directory");
-                    return false;
-                }
-                if snapshot.is_abs_path_excluded(abs_path) && !is_git_related(&abs_path) {
-                    log::debug!(
+                if !is_git_related(&abs_path) {
+                    let parent_dir_is_loaded = relative_path.parent().map_or(true, |parent| {
+                        snapshot
+                            .entry_for_path(parent)
+                            .map_or(false, |entry| entry.kind == EntryKind::Dir)
+                    });
+                    if !parent_dir_is_loaded {
+                        log::debug!("ignoring event {relative_path:?} within unloaded directory");
+                        return false;
+                    }
+                    if snapshot.is_abs_path_excluded(abs_path) {
+                        log::debug!(
                         "ignoring FS event for path {relative_path:?} within excluded directory"
                     );
-                    return false;
+                        return false;
+                    }
                 }
 
                 relative_paths.push(relative_path);
@@ -3573,11 +3584,6 @@ impl BackgroundScanner {
             // If we find a .git, we'll need to load the repository.
             else if child_name == *DOT_GIT {
                 dotgit_path = Some(child_path.clone());
-                {
-                    let mut state = self.state.lock();
-                    state.build_git_repository(child_path.clone(), self.fs.as_ref());
-                    drop(state);
-                }
             }
 
             {
@@ -3595,7 +3601,7 @@ impl BackgroundScanner {
                 Ok(Some(metadata)) => metadata,
                 Ok(None) => continue,
                 Err(err) => {
-                    log::error!("error processing {:?}: {:?}", child_abs_path, err);
+                    log::error!("error processing {child_abs_path:?}: {err:?}");
                     continue;
                 }
             };
@@ -4124,7 +4130,7 @@ impl BackgroundScanner {
     }
 }
 
-fn is_git_related(abs_path: &&PathBuf) -> bool {
+fn is_git_related(abs_path: &Path) -> bool {
     abs_path
         .components()
         .any(|c| c.as_os_str() == *DOT_GIT || c.as_os_str() == *GITIGNORE)

crates/project_panel/src/project_panel.rs 🔗

@@ -1732,7 +1732,7 @@ mod tests {
     use super::*;
     use gpui::{AnyWindowHandle, TestAppContext, ViewHandle, WindowHandle};
     use pretty_assertions::assert_eq;
-    use project::FakeFs;
+    use project::{project_settings::ProjectSettings, FakeFs};
     use serde_json::json;
     use settings::SettingsStore;
     use std::{
@@ -1832,6 +1832,123 @@ mod tests {
         );
     }
 
+    #[gpui::test]
+    async fn test_exclusions_in_visible_list(cx: &mut gpui::TestAppContext) {
+        init_test(cx);
+        cx.update(|cx| {
+            cx.update_global::<SettingsStore, _, _>(|store, cx| {
+                store.update_user_settings::<ProjectSettings>(cx, |project_settings| {
+                    project_settings.file_scan_exclusions =
+                        Some(vec!["**/.git".to_string(), "**/4/**".to_string()]);
+                });
+            });
+        });
+
+        let fs = FakeFs::new(cx.background());
+        fs.insert_tree(
+            "/root1",
+            json!({
+                ".dockerignore": "",
+                ".git": {
+                    "HEAD": "",
+                },
+                "a": {
+                    "0": { "q": "", "r": "", "s": "" },
+                    "1": { "t": "", "u": "" },
+                    "2": { "v": "", "w": "", "x": "", "y": "" },
+                },
+                "b": {
+                    "3": { "Q": "" },
+                    "4": { "R": "", "S": "", "T": "", "U": "" },
+                },
+                "C": {
+                    "5": {},
+                    "6": { "V": "", "W": "" },
+                    "7": { "X": "" },
+                    "8": { "Y": {}, "Z": "" }
+                }
+            }),
+        )
+        .await;
+        fs.insert_tree(
+            "/root2",
+            json!({
+                "d": {
+                    "4": ""
+                },
+                "e": {}
+            }),
+        )
+        .await;
+
+        let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
+        let workspace = cx
+            .add_window(|cx| Workspace::test_new(project.clone(), cx))
+            .root(cx);
+        let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
+        assert_eq!(
+            visible_entries_as_strings(&panel, 0..50, cx),
+            &[
+                "v root1",
+                "    > a",
+                "    > b",
+                "    > C",
+                "      .dockerignore",
+                "v root2",
+                "    > d",
+                "    > e",
+            ]
+        );
+
+        toggle_expand_dir(&panel, "root1/b", cx);
+        assert_eq!(
+            visible_entries_as_strings(&panel, 0..50, cx),
+            &[
+                "v root1",
+                "    > a",
+                "    v b  <== selected",
+                "        > 3",
+                "    > C",
+                "      .dockerignore",
+                "v root2",
+                "    > d",
+                "    > e",
+            ]
+        );
+
+        toggle_expand_dir(&panel, "root2/d", cx);
+        assert_eq!(
+            visible_entries_as_strings(&panel, 0..50, cx),
+            &[
+                "v root1",
+                "    > a",
+                "    v b",
+                "        > 3",
+                "    > C",
+                "      .dockerignore",
+                "v root2",
+                "    v d  <== selected",
+                "    > e",
+            ]
+        );
+
+        toggle_expand_dir(&panel, "root2/e", cx);
+        assert_eq!(
+            visible_entries_as_strings(&panel, 0..50, cx),
+            &[
+                "v root1",
+                "    > a",
+                "    v b",
+                "        > 3",
+                "    > C",
+                "      .dockerignore",
+                "v root2",
+                "    v d",
+                "    v e  <== selected",
+            ]
+        );
+    }
+
     #[gpui::test(iterations = 30)]
     async fn test_editing_files(cx: &mut gpui::TestAppContext) {
         init_test(cx);
@@ -2930,6 +3047,13 @@ mod tests {
             client::init_settings(cx);
             Project::init_settings(cx);
         });
+        cx.update(|cx| {
+            cx.update_global::<SettingsStore, _, _>(|store, cx| {
+                store.update_user_settings::<ProjectSettings>(cx, |project_settings| {
+                    project_settings.file_scan_exclusions = Some(Vec::new());
+                });
+            });
+        });
     }
 
     fn init_test_with_editor(cx: &mut TestAppContext) {