Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions crates/worktree/src/worktree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ struct BackgroundScannerState {
removed_entries: HashMap<u64, Entry>,
changed_paths: Vec<Arc<RelPath>>,
prev_snapshot: Snapshot,
scanning_enabled: bool,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -447,7 +448,11 @@ impl Worktree {
snapshot.root_char_bag,
None,
);
if !metadata.is_dir {
if metadata.is_dir {
if !scanning_enabled {
entry.kind = EntryKind::UnloadedDir;
}
} else {
if let Some(file_name) = abs_path.file_name()
&& let Some(file_name) = file_name.to_str()
&& let Ok(path) = RelPath::unix(file_name)
Expand Down Expand Up @@ -1101,14 +1106,14 @@ impl LocalWorktree {
prev_snapshot: snapshot.snapshot.clone(),
snapshot,
scanned_dirs: Default::default(),
scanning_enabled,
path_prefixes_to_scan: Default::default(),
paths_to_scan: Default::default(),
removed_entries: Default::default(),
changed_paths: Default::default(),
}),
phase: BackgroundScannerPhase::InitialScan,
share_private_files,
scanning_enabled,
settings,
watcher,
};
Expand Down Expand Up @@ -2777,7 +2782,7 @@ impl LocalSnapshot {

impl BackgroundScannerState {
fn should_scan_directory(&self, entry: &Entry) -> bool {
(!entry.is_external && (!entry.is_ignored || entry.is_always_included))
(self.scanning_enabled && !entry.is_external && (!entry.is_ignored || entry.is_always_included))
|| entry.path.file_name() == Some(DOT_GIT)
|| entry.path.file_name() == Some(local_settings_folder_name())
|| entry.path.file_name() == Some(local_vscode_folder_name())
Expand Down Expand Up @@ -3726,7 +3731,6 @@ struct BackgroundScanner {
watcher: Arc<dyn Watcher>,
settings: WorktreeSettings,
share_private_files: bool,
scanning_enabled: bool,
}

#[derive(Copy, Clone, PartialEq)]
Expand All @@ -3738,12 +3742,18 @@ enum BackgroundScannerPhase {

impl BackgroundScanner {
async fn run(&mut self, mut fs_events_rx: Pin<Box<dyn Send + Stream<Item = Vec<PathEvent>>>>) {
let root_abs_path;
let scanning_enabled;
{
let state = self.state.lock().await;
root_abs_path = state.snapshot.abs_path.clone();
scanning_enabled = state.scanning_enabled;
}

// If the worktree root does not contain a git repository, then find
// the git repository in an ancestor directory. Find any gitignore files
// in ancestor directories.
let root_abs_path = self.state.lock().await.snapshot.abs_path.clone();

let repo = if self.scanning_enabled {
let repo = if scanning_enabled {
let (ignores, exclude, repo) =
discover_ancestor_git_repo(self.fs.clone(), &root_abs_path).await;
self.state
Expand All @@ -3767,7 +3777,7 @@ impl BackgroundScanner {
};

let containing_git_repository = if let Some((ancestor_dot_git, work_directory)) = repo
&& self.scanning_enabled
&& scanning_enabled
{
maybe!(async {
self.state
Expand All @@ -3792,7 +3802,7 @@ impl BackgroundScanner {

let mut global_gitignore_events = if let Some(global_gitignore_path) =
&paths::global_gitignore_path()
&& self.scanning_enabled
&& scanning_enabled
{
let is_file = self.fs.is_file(&global_gitignore_path).await;
self.state.lock().await.snapshot.global_gitignore = if is_file {
Expand Down Expand Up @@ -3835,7 +3845,7 @@ impl BackgroundScanner {
.insert_entry(root_entry, self.fs.as_ref(), self.watcher.as_ref())
.await;
}
if root_entry.is_dir() && self.scanning_enabled {
if root_entry.is_dir() && state.scanning_enabled {
state
.enqueue_scan_dir(
root_abs_path.as_path().into(),
Expand Down
81 changes: 81 additions & 0 deletions crates/worktree/src/worktree_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2843,3 +2843,84 @@ async fn test_write_file_encoding(cx: &mut gpui::TestAppContext) {
);
}
}

#[gpui::test]
async fn test_refresh_entries_for_paths_creates_ancestors(cx: &mut TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.background_executor.clone());
fs.insert_tree(
"/root",
json!({
"a": {
"b": {
"c": {
"deep_file.txt": "content",
"sibling.txt": "content"
},
"d": {
"under_sibling_dir.txt": "content"
}
}
}
}),
)
.await;

let tree = Worktree::local(
Path::new("/root"),
true,
fs.clone(),
Default::default(),
false, // Disable scanning so the initial scan doesn't discover any entries
&mut cx.to_async(),
)
.await
.unwrap();

cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
.await;

tree.read_with(cx, |tree, _| {
assert_eq!(
tree.entries(true, 0)
.map(|e| e.path.as_ref())
.collect::<Vec<_>>(),
&[rel_path("")],
"Only root entry should exist when scanning is disabled"
);

assert!(tree.entry_for_path(rel_path("a")).is_none());
assert!(tree.entry_for_path(rel_path("a/b")).is_none());
assert!(tree.entry_for_path(rel_path("a/b/c")).is_none());
assert!(
tree.entry_for_path(rel_path("a/b/c/deep_file.txt"))
.is_none()
);
});

tree.read_with(cx, |tree, _| {
tree.as_local()
.unwrap()
.refresh_entries_for_paths(vec![rel_path("a/b/c/deep_file.txt").into()])
})
.recv()
.await;

tree.read_with(cx, |tree, _| {
assert_eq!(
tree.entries(true, 0)
.map(|e| e.path.as_ref())
.collect::<Vec<_>>(),
&[
rel_path(""),
rel_path("a"),
rel_path("a/b"),
rel_path("a/b/c"),
rel_path("a/b/c/deep_file.txt"),
rel_path("a/b/c/sibling.txt"),
rel_path("a/b/d"),
],
"All ancestors should be created when refreshing a deeply nested path"
);
});
}