aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_batch/Cargo.toml1
-rw-r--r--crates/ra_batch/src/lib.rs20
-rw-r--r--crates/ra_batch/src/vfs_filter.rs54
-rw-r--r--crates/ra_lsp_server/Cargo.toml1
-rw-r--r--crates/ra_lsp_server/src/config.rs (renamed from crates/ra_lsp_server/src/init.rs)15
-rw-r--r--crates/ra_lsp_server/src/lib.rs6
-rw-r--r--crates/ra_lsp_server/src/main.rs4
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs18
-rw-r--r--crates/ra_lsp_server/src/vfs_filter.rs54
-rw-r--r--crates/ra_lsp_server/src/world.rs22
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/support.rs4
-rw-r--r--crates/ra_project_model/Cargo.toml1
-rw-r--r--crates/ra_project_model/src/lib.rs23
-rw-r--r--crates/ra_vfs_glob/Cargo.toml9
-rw-r--r--crates/ra_vfs_glob/src/lib.rs94
15 files changed, 165 insertions, 161 deletions
diff --git a/crates/ra_batch/Cargo.toml b/crates/ra_batch/Cargo.toml
index 0ee94c445..8e23826a4 100644
--- a/crates/ra_batch/Cargo.toml
+++ b/crates/ra_batch/Cargo.toml
@@ -9,6 +9,7 @@ log = "0.4.5"
9rustc-hash = "1.0" 9rustc-hash = "1.0"
10 10
11ra_vfs = "0.2.0" 11ra_vfs = "0.2.0"
12ra_vfs_glob = { path = "../ra_vfs_glob" }
12ra_db = { path = "../ra_db" } 13ra_db = { path = "../ra_db" }
13ra_ide_api = { path = "../ra_ide_api" } 14ra_ide_api = { path = "../ra_ide_api" }
14ra_hir = { path = "../ra_hir" } 15ra_hir = { path = "../ra_hir" }
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs
index c01574fbc..0db751465 100644
--- a/crates/ra_batch/src/lib.rs
+++ b/crates/ra_batch/src/lib.rs
@@ -1,5 +1,3 @@
1mod vfs_filter;
2
3use std::{collections::HashSet, error::Error, path::Path}; 1use std::{collections::HashSet, error::Error, path::Path};
4 2
5use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
@@ -7,8 +5,8 @@ use rustc_hash::FxHashMap;
7use ra_db::{CrateGraph, FileId, SourceRootId}; 5use ra_db::{CrateGraph, FileId, SourceRootId};
8use ra_ide_api::{AnalysisChange, AnalysisHost}; 6use ra_ide_api::{AnalysisChange, AnalysisHost};
9use ra_project_model::{PackageRoot, ProjectWorkspace}; 7use ra_project_model::{PackageRoot, ProjectWorkspace};
10use ra_vfs::{Vfs, VfsChange}; 8use ra_vfs::{RootEntry, Vfs, VfsChange};
11use vfs_filter::IncludeRustFiles; 9use ra_vfs_glob::RustPackageFilterBuilder;
12 10
13type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>; 11type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;
14 12
@@ -23,7 +21,19 @@ pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId,
23 let root = std::env::current_dir()?.join(root); 21 let root = std::env::current_dir()?.join(root);
24 let ws = ProjectWorkspace::discover(root.as_ref())?; 22 let ws = ProjectWorkspace::discover(root.as_ref())?;
25 let project_roots = ws.to_roots(); 23 let project_roots = ws.to_roots();
26 let (mut vfs, roots) = Vfs::new(IncludeRustFiles::from_roots(project_roots.clone()).collect()); 24 let (mut vfs, roots) = Vfs::new(
25 project_roots
26 .iter()
27 .map(|pkg_root| {
28 RootEntry::new(
29 pkg_root.path().clone(),
30 RustPackageFilterBuilder::default()
31 .set_member(pkg_root.is_member())
32 .into_vfs_filter(),
33 )
34 })
35 .collect(),
36 );
27 let crate_graph = ws.to_crate_graph(&mut |path: &Path| { 37 let crate_graph = ws.to_crate_graph(&mut |path: &Path| {
28 let vfs_file = vfs.load(path); 38 let vfs_file = vfs.load(path);
29 log::debug!("vfs file {:?} -> {:?}", path, vfs_file); 39 log::debug!("vfs file {:?} -> {:?}", path, vfs_file);
diff --git a/crates/ra_batch/src/vfs_filter.rs b/crates/ra_batch/src/vfs_filter.rs
deleted file mode 100644
index 63bf77704..000000000
--- a/crates/ra_batch/src/vfs_filter.rs
+++ /dev/null
@@ -1,54 +0,0 @@
1use ra_project_model::PackageRoot;
2use ra_vfs::{Filter, RelativePath, RootEntry};
3use std::path::PathBuf;
4
5/// `IncludeRustFiles` is used to convert
6/// from `PackageRoot` to `RootEntry` for VFS
7pub struct IncludeRustFiles {
8 root: PackageRoot,
9}
10
11impl IncludeRustFiles {
12 pub fn from_roots<R>(roots: R) -> impl Iterator<Item = RootEntry>
13 where
14 R: IntoIterator<Item = PackageRoot>,
15 {
16 roots.into_iter().map(IncludeRustFiles::from_root)
17 }
18
19 pub fn from_root(root: PackageRoot) -> RootEntry {
20 IncludeRustFiles::from(root).into()
21 }
22
23 #[allow(unused)]
24 pub fn external(path: PathBuf) -> RootEntry {
25 IncludeRustFiles::from_root(PackageRoot::new(path, false))
26 }
27
28 pub fn member(path: PathBuf) -> RootEntry {
29 IncludeRustFiles::from_root(PackageRoot::new(path, true))
30 }
31}
32
33impl Filter for IncludeRustFiles {
34 fn include_dir(&self, dir_path: &RelativePath) -> bool {
35 self.root.include_dir(dir_path)
36 }
37
38 fn include_file(&self, file_path: &RelativePath) -> bool {
39 self.root.include_file(file_path)
40 }
41}
42
43impl From<PackageRoot> for IncludeRustFiles {
44 fn from(v: PackageRoot) -> IncludeRustFiles {
45 IncludeRustFiles { root: v }
46 }
47}
48
49impl From<IncludeRustFiles> for RootEntry {
50 fn from(v: IncludeRustFiles) -> RootEntry {
51 let path = v.root.path().clone();
52 RootEntry::new(path, Box::new(v))
53 }
54}
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index cec360667..c282d6db8 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -25,6 +25,7 @@ ra_ide_api = { path = "../ra_ide_api" }
25gen_lsp_server = { path = "../gen_lsp_server" } 25gen_lsp_server = { path = "../gen_lsp_server" }
26ra_project_model = { path = "../ra_project_model" } 26ra_project_model = { path = "../ra_project_model" }
27ra_prof = { path = "../ra_prof" } 27ra_prof = { path = "../ra_prof" }
28ra_vfs_glob = { path = "../ra_vfs_glob" }
28 29
29[dev-dependencies] 30[dev-dependencies]
30tempfile = "3" 31tempfile = "3"
diff --git a/crates/ra_lsp_server/src/init.rs b/crates/ra_lsp_server/src/config.rs
index b894b449d..6dcdc695a 100644
--- a/crates/ra_lsp_server/src/init.rs
+++ b/crates/ra_lsp_server/src/config.rs
@@ -1,9 +1,9 @@
1use serde::{Deserialize, Deserializer}; 1use serde::{Deserialize, Deserializer};
2 2
3/// Client provided initialization options 3/// Client provided initialization options
4#[derive(Deserialize, Clone, Copy, Debug, PartialEq, Eq)] 4#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
5#[serde(rename_all = "camelCase", default)] 5#[serde(rename_all = "camelCase", default)]
6pub struct InitializationOptions { 6pub struct ServerConfig {
7 /// Whether the client supports our custom highlighting publishing decorations. 7 /// Whether the client supports our custom highlighting publishing decorations.
8 /// This is different to the highlightingOn setting, which is whether the user 8 /// This is different to the highlightingOn setting, which is whether the user
9 /// wants our custom highlighting to be used. 9 /// wants our custom highlighting to be used.
@@ -18,14 +18,17 @@ pub struct InitializationOptions {
18 #[serde(deserialize_with = "nullable_bool_true")] 18 #[serde(deserialize_with = "nullable_bool_true")]
19 pub show_workspace_loaded: bool, 19 pub show_workspace_loaded: bool,
20 20
21 pub exclude_globs: Vec<String>,
22
21 pub lru_capacity: Option<usize>, 23 pub lru_capacity: Option<usize>,
22} 24}
23 25
24impl Default for InitializationOptions { 26impl Default for ServerConfig {
25 fn default() -> InitializationOptions { 27 fn default() -> ServerConfig {
26 InitializationOptions { 28 ServerConfig {
27 publish_decorations: false, 29 publish_decorations: false,
28 show_workspace_loaded: true, 30 show_workspace_loaded: true,
31 exclude_globs: Vec::new(),
29 lru_capacity: None, 32 lru_capacity: None,
30 } 33 }
31 } 34 }
@@ -56,7 +59,7 @@ mod test {
56 #[test] 59 #[test]
57 fn deserialize_init_options_defaults() { 60 fn deserialize_init_options_defaults() {
58 // check that null == default for both fields 61 // check that null == default for both fields
59 let default = InitializationOptions::default(); 62 let default = ServerConfig::default();
60 assert_eq!(default, serde_json::from_str(r#"{}"#).unwrap()); 63 assert_eq!(default, serde_json::from_str(r#"{}"#).unwrap());
61 assert_eq!( 64 assert_eq!(
62 default, 65 default,
diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs
index 56a263aa5..795f86383 100644
--- a/crates/ra_lsp_server/src/lib.rs
+++ b/crates/ra_lsp_server/src/lib.rs
@@ -4,13 +4,11 @@ mod conv;
4mod main_loop; 4mod main_loop;
5mod markdown; 5mod markdown;
6mod project_model; 6mod project_model;
7mod vfs_filter;
8pub mod req; 7pub mod req;
9pub mod init; 8pub mod config;
10mod world; 9mod world;
11 10
12pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; 11pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
13pub use crate::{ 12pub use crate::{
14 caps::server_capabilities, init::InitializationOptions, main_loop::main_loop, 13 caps::server_capabilities, config::ServerConfig, main_loop::main_loop, main_loop::LspError,
15 main_loop::LspError,
16}; 14};
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs
index c1f8243be..1a2ab1bc2 100644
--- a/crates/ra_lsp_server/src/main.rs
+++ b/crates/ra_lsp_server/src/main.rs
@@ -2,7 +2,7 @@ use flexi_logger::{Duplicate, Logger};
2use gen_lsp_server::{run_server, stdio_transport}; 2use gen_lsp_server::{run_server, stdio_transport};
3use serde::Deserialize; 3use serde::Deserialize;
4 4
5use ra_lsp_server::{InitializationOptions, Result}; 5use ra_lsp_server::{Result, ServerConfig};
6use ra_prof; 6use ra_prof;
7 7
8fn main() -> Result<()> { 8fn main() -> Result<()> {
@@ -48,7 +48,7 @@ fn main_inner() -> Result<()> {
48 48
49 let opts = params 49 let opts = params
50 .initialization_options 50 .initialization_options
51 .and_then(|v| InitializationOptions::deserialize(v).ok()) 51 .and_then(|v| ServerConfig::deserialize(v).ok())
52 .unwrap_or_default(); 52 .unwrap_or_default();
53 53
54 ra_lsp_server::main_loop(workspace_roots, params.capabilities, opts, r, s) 54 ra_lsp_server::main_loop(workspace_roots, params.capabilities, opts, r, s)
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 9a38d43d2..9d540a87e 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -23,7 +23,7 @@ use crate::{
23 project_model::workspace_loader, 23 project_model::workspace_loader,
24 req, 24 req,
25 world::{Options, WorldSnapshot, WorldState}, 25 world::{Options, WorldSnapshot, WorldState},
26 InitializationOptions, Result, 26 Result, ServerConfig,
27}; 27};
28 28
29const THREADPOOL_SIZE: usize = 8; 29const THREADPOOL_SIZE: usize = 8;
@@ -52,10 +52,11 @@ impl Error for LspError {}
52pub fn main_loop( 52pub fn main_loop(
53 ws_roots: Vec<PathBuf>, 53 ws_roots: Vec<PathBuf>,
54 client_caps: ClientCapabilities, 54 client_caps: ClientCapabilities,
55 options: InitializationOptions, 55 config: ServerConfig,
56 msg_receiver: &Receiver<RawMessage>, 56 msg_receiver: &Receiver<RawMessage>,
57 msg_sender: &Sender<RawMessage>, 57 msg_sender: &Sender<RawMessage>,
58) -> Result<()> { 58) -> Result<()> {
59 log::debug!("server_config: {:?}", config);
59 // FIXME: support dynamic workspace loading. 60 // FIXME: support dynamic workspace loading.
60 let workspaces = { 61 let workspaces = {
61 let ws_worker = workspace_loader(); 62 let ws_worker = workspace_loader();
@@ -77,14 +78,19 @@ pub fn main_loop(
77 } 78 }
78 loaded_workspaces 79 loaded_workspaces
79 }; 80 };
80 81 let globs = config
82 .exclude_globs
83 .iter()
84 .map(|glob| ra_vfs_glob::Glob::new(glob))
85 .collect::<std::result::Result<Vec<_>, _>>()?;
81 let mut state = WorldState::new( 86 let mut state = WorldState::new(
82 ws_roots, 87 ws_roots,
83 workspaces, 88 workspaces,
84 options.lru_capacity, 89 config.lru_capacity,
90 &globs,
85 Options { 91 Options {
86 publish_decorations: options.publish_decorations, 92 publish_decorations: config.publish_decorations,
87 show_workspace_loaded: options.show_workspace_loaded, 93 show_workspace_loaded: config.show_workspace_loaded,
88 supports_location_link: client_caps 94 supports_location_link: client_caps
89 .text_document 95 .text_document
90 .and_then(|it| it.definition) 96 .and_then(|it| it.definition)
diff --git a/crates/ra_lsp_server/src/vfs_filter.rs b/crates/ra_lsp_server/src/vfs_filter.rs
deleted file mode 100644
index abdc8dbad..000000000
--- a/crates/ra_lsp_server/src/vfs_filter.rs
+++ /dev/null
@@ -1,54 +0,0 @@
1use ra_project_model::PackageRoot;
2use ra_vfs::{Filter, RelativePath, RootEntry};
3use std::path::PathBuf;
4
5/// `IncludeRustFiles` is used to convert
6/// from `PackageRoot` to `RootEntry` for VFS
7pub struct IncludeRustFiles {
8 root: PackageRoot,
9}
10
11impl IncludeRustFiles {
12 pub fn from_roots<R>(roots: R) -> impl Iterator<Item = RootEntry>
13 where
14 R: IntoIterator<Item = PackageRoot>,
15 {
16 roots.into_iter().map(IncludeRustFiles::from_root)
17 }
18
19 pub fn from_root(root: PackageRoot) -> RootEntry {
20 IncludeRustFiles::from(root).into()
21 }
22
23 #[allow(unused)]
24 pub fn external(path: PathBuf) -> RootEntry {
25 IncludeRustFiles::from_root(PackageRoot::new(path, false))
26 }
27
28 pub fn member(path: PathBuf) -> RootEntry {
29 IncludeRustFiles::from_root(PackageRoot::new(path, true))
30 }
31}
32
33impl Filter for IncludeRustFiles {
34 fn include_dir(&self, dir_path: &RelativePath) -> bool {
35 self.root.include_dir(dir_path)
36 }
37
38 fn include_file(&self, file_path: &RelativePath) -> bool {
39 self.root.include_file(file_path)
40 }
41}
42
43impl std::convert::From<PackageRoot> for IncludeRustFiles {
44 fn from(v: PackageRoot) -> IncludeRustFiles {
45 IncludeRustFiles { root: v }
46 }
47}
48
49impl std::convert::From<IncludeRustFiles> for RootEntry {
50 fn from(v: IncludeRustFiles) -> RootEntry {
51 let path = v.root.path().clone();
52 RootEntry::new(path, Box::new(v))
53 }
54}
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index b57cdf925..9990ef62e 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -9,13 +9,13 @@ use parking_lot::RwLock;
9use ra_ide_api::{ 9use ra_ide_api::{
10 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, 10 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId,
11}; 11};
12use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot}; 12use ra_vfs::{RootEntry, Vfs, VfsChange, VfsFile, VfsRoot};
13use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
13use relative_path::RelativePathBuf; 14use relative_path::RelativePathBuf;
14 15
15use crate::{ 16use crate::{
16 main_loop::pending_requests::{CompletedRequest, LatestRequests}, 17 main_loop::pending_requests::{CompletedRequest, LatestRequests},
17 project_model::ProjectWorkspace, 18 project_model::ProjectWorkspace,
18 vfs_filter::IncludeRustFiles,
19 LspError, Result, 19 LspError, Result,
20}; 20};
21 21
@@ -56,14 +56,28 @@ impl WorldState {
56 folder_roots: Vec<PathBuf>, 56 folder_roots: Vec<PathBuf>,
57 workspaces: Vec<ProjectWorkspace>, 57 workspaces: Vec<ProjectWorkspace>,
58 lru_capacity: Option<usize>, 58 lru_capacity: Option<usize>,
59 exclude_globs: &[Glob],
59 options: Options, 60 options: Options,
60 ) -> WorldState { 61 ) -> WorldState {
61 let mut change = AnalysisChange::new(); 62 let mut change = AnalysisChange::new();
62 63
63 let mut roots = Vec::new(); 64 let mut roots = Vec::new();
64 roots.extend(folder_roots.iter().cloned().map(IncludeRustFiles::member)); 65 roots.extend(folder_roots.iter().map(|path| {
66 let mut filter = RustPackageFilterBuilder::default().set_member(true);
67 for glob in exclude_globs.iter() {
68 filter = filter.exclude(glob.clone());
69 }
70 RootEntry::new(path.clone(), filter.into_vfs_filter())
71 }));
65 for ws in workspaces.iter() { 72 for ws in workspaces.iter() {
66 roots.extend(IncludeRustFiles::from_roots(ws.to_roots())); 73 roots.extend(ws.to_roots().into_iter().map(|pkg_root| {
74 let mut filter =
75 RustPackageFilterBuilder::default().set_member(pkg_root.is_member());
76 for glob in exclude_globs.iter() {
77 filter = filter.exclude(glob.clone());
78 }
79 RootEntry::new(pkg_root.path().clone(), filter.into_vfs_filter())
80 }));
67 } 81 }
68 82
69 let (mut vfs, vfs_roots) = Vfs::new(roots); 83 let (mut vfs, vfs_roots) = Vfs::new(roots);
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs
index 5dddbbe17..ba8ee8b06 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/support.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs
@@ -22,7 +22,7 @@ use tempfile::TempDir;
22use test_utils::{find_mismatch, parse_fixture}; 22use test_utils::{find_mismatch, parse_fixture};
23use thread_worker::Worker; 23use thread_worker::Worker;
24 24
25use ra_lsp_server::{main_loop, req, InitializationOptions}; 25use ra_lsp_server::{main_loop, req, ServerConfig};
26 26
27pub struct Project<'a> { 27pub struct Project<'a> {
28 fixture: &'a str, 28 fixture: &'a str,
@@ -107,7 +107,7 @@ impl Server {
107 window: None, 107 window: None,
108 experimental: None, 108 experimental: None,
109 }, 109 },
110 InitializationOptions::default(), 110 ServerConfig::default(),
111 &msg_receiver, 111 &msg_receiver,
112 &msg_sender, 112 &msg_sender,
113 ) 113 )
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml
index 3545d23c9..4fd6c75ef 100644
--- a/crates/ra_project_model/Cargo.toml
+++ b/crates/ra_project_model/Cargo.toml
@@ -7,7 +7,6 @@ authors = ["rust-analyzer developers"]
7[dependencies] 7[dependencies]
8log = "0.4.5" 8log = "0.4.5"
9rustc-hash = "1.0" 9rustc-hash = "1.0"
10relative-path = "0.4.0"
11 10
12cargo_metadata = "0.8.0" 11cargo_metadata = "0.8.0"
13 12
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index c7167046b..55b94b911 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -10,7 +10,6 @@ use std::{
10}; 10};
11 11
12use ra_db::{CrateGraph, Edition, FileId}; 12use ra_db::{CrateGraph, Edition, FileId};
13use relative_path::RelativePath;
14use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
15use serde_json::from_reader; 14use serde_json::from_reader;
16 15
@@ -54,28 +53,6 @@ impl PackageRoot {
54 pub fn is_member(&self) -> bool { 53 pub fn is_member(&self) -> bool {
55 self.is_member 54 self.is_member
56 } 55 }
57
58 pub fn include_dir(&self, dir_path: &RelativePath) -> bool {
59 const COMMON_IGNORED_DIRS: &[&str] = &["node_modules", "target", ".git"];
60 const EXTERNAL_IGNORED_DIRS: &[&str] = &["examples", "tests", "benches"];
61
62 let is_ignored = if self.is_member {
63 dir_path.components().any(|c| COMMON_IGNORED_DIRS.contains(&c.as_str()))
64 } else {
65 dir_path.components().any(|c| {
66 let path = c.as_str();
67 COMMON_IGNORED_DIRS.contains(&path) || EXTERNAL_IGNORED_DIRS.contains(&path)
68 })
69 };
70
71 let hidden = dir_path.components().any(|c| c.as_str().starts_with('.'));
72
73 !is_ignored && !hidden
74 }
75
76 pub fn include_file(&self, file_path: &RelativePath) -> bool {
77 file_path.extension() == Some("rs")
78 }
79} 56}
80 57
81impl ProjectWorkspace { 58impl ProjectWorkspace {
diff --git a/crates/ra_vfs_glob/Cargo.toml b/crates/ra_vfs_glob/Cargo.toml
new file mode 100644
index 000000000..0390d7da1
--- /dev/null
+++ b/crates/ra_vfs_glob/Cargo.toml
@@ -0,0 +1,9 @@
1[package]
2edition = "2018"
3name = "ra_vfs_glob"
4version = "0.1.0"
5authors = ["rust-analyzer developers"]
6
7[dependencies]
8ra_vfs = "0.2.0"
9globset = "0.4.4"
diff --git a/crates/ra_vfs_glob/src/lib.rs b/crates/ra_vfs_glob/src/lib.rs
new file mode 100644
index 000000000..12401d75a
--- /dev/null
+++ b/crates/ra_vfs_glob/src/lib.rs
@@ -0,0 +1,94 @@
1//! `ra_vfs_glob` crate implements 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
8use globset::{GlobSet, GlobSetBuilder};
9use ra_vfs::{Filter, RelativePath};
10
11pub use globset::{Glob, GlobBuilder};
12
13const ALWAYS_IGNORED: &[&str] = &["target/**", "**/node_modules/**", "**/.git/**"];
14const IGNORED_FOR_NON_MEMBERS: &[&str] = &["examples/**", "tests/**", "benches/**"];
15
16pub struct RustPackageFilterBuilder {
17 is_member: bool,
18 exclude: GlobSetBuilder,
19}
20
21impl Default for RustPackageFilterBuilder {
22 fn default() -> RustPackageFilterBuilder {
23 RustPackageFilterBuilder { is_member: false, exclude: GlobSetBuilder::new() }
24 }
25}
26
27impl 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
50struct RustPackageFilter {
51 exclude: GlobSet,
52}
53
54impl 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]
65fn 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}