WIP: Maintain an IgnoreStack while scanning

All ignore files associated with ancestors of the directory currently being scanned are included in the stack. This allows us to compute ignore status for each entry as we initially scan it. If we encounter an ignored directory, we replace the stack with an "ignore all" variant that simply ignores every descendant of the ignored directory.

This is incomplete. We still need to construct an ignore stack in an appropriate state when rescanning subtrees in response to events. It also doesn't deal with individual ignore files being added, removed, or changed. I think we could potentially use the ignore stack while reconstructing the tree for this purpose.
This commit is contained in:
Nathan Sobo
2021-04-24 23:59:03 -06:00
parent 9cd1d5e607
commit f770a70929
2 changed files with 275 additions and 164 deletions
+66
View File
@@ -0,0 +1,66 @@
use std::{path::Path, sync::Arc};
use ignore::gitignore::Gitignore;
pub enum IgnoreStack {
None,
Some {
base: Arc<Path>,
ignore: Arc<Gitignore>,
parent: Arc<IgnoreStack>,
},
All,
}
impl IgnoreStack {
pub fn none() -> Arc<Self> {
Arc::new(Self::None)
}
pub fn all() -> Arc<Self> {
Arc::new(Self::All)
}
pub fn append(self: Arc<Self>, base: Arc<Path>, ignore: Arc<Gitignore>) -> Arc<Self> {
log::info!("appending ignore {:?}", base);
match self.as_ref() {
IgnoreStack::All => self,
_ => Arc::new(Self::Some {
base,
ignore,
parent: self,
}),
}
}
pub fn is_path_ignored(&self, path: &Path, is_dir: bool) -> bool {
println!("is_path_ignored? {:?} {}", path, is_dir);
match self {
Self::None => {
println!("none case");
false
}
Self::All => {
println!("all case");
true
}
Self::Some {
base,
ignore,
parent: prev,
} => {
println!(
"some case {:?} {:?}",
base,
path.strip_prefix(base).unwrap()
);
match ignore.matched(path.strip_prefix(base).unwrap(), is_dir) {
ignore::Match::None => prev.is_path_ignored(path, is_dir),
ignore::Match::Ignore(_) => true,
ignore::Match::Whitelist(_) => false,
}
}
}
}
}