]> git.lizzy.rs Git - rust.git/blob - crates/rust-analyzer/src/vfs_glob.rs
91b33f94e8681d3664ffa05621695bf6d8de1625
[rust.git] / crates / rust-analyzer / src / vfs_glob.rs
1 //! Exclusion rules for vfs.
2 //!
3 //! By default, we include only `.rs` files, and skip some know offenders like
4 //! `/target` or `/node_modules` altogether.
5 //!
6 //! It's also possible to add custom exclusion globs.
7
8 use globset::{GlobSet, GlobSetBuilder};
9 use ra_vfs::{Filter, RelativePath};
10
11 pub use globset::{Glob, GlobBuilder};
12
13 const ALWAYS_IGNORED: &[&str] = &["target/**", "**/node_modules/**", "**/.git/**"];
14 const IGNORED_FOR_NON_MEMBERS: &[&str] = &["examples/**", "tests/**", "benches/**"];
15
16 pub struct RustPackageFilterBuilder {
17     is_member: bool,
18     exclude: GlobSetBuilder,
19 }
20
21 impl Default for RustPackageFilterBuilder {
22     fn default() -> RustPackageFilterBuilder {
23         RustPackageFilterBuilder { is_member: false, exclude: GlobSetBuilder::new() }
24     }
25 }
26
27 impl RustPackageFilterBuilder {
28     pub fn set_member(mut self, is_member: bool) -> RustPackageFilterBuilder {
29         self.is_member = is_member;
30         self
31     }
32     pub fn exclude(mut self, glob: Glob) -> RustPackageFilterBuilder {
33         self.exclude.add(glob);
34         self
35     }
36     pub fn into_vfs_filter(self) -> Box<dyn Filter> {
37         let RustPackageFilterBuilder { is_member, mut exclude } = self;
38         for &glob in ALWAYS_IGNORED {
39             exclude.add(Glob::new(glob).unwrap());
40         }
41         if !is_member {
42             for &glob in IGNORED_FOR_NON_MEMBERS {
43                 exclude.add(Glob::new(glob).unwrap());
44             }
45         }
46         Box::new(RustPackageFilter { exclude: exclude.build().unwrap() })
47     }
48 }
49
50 struct RustPackageFilter {
51     exclude: GlobSet,
52 }
53
54 impl Filter for RustPackageFilter {
55     fn include_dir(&self, dir_path: &RelativePath) -> bool {
56         !self.exclude.is_match(dir_path.as_str())
57     }
58
59     fn include_file(&self, file_path: &RelativePath) -> bool {
60         file_path.extension() == Some("rs")
61     }
62 }
63
64 #[test]
65 fn test_globs() {
66     let filter = RustPackageFilterBuilder::default().set_member(true).into_vfs_filter();
67
68     assert!(filter.include_dir(RelativePath::new("src/tests")));
69     assert!(filter.include_dir(RelativePath::new("src/target")));
70     assert!(filter.include_dir(RelativePath::new("tests")));
71     assert!(filter.include_dir(RelativePath::new("benches")));
72
73     assert!(!filter.include_dir(RelativePath::new("target")));
74     assert!(!filter.include_dir(RelativePath::new("src/foo/.git")));
75     assert!(!filter.include_dir(RelativePath::new("foo/node_modules")));
76
77     let filter = RustPackageFilterBuilder::default().set_member(false).into_vfs_filter();
78
79     assert!(filter.include_dir(RelativePath::new("src/tests")));
80     assert!(filter.include_dir(RelativePath::new("src/target")));
81
82     assert!(!filter.include_dir(RelativePath::new("target")));
83     assert!(!filter.include_dir(RelativePath::new("src/foo/.git")));
84     assert!(!filter.include_dir(RelativePath::new("foo/node_modules")));
85     assert!(!filter.include_dir(RelativePath::new("tests")));
86     assert!(!filter.include_dir(RelativePath::new("benches")));
87
88     let filter = RustPackageFilterBuilder::default()
89         .set_member(true)
90         .exclude(Glob::new("src/llvm-project/**").unwrap())
91         .into_vfs_filter();
92
93     assert!(!filter.include_dir(RelativePath::new("src/llvm-project/clang")));
94 }