diff options
author | Bernardo <[email protected]> | 2019-01-12 17:17:52 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-01-26 08:46:16 +0000 |
commit | 76bf7498aa88c4de4517f4eb1218807fdfc7071b (patch) | |
tree | e95b92ce0f54df298d59eb96450bd6bd06ba2939 | |
parent | 6b86f038d61752bbf306ed5dd9def74be3b5dcc1 (diff) |
handle watched events filtering in `Vfs`add `is_overlayed`load changed files contents in `io`
-rw-r--r-- | Cargo.lock | 2 | ||||
-rw-r--r-- | crates/ra_vfs/src/io.rs | 74 | ||||
-rw-r--r-- | crates/ra_vfs/src/lib.rs | 165 | ||||
-rw-r--r-- | crates/ra_vfs/src/watcher.rs | 85 | ||||
-rw-r--r-- | crates/ra_vfs/tests/vfs.rs | 35 |
5 files changed, 218 insertions, 143 deletions
diff --git a/Cargo.lock b/Cargo.lock index a694c2d91..b8c840c68 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1009,7 +1009,7 @@ version = "0.1.0" | |||
1009 | dependencies = [ | 1009 | dependencies = [ |
1010 | "crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | 1010 | "crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", |
1011 | "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", | 1011 | "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", |
1012 | "flexi_logger 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", | 1012 | "flexi_logger 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", |
1013 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", | 1013 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", |
1014 | "notify 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)", | 1014 | "notify 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)", |
1015 | "ra_arena 0.1.0", | 1015 | "ra_arena 0.1.0", |
diff --git a/crates/ra_vfs/src/io.rs b/crates/ra_vfs/src/io.rs index 79dea5dc7..a0c87fb25 100644 --- a/crates/ra_vfs/src/io.rs +++ b/crates/ra_vfs/src/io.rs | |||
@@ -1,14 +1,13 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | fmt, | 2 | fmt, fs, |
3 | fs, | ||
4 | path::{Path, PathBuf}, | 3 | path::{Path, PathBuf}, |
5 | }; | 4 | }; |
6 | 5 | ||
7 | use walkdir::{DirEntry, WalkDir}; | ||
8 | use thread_worker::{WorkerHandle}; | ||
9 | use relative_path::RelativePathBuf; | 6 | use relative_path::RelativePathBuf; |
7 | use thread_worker::WorkerHandle; | ||
8 | use walkdir::{DirEntry, WalkDir}; | ||
10 | 9 | ||
11 | use crate::{VfsRoot, has_rs_extension}; | 10 | use crate::{has_rs_extension, watcher::WatcherChange, VfsRoot}; |
12 | 11 | ||
13 | pub(crate) enum Task { | 12 | pub(crate) enum Task { |
14 | AddRoot { | 13 | AddRoot { |
@@ -16,7 +15,7 @@ pub(crate) enum Task { | |||
16 | path: PathBuf, | 15 | path: PathBuf, |
17 | filter: Box<Fn(&DirEntry) -> bool + Send>, | 16 | filter: Box<Fn(&DirEntry) -> bool + Send>, |
18 | }, | 17 | }, |
19 | WatcherChange(crate::watcher::WatcherChange), | 18 | LoadChange(crate::watcher::WatcherChange), |
20 | } | 19 | } |
21 | 20 | ||
22 | #[derive(Debug)] | 21 | #[derive(Debug)] |
@@ -26,29 +25,16 @@ pub struct AddRootResult { | |||
26 | } | 25 | } |
27 | 26 | ||
28 | #[derive(Debug)] | 27 | #[derive(Debug)] |
29 | pub enum WatcherChangeResult { | 28 | pub enum WatcherChangeData { |
30 | Create { | 29 | Create { path: PathBuf, text: String }, |
31 | path: PathBuf, | 30 | Write { path: PathBuf, text: String }, |
32 | text: String, | 31 | Remove { path: PathBuf }, |
33 | }, | ||
34 | Write { | ||
35 | path: PathBuf, | ||
36 | text: String, | ||
37 | }, | ||
38 | Remove { | ||
39 | path: PathBuf, | ||
40 | }, | ||
41 | // can this be replaced and use Remove and Create instead? | ||
42 | Rename { | ||
43 | src: PathBuf, | ||
44 | dst: PathBuf, | ||
45 | text: String, | ||
46 | }, | ||
47 | } | 32 | } |
48 | 33 | ||
49 | pub enum TaskResult { | 34 | pub enum TaskResult { |
50 | AddRoot(AddRootResult), | 35 | AddRoot(AddRootResult), |
51 | WatcherChange(WatcherChangeResult), | 36 | HandleChange(WatcherChange), |
37 | LoadChange(Option<WatcherChangeData>), | ||
52 | } | 38 | } |
53 | 39 | ||
54 | impl fmt::Debug for TaskResult { | 40 | impl fmt::Debug for TaskResult { |
@@ -77,9 +63,10 @@ fn handle_task(task: Task) -> TaskResult { | |||
77 | log::debug!("... loaded {}", path.as_path().display()); | 63 | log::debug!("... loaded {}", path.as_path().display()); |
78 | TaskResult::AddRoot(AddRootResult { root, files }) | 64 | TaskResult::AddRoot(AddRootResult { root, files }) |
79 | } | 65 | } |
80 | Task::WatcherChange(change) => { | 66 | Task::LoadChange(change) => { |
81 | // TODO | 67 | log::debug!("loading {:?} ...", change); |
82 | unimplemented!() | 68 | let data = load_change(change); |
69 | TaskResult::LoadChange(data) | ||
83 | } | 70 | } |
84 | } | 71 | } |
85 | } | 72 | } |
@@ -113,3 +100,34 @@ fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePa | |||
113 | } | 100 | } |
114 | res | 101 | res |
115 | } | 102 | } |
103 | |||
104 | fn load_change(change: WatcherChange) -> Option<WatcherChangeData> { | ||
105 | let data = match change { | ||
106 | WatcherChange::Create(path) => { | ||
107 | let text = match fs::read_to_string(&path) { | ||
108 | Ok(text) => text, | ||
109 | Err(e) => { | ||
110 | log::warn!("watcher error: {}", e); | ||
111 | return None; | ||
112 | } | ||
113 | }; | ||
114 | WatcherChangeData::Create { path, text } | ||
115 | } | ||
116 | WatcherChange::Write(path) => { | ||
117 | let text = match fs::read_to_string(&path) { | ||
118 | Ok(text) => text, | ||
119 | Err(e) => { | ||
120 | log::warn!("watcher error: {}", e); | ||
121 | return None; | ||
122 | } | ||
123 | }; | ||
124 | WatcherChangeData::Write { path, text } | ||
125 | } | ||
126 | WatcherChange::Remove(path) => WatcherChangeData::Remove { path }, | ||
127 | WatcherChange::Rescan => { | ||
128 | // this should be handled by Vfs::handle_task | ||
129 | return None; | ||
130 | } | ||
131 | }; | ||
132 | Some(data) | ||
133 | } | ||
diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs index 889ed788d..2930f6b80 100644 --- a/crates/ra_vfs/src/lib.rs +++ b/crates/ra_vfs/src/lib.rs | |||
@@ -75,6 +75,7 @@ impl_arena_id!(VfsFile); | |||
75 | struct VfsFileData { | 75 | struct VfsFileData { |
76 | root: VfsRoot, | 76 | root: VfsRoot, |
77 | path: RelativePathBuf, | 77 | path: RelativePathBuf, |
78 | is_overlayed: bool, | ||
78 | text: Arc<String>, | 79 | text: Arc<String>, |
79 | } | 80 | } |
80 | 81 | ||
@@ -170,7 +171,7 @@ impl Vfs { | |||
170 | } else { | 171 | } else { |
171 | let text = fs::read_to_string(path).unwrap_or_default(); | 172 | let text = fs::read_to_string(path).unwrap_or_default(); |
172 | let text = Arc::new(text); | 173 | let text = Arc::new(text); |
173 | let file = self.add_file(root, rel_path.clone(), Arc::clone(&text)); | 174 | let file = self.add_file(root, rel_path.clone(), Arc::clone(&text), false); |
174 | let change = VfsChange::AddFile { | 175 | let change = VfsChange::AddFile { |
175 | file, | 176 | file, |
176 | text, | 177 | text, |
@@ -205,7 +206,7 @@ impl Vfs { | |||
205 | continue; | 206 | continue; |
206 | } | 207 | } |
207 | let text = Arc::new(text); | 208 | let text = Arc::new(text); |
208 | let file = self.add_file(task.root, path.clone(), Arc::clone(&text)); | 209 | let file = self.add_file(task.root, path.clone(), Arc::clone(&text), false); |
209 | files.push((file, path, text)); | 210 | files.push((file, path, text)); |
210 | } | 211 | } |
211 | 212 | ||
@@ -215,63 +216,132 @@ impl Vfs { | |||
215 | }; | 216 | }; |
216 | self.pending_changes.push(change); | 217 | self.pending_changes.push(change); |
217 | } | 218 | } |
218 | io::TaskResult::WatcherChange(change) => { | 219 | io::TaskResult::HandleChange(change) => match &change { |
219 | // TODO | 220 | watcher::WatcherChange::Create(path) |
220 | unimplemented!() | 221 | | watcher::WatcherChange::Remove(path) |
222 | | watcher::WatcherChange::Write(path) => { | ||
223 | if self.should_handle_change(&path) { | ||
224 | self.worker.inp.send(io::Task::LoadChange(change)).unwrap() | ||
225 | } | ||
226 | } | ||
227 | watcher::WatcherChange::Rescan => { | ||
228 | // TODO send Task::AddRoot? | ||
229 | } | ||
230 | }, | ||
231 | io::TaskResult::LoadChange(None) => {} | ||
232 | io::TaskResult::LoadChange(Some(change)) => match change { | ||
233 | io::WatcherChangeData::Create { path, text } | ||
234 | | io::WatcherChangeData::Write { path, text } => { | ||
235 | if let Some((root, path, file)) = self.find_root(&path) { | ||
236 | if let Some(file) = file { | ||
237 | self.do_change_file(file, text, false); | ||
238 | } else { | ||
239 | self.do_add_file(root, path, text, false); | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | io::WatcherChangeData::Remove { path } => { | ||
244 | if let Some((root, path, file)) = self.find_root(&path) { | ||
245 | if let Some(file) = file { | ||
246 | self.do_remove_file(root, path, file, false); | ||
247 | } | ||
248 | } | ||
249 | } | ||
250 | }, | ||
251 | } | ||
252 | } | ||
253 | |||
254 | fn should_handle_change(&self, path: &Path) -> bool { | ||
255 | if let Some((_root, _rel_path, file)) = self.find_root(&path) { | ||
256 | if let Some(file) = file { | ||
257 | if self.files[file].is_overlayed { | ||
258 | // file is overlayed | ||
259 | return false; | ||
260 | } | ||
221 | } | 261 | } |
262 | true | ||
263 | } else { | ||
264 | // file doesn't belong to any root | ||
265 | false | ||
222 | } | 266 | } |
223 | } | 267 | } |
224 | 268 | ||
269 | fn do_add_file( | ||
270 | &mut self, | ||
271 | root: VfsRoot, | ||
272 | path: RelativePathBuf, | ||
273 | text: String, | ||
274 | is_overlay: bool, | ||
275 | ) -> Option<VfsFile> { | ||
276 | let text = Arc::new(text); | ||
277 | let file = self.add_file(root, path.clone(), text.clone(), is_overlay); | ||
278 | self.pending_changes.push(VfsChange::AddFile { | ||
279 | file, | ||
280 | root, | ||
281 | path, | ||
282 | text, | ||
283 | }); | ||
284 | Some(file) | ||
285 | } | ||
286 | |||
287 | fn do_change_file(&mut self, file: VfsFile, text: String, is_overlay: bool) { | ||
288 | if !is_overlay && self.files[file].is_overlayed { | ||
289 | return; | ||
290 | } | ||
291 | let text = Arc::new(text); | ||
292 | self.change_file(file, text.clone(), is_overlay); | ||
293 | self.pending_changes | ||
294 | .push(VfsChange::ChangeFile { file, text }); | ||
295 | } | ||
296 | |||
297 | fn do_remove_file( | ||
298 | &mut self, | ||
299 | root: VfsRoot, | ||
300 | path: RelativePathBuf, | ||
301 | file: VfsFile, | ||
302 | is_overlay: bool, | ||
303 | ) { | ||
304 | if !is_overlay && self.files[file].is_overlayed { | ||
305 | return; | ||
306 | } | ||
307 | self.remove_file(file); | ||
308 | self.pending_changes | ||
309 | .push(VfsChange::RemoveFile { root, path, file }); | ||
310 | } | ||
311 | |||
225 | pub fn add_file_overlay(&mut self, path: &Path, text: String) -> Option<VfsFile> { | 312 | pub fn add_file_overlay(&mut self, path: &Path, text: String) -> Option<VfsFile> { |
226 | let mut res = None; | ||
227 | if let Some((root, rel_path, file)) = self.find_root(path) { | 313 | if let Some((root, rel_path, file)) = self.find_root(path) { |
228 | let text = Arc::new(text); | 314 | if let Some(file) = file { |
229 | let change = if let Some(file) = file { | 315 | self.do_change_file(file, text, true); |
230 | res = Some(file); | 316 | Some(file) |
231 | self.change_file(file, Arc::clone(&text)); | ||
232 | VfsChange::ChangeFile { file, text } | ||
233 | } else { | 317 | } else { |
234 | let file = self.add_file(root, rel_path.clone(), Arc::clone(&text)); | 318 | self.do_add_file(root, rel_path, text, true) |
235 | res = Some(file); | 319 | } |
236 | VfsChange::AddFile { | 320 | } else { |
237 | file, | 321 | None |
238 | text, | ||
239 | root, | ||
240 | path: rel_path, | ||
241 | } | ||
242 | }; | ||
243 | self.pending_changes.push(change); | ||
244 | } | 322 | } |
245 | res | ||
246 | } | 323 | } |
247 | 324 | ||
248 | pub fn change_file_overlay(&mut self, path: &Path, new_text: String) { | 325 | pub fn change_file_overlay(&mut self, path: &Path, new_text: String) { |
249 | if let Some((_root, _path, file)) = self.find_root(path) { | 326 | if let Some((_root, _path, file)) = self.find_root(path) { |
250 | let file = file.expect("can't change a file which wasn't added"); | 327 | let file = file.expect("can't change a file which wasn't added"); |
251 | let text = Arc::new(new_text); | 328 | self.do_change_file(file, new_text, true); |
252 | self.change_file(file, Arc::clone(&text)); | ||
253 | let change = VfsChange::ChangeFile { file, text }; | ||
254 | self.pending_changes.push(change); | ||
255 | } | 329 | } |
256 | } | 330 | } |
257 | 331 | ||
258 | pub fn remove_file_overlay(&mut self, path: &Path) -> Option<VfsFile> { | 332 | pub fn remove_file_overlay(&mut self, path: &Path) -> Option<VfsFile> { |
259 | let mut res = None; | ||
260 | if let Some((root, path, file)) = self.find_root(path) { | 333 | if let Some((root, path, file)) = self.find_root(path) { |
261 | let file = file.expect("can't remove a file which wasn't added"); | 334 | let file = file.expect("can't remove a file which wasn't added"); |
262 | res = Some(file); | ||
263 | let full_path = path.to_path(&self.roots[root].root); | 335 | let full_path = path.to_path(&self.roots[root].root); |
264 | let change = if let Ok(text) = fs::read_to_string(&full_path) { | 336 | if let Ok(text) = fs::read_to_string(&full_path) { |
265 | let text = Arc::new(text); | 337 | self.do_change_file(file, text, true); |
266 | self.change_file(file, Arc::clone(&text)); | ||
267 | VfsChange::ChangeFile { file, text } | ||
268 | } else { | 338 | } else { |
269 | self.remove_file(file); | 339 | self.do_remove_file(root, path, file, true); |
270 | VfsChange::RemoveFile { root, file, path } | 340 | } |
271 | }; | 341 | Some(file) |
272 | self.pending_changes.push(change); | 342 | } else { |
343 | None | ||
273 | } | 344 | } |
274 | res | ||
275 | } | 345 | } |
276 | 346 | ||
277 | pub fn commit_changes(&mut self) -> Vec<VfsChange> { | 347 | pub fn commit_changes(&mut self) -> Vec<VfsChange> { |
@@ -285,15 +355,28 @@ impl Vfs { | |||
285 | self.worker_handle.shutdown() | 355 | self.worker_handle.shutdown() |
286 | } | 356 | } |
287 | 357 | ||
288 | fn add_file(&mut self, root: VfsRoot, path: RelativePathBuf, text: Arc<String>) -> VfsFile { | 358 | fn add_file( |
289 | let data = VfsFileData { root, path, text }; | 359 | &mut self, |
360 | root: VfsRoot, | ||
361 | path: RelativePathBuf, | ||
362 | text: Arc<String>, | ||
363 | is_overlayed: bool, | ||
364 | ) -> VfsFile { | ||
365 | let data = VfsFileData { | ||
366 | root, | ||
367 | path, | ||
368 | text, | ||
369 | is_overlayed, | ||
370 | }; | ||
290 | let file = self.files.alloc(data); | 371 | let file = self.files.alloc(data); |
291 | self.root2files.get_mut(&root).unwrap().insert(file); | 372 | self.root2files.get_mut(&root).unwrap().insert(file); |
292 | file | 373 | file |
293 | } | 374 | } |
294 | 375 | ||
295 | fn change_file(&mut self, file: VfsFile, new_text: Arc<String>) { | 376 | fn change_file(&mut self, file: VfsFile, new_text: Arc<String>, is_overlayed: bool) { |
296 | self.files[file].text = new_text; | 377 | let mut file_data = &mut self.files[file]; |
378 | file_data.text = new_text; | ||
379 | file_data.is_overlayed = is_overlayed; | ||
297 | } | 380 | } |
298 | 381 | ||
299 | fn remove_file(&mut self, file: VfsFile) { | 382 | fn remove_file(&mut self, file: VfsFile) { |
diff --git a/crates/ra_vfs/src/watcher.rs b/crates/ra_vfs/src/watcher.rs index a6d0496c0..a5401869c 100644 --- a/crates/ra_vfs/src/watcher.rs +++ b/crates/ra_vfs/src/watcher.rs | |||
@@ -5,10 +5,10 @@ use std::{ | |||
5 | time::Duration, | 5 | time::Duration, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::io; | ||
8 | use crossbeam_channel::Sender; | 9 | use crossbeam_channel::Sender; |
9 | use drop_bomb::DropBomb; | 10 | use drop_bomb::DropBomb; |
10 | use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher}; | 11 | use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher}; |
11 | use crate::{has_rs_extension, io}; | ||
12 | 12 | ||
13 | pub struct Watcher { | 13 | pub struct Watcher { |
14 | watcher: RecommendedWatcher, | 14 | watcher: RecommendedWatcher, |
@@ -21,59 +21,41 @@ pub enum WatcherChange { | |||
21 | Create(PathBuf), | 21 | Create(PathBuf), |
22 | Write(PathBuf), | 22 | Write(PathBuf), |
23 | Remove(PathBuf), | 23 | Remove(PathBuf), |
24 | // can this be replaced and use Remove and Create instead? | 24 | Rescan, |
25 | Rename(PathBuf, PathBuf), | ||
26 | } | 25 | } |
27 | 26 | ||
28 | impl WatcherChange { | 27 | fn send_change_events( |
29 | fn try_from_debounced_event(ev: DebouncedEvent) -> Option<WatcherChange> { | 28 | ev: DebouncedEvent, |
30 | match ev { | 29 | sender: &Sender<io::Task>, |
31 | DebouncedEvent::NoticeWrite(_) | 30 | ) -> Result<(), Box<std::error::Error>> { |
32 | | DebouncedEvent::NoticeRemove(_) | 31 | match ev { |
33 | | DebouncedEvent::Chmod(_) => { | 32 | DebouncedEvent::NoticeWrite(_) |
34 | // ignore | 33 | | DebouncedEvent::NoticeRemove(_) |
35 | None | 34 | | DebouncedEvent::Chmod(_) => { |
36 | } | 35 | // ignore |
37 | DebouncedEvent::Rescan => { | 36 | } |
38 | // TODO should we rescan the root? | 37 | DebouncedEvent::Rescan => { |
39 | None | 38 | sender.send(io::Task::LoadChange(WatcherChange::Rescan))?; |
40 | } | 39 | } |
41 | DebouncedEvent::Create(path) => { | 40 | DebouncedEvent::Create(path) => { |
42 | if has_rs_extension(&path) { | 41 | sender.send(io::Task::LoadChange(WatcherChange::Create(path)))?; |
43 | Some(WatcherChange::Create(path)) | 42 | } |
44 | } else { | 43 | DebouncedEvent::Write(path) => { |
45 | None | 44 | sender.send(io::Task::LoadChange(WatcherChange::Write(path)))?; |
46 | } | 45 | } |
47 | } | 46 | DebouncedEvent::Remove(path) => { |
48 | DebouncedEvent::Write(path) => { | 47 | sender.send(io::Task::LoadChange(WatcherChange::Remove(path)))?; |
49 | if has_rs_extension(&path) { | 48 | } |
50 | Some(WatcherChange::Write(path)) | 49 | DebouncedEvent::Rename(src, dst) => { |
51 | } else { | 50 | sender.send(io::Task::LoadChange(WatcherChange::Remove(src)))?; |
52 | None | 51 | sender.send(io::Task::LoadChange(WatcherChange::Create(dst)))?; |
53 | } | 52 | } |
54 | } | 53 | DebouncedEvent::Error(err, path) => { |
55 | DebouncedEvent::Remove(path) => { | 54 | // TODO should we reload the file contents? |
56 | if has_rs_extension(&path) { | 55 | log::warn!("watcher error {}, {:?}", err, path); |
57 | Some(WatcherChange::Remove(path)) | ||
58 | } else { | ||
59 | None | ||
60 | } | ||
61 | } | ||
62 | DebouncedEvent::Rename(src, dst) => { | ||
63 | match (has_rs_extension(&src), has_rs_extension(&dst)) { | ||
64 | (true, true) => Some(WatcherChange::Rename(src, dst)), | ||
65 | (true, false) => Some(WatcherChange::Remove(src)), | ||
66 | (false, true) => Some(WatcherChange::Create(dst)), | ||
67 | (false, false) => None, | ||
68 | } | ||
69 | } | ||
70 | DebouncedEvent::Error(err, path) => { | ||
71 | // TODO should we reload the file contents? | ||
72 | log::warn!("watch error {}, {:?}", err, path); | ||
73 | None | ||
74 | } | ||
75 | } | 56 | } |
76 | } | 57 | } |
58 | Ok(()) | ||
77 | } | 59 | } |
78 | 60 | ||
79 | impl Watcher { | 61 | impl Watcher { |
@@ -86,8 +68,7 @@ impl Watcher { | |||
86 | input_receiver | 68 | input_receiver |
87 | .into_iter() | 69 | .into_iter() |
88 | // forward relevant events only | 70 | // forward relevant events only |
89 | .filter_map(WatcherChange::try_from_debounced_event) | 71 | .try_for_each(|change| send_change_events(change, &output_sender)) |
90 | .try_for_each(|change| output_sender.send(io::Task::WatcherChange(change))) | ||
91 | .unwrap() | 72 | .unwrap() |
92 | }); | 73 | }); |
93 | Ok(Watcher { | 74 | Ok(Watcher { |
diff --git a/crates/ra_vfs/tests/vfs.rs b/crates/ra_vfs/tests/vfs.rs index 21d5633b1..9cde2bed7 100644 --- a/crates/ra_vfs/tests/vfs.rs +++ b/crates/ra_vfs/tests/vfs.rs | |||
@@ -4,6 +4,13 @@ use flexi_logger::Logger; | |||
4 | use ra_vfs::{Vfs, VfsChange}; | 4 | use ra_vfs::{Vfs, VfsChange}; |
5 | use tempfile::tempdir; | 5 | use tempfile::tempdir; |
6 | 6 | ||
7 | fn process_tasks(vfs: &mut Vfs, num_tasks: u32) { | ||
8 | for _ in 0..num_tasks { | ||
9 | let task = vfs.task_receiver().recv().unwrap(); | ||
10 | vfs.handle_task(task); | ||
11 | } | ||
12 | } | ||
13 | |||
7 | #[test] | 14 | #[test] |
8 | fn test_vfs_works() -> std::io::Result<()> { | 15 | fn test_vfs_works() -> std::io::Result<()> { |
9 | Logger::with_str("debug").start().unwrap(); | 16 | Logger::with_str("debug").start().unwrap(); |
@@ -25,10 +32,7 @@ fn test_vfs_works() -> std::io::Result<()> { | |||
25 | let b_root = dir.path().join("a/b"); | 32 | let b_root = dir.path().join("a/b"); |
26 | 33 | ||
27 | let (mut vfs, _) = Vfs::new(vec![a_root, b_root]); | 34 | let (mut vfs, _) = Vfs::new(vec![a_root, b_root]); |
28 | for _ in 0..2 { | 35 | process_tasks(&mut vfs, 2); |
29 | let task = vfs.task_receiver().recv().unwrap(); | ||
30 | vfs.handle_task(task); | ||
31 | } | ||
32 | { | 36 | { |
33 | let files = vfs | 37 | let files = vfs |
34 | .commit_changes() | 38 | .commit_changes() |
@@ -57,30 +61,26 @@ fn test_vfs_works() -> std::io::Result<()> { | |||
57 | assert_eq!(files, expected_files); | 61 | assert_eq!(files, expected_files); |
58 | } | 62 | } |
59 | 63 | ||
60 | // on disk change | ||
61 | fs::write(&dir.path().join("a/b/baz.rs"), "quux").unwrap(); | 64 | fs::write(&dir.path().join("a/b/baz.rs"), "quux").unwrap(); |
62 | let task = vfs.task_receiver().recv().unwrap(); | 65 | process_tasks(&mut vfs, 1); |
63 | vfs.handle_task(task); | ||
64 | match vfs.commit_changes().as_slice() { | 66 | match vfs.commit_changes().as_slice() { |
65 | [VfsChange::ChangeFile { text, .. }] => assert_eq!(text.as_str(), "quux"), | 67 | [VfsChange::ChangeFile { text, .. }] => assert_eq!(text.as_str(), "quux"), |
66 | _ => panic!("unexpected changes"), | 68 | _ => panic!("unexpected changes"), |
67 | } | 69 | } |
68 | 70 | ||
69 | // in memory change | ||
70 | vfs.change_file_overlay(&dir.path().join("a/b/baz.rs"), "m".to_string()); | 71 | vfs.change_file_overlay(&dir.path().join("a/b/baz.rs"), "m".to_string()); |
71 | match vfs.commit_changes().as_slice() { | 72 | match vfs.commit_changes().as_slice() { |
72 | [VfsChange::ChangeFile { text, .. }] => assert_eq!(text.as_str(), "m"), | 73 | [VfsChange::ChangeFile { text, .. }] => assert_eq!(text.as_str(), "m"), |
73 | _ => panic!("unexpected changes"), | 74 | _ => panic!("unexpected changes"), |
74 | } | 75 | } |
75 | 76 | ||
76 | // in memory remove, restores data on disk | 77 | // removing overlay restores data on disk |
77 | vfs.remove_file_overlay(&dir.path().join("a/b/baz.rs")); | 78 | vfs.remove_file_overlay(&dir.path().join("a/b/baz.rs")); |
78 | match vfs.commit_changes().as_slice() { | 79 | match vfs.commit_changes().as_slice() { |
79 | [VfsChange::ChangeFile { text, .. }] => assert_eq!(text.as_str(), "quux"), | 80 | [VfsChange::ChangeFile { text, .. }] => assert_eq!(text.as_str(), "quux"), |
80 | _ => panic!("unexpected changes"), | 81 | _ => panic!("unexpected changes"), |
81 | } | 82 | } |
82 | 83 | ||
83 | // in memory add | ||
84 | vfs.add_file_overlay(&dir.path().join("a/b/spam.rs"), "spam".to_string()); | 84 | vfs.add_file_overlay(&dir.path().join("a/b/spam.rs"), "spam".to_string()); |
85 | match vfs.commit_changes().as_slice() { | 85 | match vfs.commit_changes().as_slice() { |
86 | [VfsChange::AddFile { text, path, .. }] => { | 86 | [VfsChange::AddFile { text, path, .. }] => { |
@@ -90,17 +90,14 @@ fn test_vfs_works() -> std::io::Result<()> { | |||
90 | _ => panic!("unexpected changes"), | 90 | _ => panic!("unexpected changes"), |
91 | } | 91 | } |
92 | 92 | ||
93 | // in memory remove | ||
94 | vfs.remove_file_overlay(&dir.path().join("a/b/spam.rs")); | 93 | vfs.remove_file_overlay(&dir.path().join("a/b/spam.rs")); |
95 | match vfs.commit_changes().as_slice() { | 94 | match vfs.commit_changes().as_slice() { |
96 | [VfsChange::RemoveFile { path, .. }] => assert_eq!(path, "spam.rs"), | 95 | [VfsChange::RemoveFile { path, .. }] => assert_eq!(path, "spam.rs"), |
97 | _ => panic!("unexpected changes"), | 96 | _ => panic!("unexpected changes"), |
98 | } | 97 | } |
99 | 98 | ||
100 | // on disk add | ||
101 | fs::write(&dir.path().join("a/new.rs"), "new hello").unwrap(); | 99 | fs::write(&dir.path().join("a/new.rs"), "new hello").unwrap(); |
102 | let task = vfs.task_receiver().recv().unwrap(); | 100 | process_tasks(&mut vfs, 1); |
103 | vfs.handle_task(task); | ||
104 | match vfs.commit_changes().as_slice() { | 101 | match vfs.commit_changes().as_slice() { |
105 | [VfsChange::AddFile { text, path, .. }] => { | 102 | [VfsChange::AddFile { text, path, .. }] => { |
106 | assert_eq!(text.as_str(), "new hello"); | 103 | assert_eq!(text.as_str(), "new hello"); |
@@ -109,10 +106,8 @@ fn test_vfs_works() -> std::io::Result<()> { | |||
109 | _ => panic!("unexpected changes"), | 106 | _ => panic!("unexpected changes"), |
110 | } | 107 | } |
111 | 108 | ||
112 | // on disk rename | ||
113 | fs::rename(&dir.path().join("a/new.rs"), &dir.path().join("a/new1.rs")).unwrap(); | 109 | fs::rename(&dir.path().join("a/new.rs"), &dir.path().join("a/new1.rs")).unwrap(); |
114 | let task = vfs.task_receiver().recv().unwrap(); | 110 | process_tasks(&mut vfs, 2); |
115 | vfs.handle_task(task); | ||
116 | match vfs.commit_changes().as_slice() { | 111 | match vfs.commit_changes().as_slice() { |
117 | [VfsChange::RemoveFile { | 112 | [VfsChange::RemoveFile { |
118 | path: removed_path, .. | 113 | path: removed_path, .. |
@@ -125,13 +120,11 @@ fn test_vfs_works() -> std::io::Result<()> { | |||
125 | assert_eq!(added_path, "new1.rs"); | 120 | assert_eq!(added_path, "new1.rs"); |
126 | assert_eq!(text.as_str(), "new hello"); | 121 | assert_eq!(text.as_str(), "new hello"); |
127 | } | 122 | } |
128 | _ => panic!("unexpected changes"), | 123 | xs => panic!("unexpected changes {:?}", xs), |
129 | } | 124 | } |
130 | 125 | ||
131 | // on disk remove | ||
132 | fs::remove_file(&dir.path().join("a/new1.rs")).unwrap(); | 126 | fs::remove_file(&dir.path().join("a/new1.rs")).unwrap(); |
133 | let task = vfs.task_receiver().recv().unwrap(); | 127 | process_tasks(&mut vfs, 1); |
134 | vfs.handle_task(task); | ||
135 | match vfs.commit_changes().as_slice() { | 128 | match vfs.commit_changes().as_slice() { |
136 | [VfsChange::RemoveFile { path, .. }] => assert_eq!(path, "new1.rs"), | 129 | [VfsChange::RemoveFile { path, .. }] => assert_eq!(path, "new1.rs"), |
137 | _ => panic!("unexpected changes"), | 130 | _ => panic!("unexpected changes"), |