1use ignore::gitignore::Gitignore;
2use std::{ffi::OsStr, path::Path, sync::Arc};
3
4pub enum IgnoreStack {
5 None,
6 Some {
7 abs_base_path: Arc<Path>,
8 ignore: Arc<Gitignore>,
9 parent: Arc<IgnoreStack>,
10 },
11 All,
12}
13
14impl IgnoreStack {
15 pub fn none() -> Arc<Self> {
16 Arc::new(Self::None)
17 }
18
19 pub fn all() -> Arc<Self> {
20 Arc::new(Self::All)
21 }
22
23 pub fn is_all(&self) -> bool {
24 matches!(self, IgnoreStack::All)
25 }
26
27 pub fn append(self: Arc<Self>, abs_base_path: Arc<Path>, ignore: Arc<Gitignore>) -> Arc<Self> {
28 match self.as_ref() {
29 IgnoreStack::All => self,
30 _ => Arc::new(Self::Some {
31 abs_base_path,
32 ignore,
33 parent: self,
34 }),
35 }
36 }
37
38 pub fn is_abs_path_ignored(&self, abs_path: &Path, is_dir: bool) -> bool {
39 if is_dir && abs_path.file_name() == Some(OsStr::new(".git")) {
40 return true;
41 }
42
43 match self {
44 Self::None => false,
45 Self::All => true,
46 Self::Some {
47 abs_base_path,
48 ignore,
49 parent: prev,
50 } => match ignore.matched(abs_path.strip_prefix(abs_base_path).unwrap(), is_dir) {
51 ignore::Match::None => prev.is_abs_path_ignored(abs_path, is_dir),
52 ignore::Match::Ignore(_) => true,
53 ignore::Match::Whitelist(_) => false,
54 },
55 }
56 }
57}