This commit is contained in:
Cole Miller 2025-07-29 10:43:00 -04:00
parent 890ff160d7
commit 37336c6211
2 changed files with 54 additions and 31 deletions

View file

@ -1,42 +1,60 @@
use ignore::gitignore::Gitignore; use ignore::gitignore::Gitignore;
use std::{ffi::OsStr, path::Path, sync::Arc}; use std::{ffi::OsStr, path::Path, sync::Arc};
#[derive(Clone, Debug)]
pub struct IgnoreStack {
pub repo_root: Option<Arc<Path>>,
pub top: Arc<IgnoreStackEntry>,
}
#[derive(Debug)] #[derive(Debug)]
pub enum IgnoreStack { pub enum IgnoreStackEntry {
None, None,
Global { Global {
repo_root: Option<Arc<Path>>,
ignore: Arc<Gitignore>, ignore: Arc<Gitignore>,
}, },
Some { Some {
abs_base_path: Arc<Path>, abs_base_path: Arc<Path>,
ignore: Arc<Gitignore>, ignore: Arc<Gitignore>,
parent: Arc<IgnoreStack>, parent: Arc<IgnoreStackEntry>,
}, },
All, All,
} }
impl IgnoreStack { impl IgnoreStack {
pub fn none() -> Arc<Self> { pub fn none() -> Self {
Arc::new(Self::None) Self {
repo_root: None,
top: Arc::new(IgnoreStackEntry::None),
}
} }
pub fn all() -> Arc<Self> { pub fn all() -> Self {
Arc::new(Self::All) Self {
repo_root: None,
top: Arc::new(IgnoreStackEntry::All),
}
} }
pub fn global(repo_root: Option<Arc<Path>>, ignore: Arc<Gitignore>) -> Arc<Self> { pub fn global(ignore: Arc<Gitignore>) -> Self {
Arc::new(Self::Global { repo_root, ignore }) Self {
repo_root: None,
top: Arc::new(IgnoreStackEntry::Global { ignore }),
}
} }
pub fn append(self: Arc<Self>, abs_base_path: Arc<Path>, ignore: Arc<Gitignore>) -> Arc<Self> { pub fn append(self, abs_base_path: Arc<Path>, ignore: Arc<Gitignore>) -> Self {
match self.as_ref() { let top = match self.top.as_ref() {
IgnoreStack::All => self, IgnoreStackEntry::All => self.top.clone(),
_ => Arc::new(Self::Some { _ => Arc::new(IgnoreStackEntry::Some {
abs_base_path, abs_base_path,
ignore, ignore,
parent: self, parent: self.top.clone(),
}), }),
};
Self {
repo_root: self.repo_root,
top,
} }
} }
@ -45,12 +63,12 @@ impl IgnoreStack {
return true; return true;
} }
match self { match self.top.as_ref() {
Self::None => false, IgnoreStackEntry::None => false,
Self::All => true, IgnoreStackEntry::All => true,
Self::Global { repo_root, ignore } => { IgnoreStackEntry::Global { ignore } => {
let combined_path; let combined_path;
let abs_path = if let Some(repo_root) = repo_root { let abs_path = if let Some(repo_root) = self.repo_root.as_ref() {
combined_path = ignore.path().join( combined_path = ignore.path().join(
abs_path abs_path
.strip_prefix(repo_root) .strip_prefix(repo_root)
@ -66,12 +84,16 @@ impl IgnoreStack {
ignore::Match::Whitelist(_) => false, ignore::Match::Whitelist(_) => false,
} }
} }
Self::Some { IgnoreStackEntry::Some {
abs_base_path, abs_base_path,
ignore, ignore,
parent: prev, parent: prev,
} => match ignore.matched(abs_path.strip_prefix(abs_base_path).unwrap(), is_dir) { } => match ignore.matched(abs_path.strip_prefix(abs_base_path).unwrap(), is_dir) {
ignore::Match::None => prev.is_abs_path_ignored(abs_path, is_dir), ignore::Match::None => IgnoreStack {
repo_root: self.repo_root.clone(),
top: prev.clone(),
}
.is_abs_path_ignored(abs_path, is_dir),
ignore::Match::Ignore(_) => true, ignore::Match::Ignore(_) => true,
ignore::Match::Whitelist(_) => false, ignore::Match::Whitelist(_) => false,
}, },

View file

@ -2777,12 +2777,7 @@ impl LocalSnapshot {
inodes inodes
} }
fn ignore_stack_for_abs_path( fn ignore_stack_for_abs_path(&self, abs_path: &Path, is_dir: bool, fs: &dyn Fs) -> IgnoreStack {
&self,
abs_path: &Path,
is_dir: bool,
fs: &dyn Fs,
) -> Arc<IgnoreStack> {
let mut new_ignores = Vec::new(); let mut new_ignores = Vec::new();
let mut repo_root = None; let mut repo_root = None;
for (index, ancestor) in abs_path.ancestors().enumerate() { for (index, ancestor) in abs_path.ancestors().enumerate() {
@ -2803,10 +2798,11 @@ impl LocalSnapshot {
} }
let mut ignore_stack = if let Some(global_gitignore) = self.global_gitignore.clone() { let mut ignore_stack = if let Some(global_gitignore) = self.global_gitignore.clone() {
IgnoreStack::global(repo_root, global_gitignore) IgnoreStack::global(global_gitignore)
} else { } else {
IgnoreStack::none() IgnoreStack::none()
}; };
ignore_stack.repo_root = repo_root;
for (parent_abs_path, ignore) in new_ignores.into_iter().rev() { for (parent_abs_path, ignore) in new_ignores.into_iter().rev() {
if ignore_stack.is_abs_path_ignored(parent_abs_path, true) { if ignore_stack.is_abs_path_ignored(parent_abs_path, true) {
ignore_stack = IgnoreStack::all(); ignore_stack = IgnoreStack::all();
@ -4369,12 +4365,14 @@ impl BackgroundScanner {
swap_to_front(&mut child_paths, *GITIGNORE); swap_to_front(&mut child_paths, *GITIGNORE);
swap_to_front(&mut child_paths, *DOT_GIT); swap_to_front(&mut child_paths, *DOT_GIT);
let mut repo_root = None;
for child_abs_path in child_paths { for child_abs_path in child_paths {
let child_abs_path: Arc<Path> = child_abs_path.into(); let child_abs_path: Arc<Path> = child_abs_path.into();
let child_name = child_abs_path.file_name().unwrap(); let child_name = child_abs_path.file_name().unwrap();
let child_path: Arc<Path> = job.path.join(child_name).into(); let child_path: Arc<Path> = job.path.join(child_name).into();
if child_name == *DOT_GIT { if child_name == *DOT_GIT {
repo_root = Some(child_abs_path.clone());
let mut state = self.state.lock(); let mut state = self.state.lock();
state.insert_git_repository( state.insert_git_repository(
child_path.clone(), child_path.clone(),
@ -4386,6 +4384,9 @@ impl BackgroundScanner {
Ok(ignore) => { Ok(ignore) => {
let ignore = Arc::new(ignore); let ignore = Arc::new(ignore);
ignore_stack = ignore_stack.append(job.abs_path.clone(), ignore.clone()); ignore_stack = ignore_stack.append(job.abs_path.clone(), ignore.clone());
if let Some(repo_root) = repo_root.clone() {
ignore_stack.repo_root = Some(repo_root);
}
new_ignore = Some(ignore); new_ignore = Some(ignore);
} }
Err(error) => { Err(error) => {
@ -4688,7 +4689,7 @@ impl BackgroundScanner {
&self, &self,
scan_job_tx: Sender<ScanJob>, scan_job_tx: Sender<ScanJob>,
prev_snapshot: LocalSnapshot, prev_snapshot: LocalSnapshot,
mut ignores_to_update: impl Iterator<Item = (Arc<Path>, Arc<IgnoreStack>)>, mut ignores_to_update: impl Iterator<Item = (Arc<Path>, IgnoreStack)>,
) { ) {
let (ignore_queue_tx, ignore_queue_rx) = channel::unbounded(); let (ignore_queue_tx, ignore_queue_rx) = channel::unbounded();
{ {
@ -5147,7 +5148,7 @@ fn char_bag_for_path(root_char_bag: CharBag, path: &Path) -> CharBag {
struct ScanJob { struct ScanJob {
abs_path: Arc<Path>, abs_path: Arc<Path>,
path: Arc<Path>, path: Arc<Path>,
ignore_stack: Arc<IgnoreStack>, ignore_stack: IgnoreStack,
scan_queue: Sender<ScanJob>, scan_queue: Sender<ScanJob>,
ancestor_inodes: TreeSet<u64>, ancestor_inodes: TreeSet<u64>,
is_external: bool, is_external: bool,
@ -5155,7 +5156,7 @@ struct ScanJob {
struct UpdateIgnoreStatusJob { struct UpdateIgnoreStatusJob {
abs_path: Arc<Path>, abs_path: Arc<Path>,
ignore_stack: Arc<IgnoreStack>, ignore_stack: IgnoreStack,
ignore_queue: Sender<UpdateIgnoreStatusJob>, ignore_queue: Sender<UpdateIgnoreStatusJob>,
scan_queue: Sender<ScanJob>, scan_queue: Sender<ScanJob>,
} }