aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_vfs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_vfs')
-rw-r--r--crates/ra_vfs/Cargo.toml1
-rw-r--r--crates/ra_vfs/src/lib.rs2
-rw-r--r--crates/ra_vfs/src/watcher.rs37
-rw-r--r--crates/ra_vfs/tests/vfs.rs106
4 files changed, 94 insertions, 52 deletions
diff --git a/crates/ra_vfs/Cargo.toml b/crates/ra_vfs/Cargo.toml
index f7a972e91..b703cbd9f 100644
--- a/crates/ra_vfs/Cargo.toml
+++ b/crates/ra_vfs/Cargo.toml
@@ -18,3 +18,4 @@ ra_arena = { path = "../ra_arena" }
18 18
19[dev-dependencies] 19[dev-dependencies]
20tempfile = "3" 20tempfile = "3"
21flexi_logger = "0.10.0"
diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs
index 5336822b3..1ca94dcd6 100644
--- a/crates/ra_vfs/src/lib.rs
+++ b/crates/ra_vfs/src/lib.rs
@@ -98,7 +98,7 @@ impl Vfs {
98 pub fn new(mut roots: Vec<PathBuf>) -> (Vfs, Vec<VfsRoot>) { 98 pub fn new(mut roots: Vec<PathBuf>) -> (Vfs, Vec<VfsRoot>) {
99 let (worker, worker_handle) = io::start(); 99 let (worker, worker_handle) = io::start();
100 100
101 let watcher = Watcher::new().unwrap(); // TODO return Result? 101 let watcher = Watcher::start().unwrap(); // TODO return Result?
102 102
103 let mut res = Vfs { 103 let mut res = Vfs {
104 roots: Arena::default(), 104 roots: Arena::default(),
diff --git a/crates/ra_vfs/src/watcher.rs b/crates/ra_vfs/src/watcher.rs
index cc05f949e..1aac23616 100644
--- a/crates/ra_vfs/src/watcher.rs
+++ b/crates/ra_vfs/src/watcher.rs
@@ -39,7 +39,6 @@ impl WatcherChange {
39 DebouncedEvent::Remove(path) => Some(WatcherChange::Remove(path)), 39 DebouncedEvent::Remove(path) => Some(WatcherChange::Remove(path)),
40 DebouncedEvent::Rename(src, dst) => Some(WatcherChange::Rename(src, dst)), 40 DebouncedEvent::Rename(src, dst) => Some(WatcherChange::Rename(src, dst)),
41 DebouncedEvent::Error(err, path) => { 41 DebouncedEvent::Error(err, path) => {
42 // TODO
43 log::warn!("watch error {}, {:?}", err, path); 42 log::warn!("watch error {}, {:?}", err, path);
44 None 43 None
45 } 44 }
@@ -48,23 +47,17 @@ impl WatcherChange {
48} 47}
49 48
50impl Watcher { 49impl Watcher {
51 pub fn new() -> Result<Watcher, Box<std::error::Error>> { 50 pub fn start() -> Result<Watcher, Box<std::error::Error>> {
52 let (input_sender, input_receiver) = mpsc::channel(); 51 let (input_sender, input_receiver) = mpsc::channel();
53 let watcher = notify::watcher(input_sender, Duration::from_millis(250))?; 52 let watcher = notify::watcher(input_sender, Duration::from_millis(250))?;
54 let (output_sender, output_receiver) = crossbeam_channel::unbounded(); 53 let (output_sender, output_receiver) = crossbeam_channel::unbounded();
55 let thread = thread::spawn(move || loop { 54 let thread = thread::spawn(move || {
56 match input_receiver.recv() { 55 input_receiver
57 Ok(ev) => { 56 .into_iter()
58 // forward relevant events only 57 // forward relevant events only
59 if let Some(change) = WatcherChange::from_debounced_event(ev) { 58 .filter_map(WatcherChange::from_debounced_event)
60 output_sender.send(change).unwrap(); 59 .try_for_each(|change| output_sender.send(change))
61 } 60 .unwrap()
62 }
63 Err(err) => {
64 log::debug!("Watcher stopped ({})", err);
65 break;
66 }
67 }
68 }); 61 });
69 Ok(Watcher { 62 Ok(Watcher {
70 receiver: output_receiver, 63 receiver: output_receiver,
@@ -86,11 +79,13 @@ impl Watcher {
86 pub fn shutdown(mut self) -> thread::Result<()> { 79 pub fn shutdown(mut self) -> thread::Result<()> {
87 self.bomb.defuse(); 80 self.bomb.defuse();
88 drop(self.watcher); 81 drop(self.watcher);
89 let res = self.thread.join(); 82 // TODO this doesn't terminate for some reason
90 match &res { 83 // let res = self.thread.join();
91 Ok(()) => log::info!("... Watcher terminated with ok"), 84 // match &res {
92 Err(_) => log::error!("... Watcher terminated with err"), 85 // Ok(()) => log::info!("... Watcher terminated with ok"),
93 } 86 // Err(_) => log::error!("... Watcher terminated with err"),
94 res 87 // }
88 // res
89 Ok(())
95 } 90 }
96} 91}
diff --git a/crates/ra_vfs/tests/vfs.rs b/crates/ra_vfs/tests/vfs.rs
index f56fc4603..8634be9c4 100644
--- a/crates/ra_vfs/tests/vfs.rs
+++ b/crates/ra_vfs/tests/vfs.rs
@@ -1,14 +1,13 @@
1use std::{ 1use std::{collections::HashSet, fs};
2 fs,
3 collections::HashSet,
4};
5
6use tempfile::tempdir;
7 2
3use flexi_logger::Logger;
8use ra_vfs::{Vfs, VfsChange}; 4use ra_vfs::{Vfs, VfsChange};
5use tempfile::tempdir;
9 6
10#[test] 7#[test]
11fn test_vfs_works() -> std::io::Result<()> { 8fn test_vfs_works() -> std::io::Result<()> {
9 Logger::with_str("debug").start().unwrap();
10
12 let files = [ 11 let files = [
13 ("a/foo.rs", "hello"), 12 ("a/foo.rs", "hello"),
14 ("a/bar.rs", "world"), 13 ("a/bar.rs", "world"),
@@ -58,42 +57,89 @@ fn test_vfs_works() -> std::io::Result<()> {
58 assert_eq!(files, expected_files); 57 assert_eq!(files, expected_files);
59 } 58 }
60 59
61 vfs.add_file_overlay(&dir.path().join("a/b/baz.rs"), "quux".to_string()); 60 // on disk change
62 let change = vfs.commit_changes().pop().unwrap(); 61 fs::write(&dir.path().join("a/b/baz.rs"), "quux").unwrap();
63 match change { 62 let change = vfs.change_receiver().recv().unwrap();
64 VfsChange::ChangeFile { text, .. } => assert_eq!(&*text, "quux"), 63 vfs.handle_change(change);
65 _ => panic!("unexpected change"), 64 match vfs.commit_changes().as_slice() {
65 [VfsChange::ChangeFile { text, .. }] => assert_eq!(text.as_str(), "quux"),
66 _ => panic!("unexpected changes"),
66 } 67 }
67 68
68 vfs.change_file_overlay(&dir.path().join("a/b/baz.rs"), "m".to_string()); 69 // in memory change
69 let change = vfs.commit_changes().pop().unwrap(); 70 vfs.change_file_overlay(&dir.path().join("a/b/baz.rs"), Some("m".to_string()));
70 match change { 71 match vfs.commit_changes().as_slice() {
71 VfsChange::ChangeFile { text, .. } => assert_eq!(&*text, "m"), 72 [VfsChange::ChangeFile { text, .. }] => assert_eq!(text.as_str(), "m"),
72 _ => panic!("unexpected change"), 73 _ => panic!("unexpected changes"),
73 } 74 }
74 75
76 // in memory remove, restores data on disk
75 vfs.remove_file_overlay(&dir.path().join("a/b/baz.rs")); 77 vfs.remove_file_overlay(&dir.path().join("a/b/baz.rs"));
76 let change = vfs.commit_changes().pop().unwrap(); 78 match vfs.commit_changes().as_slice() {
77 match change { 79 [VfsChange::ChangeFile { text, .. }] => assert_eq!(text.as_str(), "quux"),
78 VfsChange::ChangeFile { text, .. } => assert_eq!(&*text, "nested hello"), 80 _ => panic!("unexpected changes"),
79 _ => panic!("unexpected change"),
80 } 81 }
81 82
82 vfs.add_file_overlay(&dir.path().join("a/b/spam.rs"), "spam".to_string()); 83 // in memory add
83 let change = vfs.commit_changes().pop().unwrap(); 84 vfs.add_file_overlay(&dir.path().join("a/b/spam.rs"), Some("spam".to_string()));
84 match change { 85 match vfs.commit_changes().as_slice() {
85 VfsChange::AddFile { text, path, .. } => { 86 [VfsChange::AddFile { text, path, .. }] => {
86 assert_eq!(&*text, "spam"); 87 assert_eq!(text.as_str(), "spam");
87 assert_eq!(path, "spam.rs"); 88 assert_eq!(path, "spam.rs");
88 } 89 }
89 _ => panic!("unexpected change"), 90 _ => panic!("unexpected changes"),
90 } 91 }
91 92
93 // in memory remove
92 vfs.remove_file_overlay(&dir.path().join("a/b/spam.rs")); 94 vfs.remove_file_overlay(&dir.path().join("a/b/spam.rs"));
93 let change = vfs.commit_changes().pop().unwrap(); 95 match vfs.commit_changes().as_slice() {
94 match change { 96 [VfsChange::RemoveFile { path, .. }] => assert_eq!(path, "spam.rs"),
95 VfsChange::RemoveFile { .. } => (), 97 _ => panic!("unexpected changes"),
96 _ => panic!("unexpected change"), 98 }
99
100 // on disk add
101 fs::write(&dir.path().join("a/new.rs"), "new hello").unwrap();
102 let change = vfs.change_receiver().recv().unwrap();
103 vfs.handle_change(change);
104 match vfs.commit_changes().as_slice() {
105 [VfsChange::AddFile { text, path, .. }] => {
106 assert_eq!(text.as_str(), "new hello");
107 assert_eq!(path, "new.rs");
108 }
109 _ => panic!("unexpected changes"),
110 }
111
112 // on disk rename
113 fs::rename(&dir.path().join("a/new.rs"), &dir.path().join("a/new1.rs")).unwrap();
114 let change = vfs.change_receiver().recv().unwrap();
115 vfs.handle_change(change);
116 match vfs.commit_changes().as_slice() {
117 [VfsChange::RemoveFile {
118 path: removed_path, ..
119 }, VfsChange::AddFile {
120 text,
121 path: added_path,
122 ..
123 }] => {
124 assert_eq!(removed_path, "new.rs");
125 assert_eq!(added_path, "new1.rs");
126 assert_eq!(text.as_str(), "new hello");
127 }
128 _ => panic!("unexpected changes"),
129 }
130
131 // on disk remove
132 fs::remove_file(&dir.path().join("a/new1.rs")).unwrap();
133 let change = vfs.change_receiver().recv().unwrap();
134 vfs.handle_change(change);
135 match vfs.commit_changes().as_slice() {
136 [VfsChange::RemoveFile { path, .. }] => assert_eq!(path, "new1.rs"),
137 _ => panic!("unexpected changes"),
138 }
139
140 match vfs.change_receiver().try_recv() {
141 Err(crossbeam_channel::TryRecvError::Empty) => (),
142 res => panic!("unexpected {:?}", res),
97 } 143 }
98 144
99 vfs.shutdown().unwrap(); 145 vfs.shutdown().unwrap();