@@ -2759,6 +2759,10 @@ impl EntryKind {
)
}
+ pub fn is_unloaded(&self) -> bool {
+ matches!(self, EntryKind::UnloadedDir)
+ }
+
pub fn is_file(&self) -> bool {
matches!(self, EntryKind::File(_))
}
@@ -3773,6 +3777,7 @@ impl BackgroundScanner {
let mut changes = Vec::new();
let mut old_paths = old_snapshot.entries_by_path.cursor::<PathKey>();
let mut new_paths = new_snapshot.entries_by_path.cursor::<PathKey>();
+ let mut last_newly_loaded_dir_path = None;
old_paths.next(&());
new_paths.next(&());
for path in event_paths {
@@ -3820,20 +3825,33 @@ impl BackgroundScanner {
changes.push((old_entry.path.clone(), old_entry.id, Removed));
changes.push((new_entry.path.clone(), new_entry.id, Added));
} else if old_entry != new_entry {
- changes.push((new_entry.path.clone(), new_entry.id, Updated));
+ if old_entry.kind.is_unloaded() {
+ last_newly_loaded_dir_path = Some(&new_entry.path);
+ changes.push((
+ new_entry.path.clone(),
+ new_entry.id,
+ Loaded,
+ ));
+ } else {
+ changes.push((
+ new_entry.path.clone(),
+ new_entry.id,
+ Updated,
+ ));
+ }
}
old_paths.next(&());
new_paths.next(&());
}
Ordering::Greater => {
+ let is_newly_loaded = self.phase == InitialScan
+ || last_newly_loaded_dir_path
+ .as_ref()
+ .map_or(false, |dir| new_entry.path.starts_with(&dir));
changes.push((
new_entry.path.clone(),
new_entry.id,
- if self.phase == InitialScan {
- Loaded
- } else {
- Added
- },
+ if is_newly_loaded { Loaded } else { Added },
));
new_paths.next(&());
}
@@ -15,6 +15,7 @@ use serde_json::json;
use std::{
env,
fmt::Write,
+ mem,
path::{Path, PathBuf},
sync::Arc,
};
@@ -313,6 +314,21 @@ async fn test_symlinks_pointing_outside(cx: &mut TestAppContext) {
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
.await;
+ let tree_updates = Arc::new(Mutex::new(Vec::new()));
+ tree.update(cx, |_, cx| {
+ let tree_updates = tree_updates.clone();
+ cx.subscribe(&tree, move |_, _, event, _| {
+ if let Event::UpdatedEntries(update) = event {
+ tree_updates.lock().extend(
+ update
+ .iter()
+ .map(|(path, _, change)| (path.clone(), *change)),
+ );
+ }
+ })
+ .detach();
+ });
+
// The symlinked directories are not scanned by default.
tree.read_with(cx, |tree, _| {
assert_eq!(
@@ -365,6 +381,14 @@ async fn test_symlinks_pointing_outside(cx: &mut TestAppContext) {
]
);
});
+ assert_eq!(
+ mem::take(&mut *tree_updates.lock()),
+ &[
+ (Path::new("deps/dep-dir3").into(), PathChange::Loaded),
+ (Path::new("deps/dep-dir3/deps").into(), PathChange::Loaded),
+ (Path::new("deps/dep-dir3/src").into(), PathChange::Loaded)
+ ]
+ );
// Expand a subdirectory of one of the symlinked directories.
tree.read_with(cx, |tree, _| {
@@ -396,6 +420,21 @@ async fn test_symlinks_pointing_outside(cx: &mut TestAppContext) {
]
);
});
+
+ assert_eq!(
+ mem::take(&mut *tree_updates.lock()),
+ &[
+ (Path::new("deps/dep-dir3/src").into(), PathChange::Loaded),
+ (
+ Path::new("deps/dep-dir3/src/e.rs").into(),
+ PathChange::Loaded
+ ),
+ (
+ Path::new("deps/dep-dir3/src/f.rs").into(),
+ PathChange::Loaded
+ )
+ ]
+ );
}
#[gpui::test]
@@ -1114,7 +1153,6 @@ fn check_worktree_change_events(tree: &mut Worktree, cx: &mut ModelContext<Workt
Ok(ix) | Err(ix) => ix,
};
match change_type {
- PathChange::Loaded => entries.insert(ix, entry.unwrap()),
PathChange::Added => entries.insert(ix, entry.unwrap()),
PathChange::Removed => drop(entries.remove(ix)),
PathChange::Updated => {
@@ -1123,7 +1161,7 @@ fn check_worktree_change_events(tree: &mut Worktree, cx: &mut ModelContext<Workt
assert_eq!(existing_entry.path, entry.path);
*existing_entry = entry;
}
- PathChange::AddedOrUpdated => {
+ PathChange::AddedOrUpdated | PathChange::Loaded => {
let entry = entry.unwrap();
if entries.get(ix).map(|e| &e.path) == Some(&entry.path) {
*entries.get_mut(ix).unwrap() = entry;