aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_vfs/src/io.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_vfs/src/io.rs')
-rw-r--r--crates/ra_vfs/src/io.rs45
1 files changed, 26 insertions, 19 deletions
diff --git a/crates/ra_vfs/src/io.rs b/crates/ra_vfs/src/io.rs
index ff5ae3a19..dc0b84d5a 100644
--- a/crates/ra_vfs/src/io.rs
+++ b/crates/ra_vfs/src/io.rs
@@ -17,14 +17,28 @@ pub(crate) enum Task {
17 AddRoot { root: VfsRoot, config: Arc<RootConfig> }, 17 AddRoot { root: VfsRoot, config: Arc<RootConfig> },
18} 18}
19 19
20/// `TaskResult` transfers files read on the IO thread to the VFS on the main
21/// thread.
20#[derive(Debug)] 22#[derive(Debug)]
21pub enum TaskResult { 23pub enum TaskResult {
24 /// Emitted when we've recursively scanned a source root during the initial
25 /// load.
22 BulkLoadRoot { root: VfsRoot, files: Vec<(RelativePathBuf, String)> }, 26 BulkLoadRoot { root: VfsRoot, files: Vec<(RelativePathBuf, String)> },
23 AddSingleFile { root: VfsRoot, path: RelativePathBuf, text: String }, 27 /// Emitted when we've noticed that a single file has changed.
24 ChangeSingleFile { root: VfsRoot, path: RelativePathBuf, text: String }, 28 ///
25 RemoveSingleFile { root: VfsRoot, path: RelativePathBuf }, 29 /// Note that this by design does not distinguish between
30 /// create/delete/write events, and instead specifies the *current* state of
31 /// the file. The idea is to guarantee that in the quiescent state the sum
32 /// of all results equals to the current state of the file system, while
33 /// allowing to skip intermediate events in non-quiescent states.
34 SingleFile { root: VfsRoot, path: RelativePathBuf, text: Option<String> },
26} 35}
27 36
37/// The kind of raw notification we've received from the notify library.
38///
39/// Note that these are not necessary 100% precise (for example we might receive
40/// `Create` instead of `Write`, see #734), but we try do distinguish `Create`s
41/// to implement recursive watching of directories.
28#[derive(Debug)] 42#[derive(Debug)]
29enum ChangeKind { 43enum ChangeKind {
30 Create, 44 Create,
@@ -45,7 +59,7 @@ impl Worker {
45 // explained by the following concerns: 59 // explained by the following concerns:
46 // * we need to burn a thread translating from notify's mpsc to 60 // * we need to burn a thread translating from notify's mpsc to
47 // crossbeam_channel. 61 // crossbeam_channel.
48 // * we want to read all files from a single thread, to gurantee that 62 // * we want to read all files from a single thread, to guarantee that
49 // we always get fresher versions and never go back in time. 63 // we always get fresher versions and never go back in time.
50 // * we want to tear down everything neatly during shutdown. 64 // * we want to tear down everything neatly during shutdown.
51 let (worker, worker_handle) = thread_worker::spawn( 65 let (worker, worker_handle) = thread_worker::spawn(
@@ -63,7 +77,7 @@ impl Worker {
63 let mut watcher = notify::watcher(notify_sender, WATCHER_DELAY) 77 let mut watcher = notify::watcher(notify_sender, WATCHER_DELAY)
64 .map_err(|e| log::error!("failed to spawn notify {}", e)) 78 .map_err(|e| log::error!("failed to spawn notify {}", e))
65 .ok(); 79 .ok();
66 // Start a silly thread to tranform between two channels 80 // Start a silly thread to transform between two channels
67 let thread = thread::spawn(move || { 81 let thread = thread::spawn(move || {
68 notify_receiver 82 notify_receiver
69 .into_iter() 83 .into_iter()
@@ -98,7 +112,7 @@ impl Worker {
98 } 112 }
99 // Stopped the watcher 113 // Stopped the watcher
100 drop(watcher.take()); 114 drop(watcher.take());
101 // Drain pending events: we are not inrerested in them anyways! 115 // Drain pending events: we are not interested in them anyways!
102 watcher_receiver.into_iter().for_each(|_| ()); 116 watcher_receiver.into_iter().for_each(|_| ());
103 117
104 let res = thread.join(); 118 let res = thread.join();
@@ -199,23 +213,16 @@ fn handle_change(
199 } 213 }
200 paths 214 paths
201 .into_iter() 215 .into_iter()
202 .filter_map(|rel_path| { 216 .try_for_each(|rel_path| {
203 let abs_path = rel_path.to_path(&config.root); 217 let abs_path = rel_path.to_path(&config.root);
204 let text = read_to_string(&abs_path)?; 218 let text = read_to_string(&abs_path);
205 Some((rel_path, text)) 219 sender.send(TaskResult::SingleFile { root, path: rel_path, text })
206 })
207 .try_for_each(|(path, text)| {
208 sender.send(TaskResult::AddSingleFile { root, path, text })
209 }) 220 })
210 .unwrap() 221 .unwrap()
211 } 222 }
212 ChangeKind::Write => { 223 ChangeKind::Write | ChangeKind::Remove => {
213 if let Some(text) = read_to_string(&path) { 224 let text = read_to_string(&path);
214 sender.send(TaskResult::ChangeSingleFile { root, path: rel_path, text }).unwrap(); 225 sender.send(TaskResult::SingleFile { root, path: rel_path, text }).unwrap();
215 }
216 }
217 ChangeKind::Remove => {
218 sender.send(TaskResult::RemoveSingleFile { root, path: rel_path }).unwrap()
219 } 226 }
220 } 227 }
221} 228}