diff options
author | Aleksey Kladov <[email protected]> | 2020-07-18 15:40:10 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-07-18 15:40:10 +0100 |
commit | 46ac9ff5e3cf070584d8167150655d091d47e3c2 (patch) | |
tree | ca33f4a791eb41439cee21d6b715b8f89fb80b1e /crates/vfs/src | |
parent | fd6717799c03c9171bb7ec0f50bce98d1dfb44bd (diff) |
Simplify exclusion logic
Diffstat (limited to 'crates/vfs/src')
-rw-r--r-- | crates/vfs/src/loader.rs | 82 |
1 files changed, 73 insertions, 9 deletions
diff --git a/crates/vfs/src/loader.rs b/crates/vfs/src/loader.rs index 6de2e5b3f..9c6e4b6a7 100644 --- a/crates/vfs/src/loader.rs +++ b/crates/vfs/src/loader.rs | |||
@@ -3,10 +3,25 @@ use std::fmt; | |||
3 | 3 | ||
4 | use paths::{AbsPath, AbsPathBuf}; | 4 | use paths::{AbsPath, AbsPathBuf}; |
5 | 5 | ||
6 | #[derive(Debug)] | 6 | #[derive(Debug, Clone)] |
7 | pub enum Entry { | 7 | pub enum Entry { |
8 | Files(Vec<AbsPathBuf>), | 8 | Files(Vec<AbsPathBuf>), |
9 | Directory { path: AbsPathBuf, include: Vec<String> }, | 9 | Directories(Directories), |
10 | } | ||
11 | |||
12 | /// Specifies a set of files on the file system. | ||
13 | /// | ||
14 | /// A file is included if: | ||
15 | /// * it has included extension | ||
16 | /// * it is under an `include` path | ||
17 | /// * it is not under `exclude` path | ||
18 | /// | ||
19 | /// If many include/exclude paths match, the longest one wins. | ||
20 | #[derive(Debug, Clone)] | ||
21 | pub struct Directories { | ||
22 | pub extensions: Vec<String>, | ||
23 | pub include: Vec<AbsPathBuf>, | ||
24 | pub exclude: Vec<AbsPathBuf>, | ||
10 | } | 25 | } |
11 | 26 | ||
12 | #[derive(Debug)] | 27 | #[derive(Debug)] |
@@ -33,21 +48,70 @@ pub trait Handle: fmt::Debug { | |||
33 | 48 | ||
34 | impl Entry { | 49 | impl Entry { |
35 | pub fn rs_files_recursively(base: AbsPathBuf) -> Entry { | 50 | pub fn rs_files_recursively(base: AbsPathBuf) -> Entry { |
36 | Entry::Directory { path: base, include: globs(&["*.rs", "!/.git/"]) } | 51 | Entry::Directories(dirs(base, &[".git"])) |
37 | } | 52 | } |
38 | pub fn local_cargo_package(base: AbsPathBuf) -> Entry { | 53 | pub fn local_cargo_package(base: AbsPathBuf) -> Entry { |
39 | Entry::Directory { path: base, include: globs(&["*.rs", "!/target/", "!/.git/"]) } | 54 | Entry::Directories(dirs(base, &[".git", "target"])) |
40 | } | 55 | } |
41 | pub fn cargo_package_dependency(base: AbsPathBuf) -> Entry { | 56 | pub fn cargo_package_dependency(base: AbsPathBuf) -> Entry { |
42 | Entry::Directory { | 57 | Entry::Directories(dirs(base, &[".git", "/tests", "/examples", "/benches"])) |
43 | path: base, | 58 | } |
44 | include: globs(&["*.rs", "!/tests/", "!/examples/", "!/benches/", "!/.git/"]), | 59 | |
60 | pub fn contains_file(&self, path: &AbsPath) -> bool { | ||
61 | match self { | ||
62 | Entry::Files(files) => files.iter().any(|it| it == path), | ||
63 | Entry::Directories(dirs) => dirs.contains_file(path), | ||
64 | } | ||
65 | } | ||
66 | pub fn contains_dir(&self, path: &AbsPath) -> bool { | ||
67 | match self { | ||
68 | Entry::Files(_) => false, | ||
69 | Entry::Directories(dirs) => dirs.contains_dir(path), | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | impl Directories { | ||
75 | pub fn contains_file(&self, path: &AbsPath) -> bool { | ||
76 | let ext = path.extension().unwrap_or_default(); | ||
77 | if self.extensions.iter().all(|it| it.as_str() != ext) { | ||
78 | return false; | ||
79 | } | ||
80 | self.includes_path(path) | ||
81 | } | ||
82 | pub fn contains_dir(&self, path: &AbsPath) -> bool { | ||
83 | self.includes_path(path) | ||
84 | } | ||
85 | fn includes_path(&self, path: &AbsPath) -> bool { | ||
86 | let mut include = None; | ||
87 | for incl in &self.include { | ||
88 | if is_prefix(incl, path) { | ||
89 | include = Some(match include { | ||
90 | Some(prev) if is_prefix(incl, prev) => prev, | ||
91 | _ => incl, | ||
92 | }) | ||
93 | } | ||
94 | } | ||
95 | let include = match include { | ||
96 | Some(it) => it, | ||
97 | None => return false, | ||
98 | }; | ||
99 | for excl in &self.exclude { | ||
100 | if is_prefix(excl, path) && is_prefix(include, excl) { | ||
101 | return false; | ||
102 | } | ||
103 | } | ||
104 | return true; | ||
105 | |||
106 | fn is_prefix(short: &AbsPath, long: &AbsPath) -> bool { | ||
107 | long.strip_prefix(short).is_some() | ||
45 | } | 108 | } |
46 | } | 109 | } |
47 | } | 110 | } |
48 | 111 | ||
49 | fn globs(globs: &[&str]) -> Vec<String> { | 112 | fn dirs(base: AbsPathBuf, exclude: &[&str]) -> Directories { |
50 | globs.iter().map(|it| it.to_string()).collect() | 113 | let exclude = exclude.iter().map(|it| base.join(it)).collect::<Vec<_>>(); |
114 | Directories { extensions: vec!["rs".to_string()], include: vec![base], exclude } | ||
51 | } | 115 | } |
52 | 116 | ||
53 | impl fmt::Debug for Message { | 117 | impl fmt::Debug for Message { |