diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index 152277af2e3f626aa0da608af275505b04d0af32..942e692a020049b102a0d810bfbf1a9074962611 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -52,7 +52,7 @@ use std::{ fmt, future::Future, mem::{self}, - ops::{Deref, DerefMut}, + ops::{Deref, DerefMut, Range}, path::{Path, PathBuf}, pin::Pin, sync::{ @@ -3877,29 +3877,35 @@ impl BackgroundScanner { abs_paths.dedup_by(|a, b| a.starts_with(b)); { let snapshot = &self.state.lock().await.snapshot; - abs_paths.retain(|abs_path| { - let abs_path = &SanitizedPath::new(abs_path); + let mut ranges_to_drop = SmallVec::<[Range; 4]>::new(); - { - let mut is_git_related = false; + fn skip_ix(ranges: &mut SmallVec<[Range; 4]>, ix: usize) { + if let Some(last_range) = ranges.last_mut() + && last_range.end == ix + { + last_range.end += 1; + } else { + ranges.push(ix..ix + 1); + } + } - let dot_git_paths = self.executor.block(maybe!(async { - let mut path = None; - for ancestor in abs_path.as_path().ancestors() { + for (ix, abs_path) in abs_paths.iter().enumerate() { + let abs_path = &SanitizedPath::new(&abs_path); + let mut is_git_related = false; + let mut dot_git_paths = None; + + for ancestor in abs_path.as_path().ancestors() { if is_git_dir(ancestor, self.fs.as_ref()).await { let path_in_git_dir = abs_path .as_path() .strip_prefix(ancestor) .expect("stripping off the ancestor"); - path = Some((ancestor.to_owned(), path_in_git_dir.to_owned())); - break; - } + dot_git_paths = Some((ancestor.to_owned(), path_in_git_dir.to_owned())); + break; } - path - - })); + } if let Some((dot_git_abs_path, path_in_git_dir)) = dot_git_paths { if skipped_files_in_dot_git @@ -3909,8 +3915,11 @@ impl BackgroundScanner { path_in_git_dir.starts_with(skipped_git_subdir) }) { - log::debug!("ignoring event {abs_path:?} as it's in the .git directory among skipped files or directories"); - return false; + log::debug!( + "ignoring event {abs_path:?} as it's in the .git directory among skipped files or directories" + ); + skip_ix(&mut ranges_to_drop, ix); + continue; } is_git_related = true; @@ -3919,8 +3928,7 @@ impl BackgroundScanner { } } - let relative_path = if let Ok(path) = - abs_path.strip_prefix(&root_canonical_path) + let relative_path = if let Ok(path) = abs_path.strip_prefix(&root_canonical_path) && let Ok(path) = RelPath::new(path, PathStyle::local()) { path @@ -3931,10 +3939,11 @@ impl BackgroundScanner { ); } else { log::error!( - "ignoring event {abs_path:?} outside of root path {root_canonical_path:?}", + "ignoring event {abs_path:?} outside of root path {root_canonical_path:?}", ); } - return false; + skip_ix(&mut ranges_to_drop, ix); + continue; }; if abs_path.file_name() == Some(OsStr::new(GITIGNORE)) { @@ -3958,21 +3967,26 @@ impl BackgroundScanner { }); if !parent_dir_is_loaded { log::debug!("ignoring event {relative_path:?} within unloaded directory"); - return false; + skip_ix(&mut ranges_to_drop, ix); + continue; } if self.settings.is_path_excluded(&relative_path) { if !is_git_related { log::debug!("ignoring FS event for excluded path {relative_path:?}"); } - return false; + skip_ix(&mut ranges_to_drop, ix); + continue; } relative_paths.push(relative_path.into_arc()); - true } - }); + + for range_to_drop in ranges_to_drop.into_iter().rev() { + abs_paths.drain(range_to_drop); + } } + if relative_paths.is_empty() && dot_git_abs_paths.is_empty() { return; }