diff options
Diffstat (limited to 'crates/ra_vfs')
-rw-r--r-- | crates/ra_vfs/src/io/mod.rs | 45 | ||||
-rw-r--r-- | crates/ra_vfs/src/io/watcher.rs | 16 | ||||
-rw-r--r-- | crates/ra_vfs/src/lib.rs | 17 |
3 files changed, 44 insertions, 34 deletions
diff --git a/crates/ra_vfs/src/io/mod.rs b/crates/ra_vfs/src/io/mod.rs index 6d5af7690..daac6c6f2 100644 --- a/crates/ra_vfs/src/io/mod.rs +++ b/crates/ra_vfs/src/io/mod.rs | |||
@@ -9,26 +9,27 @@ use crossbeam_channel::{Receiver, Sender}; | |||
9 | use parking_lot::Mutex; | 9 | use parking_lot::Mutex; |
10 | use relative_path::RelativePathBuf; | 10 | use relative_path::RelativePathBuf; |
11 | use thread_worker::WorkerHandle; | 11 | use thread_worker::WorkerHandle; |
12 | use walkdir::{DirEntry, WalkDir}; | 12 | use walkdir::WalkDir; |
13 | 13 | ||
14 | mod watcher; | 14 | mod watcher; |
15 | use watcher::Watcher; | 15 | use watcher::Watcher; |
16 | pub use watcher::WatcherChange; | 16 | pub use watcher::WatcherChange; |
17 | 17 | ||
18 | use crate::VfsRoot; | 18 | use crate::{RootFilter, VfsRoot}; |
19 | 19 | ||
20 | pub(crate) enum Task { | 20 | pub(crate) enum Task { |
21 | AddRoot { | 21 | AddRoot { |
22 | root: VfsRoot, | 22 | root: VfsRoot, |
23 | path: PathBuf, | 23 | path: PathBuf, |
24 | filter: Box<Fn(&DirEntry) -> bool + Send>, | 24 | root_filter: Arc<RootFilter>, |
25 | nested_roots: Vec<PathBuf>, | ||
25 | }, | 26 | }, |
26 | /// this variant should only be created by the watcher | 27 | /// this variant should only be created by the watcher |
27 | HandleChange(WatcherChange), | 28 | HandleChange(WatcherChange), |
28 | LoadChange(WatcherChange), | 29 | LoadChange(WatcherChange), |
29 | Watch { | 30 | Watch { |
30 | dir: PathBuf, | 31 | dir: PathBuf, |
31 | filter: Box<Fn(&DirEntry) -> bool + Send>, | 32 | root_filter: Arc<RootFilter>, |
32 | }, | 33 | }, |
33 | } | 34 | } |
34 | 35 | ||
@@ -109,7 +110,7 @@ impl Worker { | |||
109 | fn watch( | 110 | fn watch( |
110 | watcher: &Arc<Mutex<Option<Watcher>>>, | 111 | watcher: &Arc<Mutex<Option<Watcher>>>, |
111 | dir: &Path, | 112 | dir: &Path, |
112 | filter_entry: impl Fn(&DirEntry) -> bool, | 113 | filter_entry: &RootFilter, |
113 | emit_for_existing: bool, | 114 | emit_for_existing: bool, |
114 | ) { | 115 | ) { |
115 | let mut watcher = watcher.lock(); | 116 | let mut watcher = watcher.lock(); |
@@ -125,10 +126,19 @@ fn watch( | |||
125 | 126 | ||
126 | fn handle_task(task: Task, watcher: &Arc<Mutex<Option<Watcher>>>) -> TaskResult { | 127 | fn handle_task(task: Task, watcher: &Arc<Mutex<Option<Watcher>>>) -> TaskResult { |
127 | match task { | 128 | match task { |
128 | Task::AddRoot { root, path, filter } => { | 129 | Task::AddRoot { |
129 | watch(watcher, &path, &*filter, false); | 130 | root, |
131 | path, | ||
132 | root_filter, | ||
133 | nested_roots, | ||
134 | } => { | ||
135 | watch(watcher, &path, &*root_filter, false); | ||
130 | log::debug!("loading {} ...", path.as_path().display()); | 136 | log::debug!("loading {} ...", path.as_path().display()); |
131 | let files = load_root(path.as_path(), &*filter); | 137 | let files = load_root( |
138 | path.as_path(), | ||
139 | root_filter.as_ref(), | ||
140 | nested_roots.as_slice(), | ||
141 | ); | ||
132 | log::debug!("... loaded {}", path.as_path().display()); | 142 | log::debug!("... loaded {}", path.as_path().display()); |
133 | TaskResult::AddRoot(AddRootResult { root, files }) | 143 | TaskResult::AddRoot(AddRootResult { root, files }) |
134 | } | 144 | } |
@@ -143,16 +153,27 @@ fn handle_task(task: Task, watcher: &Arc<Mutex<Option<Watcher>>>) -> TaskResult | |||
143 | None => TaskResult::NoOp, | 153 | None => TaskResult::NoOp, |
144 | } | 154 | } |
145 | } | 155 | } |
146 | Task::Watch { dir, filter } => { | 156 | Task::Watch { dir, root_filter } => { |
147 | watch(watcher, &dir, &*filter, true); | 157 | watch(watcher, &dir, root_filter.as_ref(), true); |
148 | TaskResult::NoOp | 158 | TaskResult::NoOp |
149 | } | 159 | } |
150 | } | 160 | } |
151 | } | 161 | } |
152 | 162 | ||
153 | fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePathBuf, String)> { | 163 | fn load_root( |
164 | root: &Path, | ||
165 | root_filter: &RootFilter, | ||
166 | nested_roots: &[PathBuf], | ||
167 | ) -> Vec<(RelativePathBuf, String)> { | ||
154 | let mut res = Vec::new(); | 168 | let mut res = Vec::new(); |
155 | for entry in WalkDir::new(root).into_iter().filter_entry(filter) { | 169 | for entry in WalkDir::new(root).into_iter().filter_entry(|entry| { |
170 | if entry.file_type().is_dir() && nested_roots.iter().any(|it| it == entry.path()) { | ||
171 | // do not load files of a nested root | ||
172 | false | ||
173 | } else { | ||
174 | root_filter.can_contain(entry.path()).is_some() | ||
175 | } | ||
176 | }) { | ||
156 | let entry = match entry { | 177 | let entry = match entry { |
157 | Ok(entry) => entry, | 178 | Ok(entry) => entry, |
158 | Err(e) => { | 179 | Err(e) => { |
diff --git a/crates/ra_vfs/src/io/watcher.rs b/crates/ra_vfs/src/io/watcher.rs index e33298477..5e9bc8ff3 100644 --- a/crates/ra_vfs/src/io/watcher.rs +++ b/crates/ra_vfs/src/io/watcher.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use crate::io; | 1 | use crate::{io, RootFilter}; |
2 | use crossbeam_channel::Sender; | 2 | use crossbeam_channel::Sender; |
3 | use drop_bomb::DropBomb; | 3 | use drop_bomb::DropBomb; |
4 | use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher}; | 4 | use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher}; |
@@ -8,7 +8,7 @@ use std::{ | |||
8 | thread, | 8 | thread, |
9 | time::Duration, | 9 | time::Duration, |
10 | }; | 10 | }; |
11 | use walkdir::{DirEntry, WalkDir}; | 11 | use walkdir::WalkDir; |
12 | 12 | ||
13 | #[derive(Debug)] | 13 | #[derive(Debug)] |
14 | pub enum WatcherChange { | 14 | pub enum WatcherChange { |
@@ -83,13 +83,11 @@ impl Watcher { | |||
83 | }) | 83 | }) |
84 | } | 84 | } |
85 | 85 | ||
86 | pub fn watch_recursive( | 86 | pub fn watch_recursive(&mut self, dir: &Path, filter: &RootFilter, emit_for_contents: bool) { |
87 | &mut self, | 87 | for res in WalkDir::new(dir) |
88 | dir: &Path, | 88 | .into_iter() |
89 | filter_entry: impl Fn(&DirEntry) -> bool, | 89 | .filter_entry(|entry| filter.can_contain(entry.path()).is_some()) |
90 | emit_for_contents: bool, | 90 | { |
91 | ) { | ||
92 | for res in WalkDir::new(dir).into_iter().filter_entry(filter_entry) { | ||
93 | match res { | 91 | match res { |
94 | Ok(entry) => { | 92 | Ok(entry) => { |
95 | if entry.path().is_dir() { | 93 | if entry.path().is_dir() { |
diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs index 5db0d8646..1d0af6a09 100644 --- a/crates/ra_vfs/src/lib.rs +++ b/crates/ra_vfs/src/lib.rs | |||
@@ -28,7 +28,6 @@ use crossbeam_channel::Receiver; | |||
28 | use ra_arena::{impl_arena_id, Arena, RawId}; | 28 | use ra_arena::{impl_arena_id, Arena, RawId}; |
29 | use relative_path::RelativePathBuf; | 29 | use relative_path::RelativePathBuf; |
30 | use rustc_hash::{FxHashMap, FxHashSet}; | 30 | use rustc_hash::{FxHashMap, FxHashSet}; |
31 | use walkdir::DirEntry; | ||
32 | 31 | ||
33 | pub use crate::io::TaskResult as VfsTask; | 32 | pub use crate::io::TaskResult as VfsTask; |
34 | use io::{Task, TaskResult, WatcherChange, WatcherChangeData, Worker}; | 33 | use io::{Task, TaskResult, WatcherChange, WatcherChangeData, Worker}; |
@@ -128,23 +127,17 @@ impl Vfs { | |||
128 | let root = res.roots.alloc(root_filter.clone()); | 127 | let root = res.roots.alloc(root_filter.clone()); |
129 | res.root2files.insert(root, Default::default()); | 128 | res.root2files.insert(root, Default::default()); |
130 | 129 | ||
131 | let nested = roots[..i] | 130 | let nested_roots = roots[..i] |
132 | .iter() | 131 | .iter() |
133 | .filter(|it| it.starts_with(path)) | 132 | .filter(|it| it.starts_with(path)) |
134 | .map(|it| it.clone()) | 133 | .map(|it| it.clone()) |
135 | .collect::<Vec<_>>(); | 134 | .collect::<Vec<_>>(); |
136 | 135 | ||
137 | let filter = move |entry: &DirEntry| { | ||
138 | if entry.file_type().is_dir() && nested.iter().any(|it| it == entry.path()) { | ||
139 | false | ||
140 | } else { | ||
141 | root_filter.can_contain(entry.path()).is_some() | ||
142 | } | ||
143 | }; | ||
144 | let task = io::Task::AddRoot { | 136 | let task = io::Task::AddRoot { |
145 | root, | 137 | root, |
146 | path: path.clone(), | 138 | path: path.clone(), |
147 | filter: Box::new(filter), | 139 | root_filter, |
140 | nested_roots, | ||
148 | }; | 141 | }; |
149 | res.worker.sender().send(task).unwrap(); | 142 | res.worker.sender().send(task).unwrap(); |
150 | } | 143 | } |
@@ -232,13 +225,11 @@ impl Vfs { | |||
232 | WatcherChange::Create(path) if path.is_dir() => { | 225 | WatcherChange::Create(path) if path.is_dir() => { |
233 | if let Some((root, _path, _file)) = self.find_root(&path) { | 226 | if let Some((root, _path, _file)) = self.find_root(&path) { |
234 | let root_filter = self.roots[root].clone(); | 227 | let root_filter = self.roots[root].clone(); |
235 | let filter = | ||
236 | move |entry: &DirEntry| root_filter.can_contain(entry.path()).is_some(); | ||
237 | self.worker | 228 | self.worker |
238 | .sender() | 229 | .sender() |
239 | .send(Task::Watch { | 230 | .send(Task::Watch { |
240 | dir: path.to_path_buf(), | 231 | dir: path.to_path_buf(), |
241 | filter: Box::new(filter), | 232 | root_filter, |
242 | }) | 233 | }) |
243 | .unwrap() | 234 | .unwrap() |
244 | } | 235 | } |