aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_vfs/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_vfs/src/lib.rs')
-rw-r--r--crates/ra_vfs/src/lib.rs59
1 files changed, 45 insertions, 14 deletions
diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs
index cdea18d73..5336822b3 100644
--- a/crates/ra_vfs/src/lib.rs
+++ b/crates/ra_vfs/src/lib.rs
@@ -14,26 +14,26 @@
14//! which are watched for changes. Typically, there will be a root for each 14//! which are watched for changes. Typically, there will be a root for each
15//! Cargo package. 15//! Cargo package.
16mod io; 16mod io;
17mod watcher;
17 18
18use std::{ 19use std::{
19 fmt,
20 mem,
21 thread,
22 cmp::Reverse, 20 cmp::Reverse,
23 path::{Path, PathBuf},
24 ffi::OsStr, 21 ffi::OsStr,
22 fmt, fs, mem,
23 path::{Path, PathBuf},
25 sync::Arc, 24 sync::Arc,
26 fs, 25 thread,
27}; 26};
28 27
29use rustc_hash::{FxHashMap, FxHashSet};
30use relative_path::RelativePathBuf;
31use crossbeam_channel::Receiver; 28use crossbeam_channel::Receiver;
32use walkdir::DirEntry; 29use ra_arena::{impl_arena_id, Arena, RawId};
30use relative_path::RelativePathBuf;
31use rustc_hash::{FxHashMap, FxHashSet};
33use thread_worker::WorkerHandle; 32use thread_worker::WorkerHandle;
34use ra_arena::{Arena, RawId, impl_arena_id}; 33use walkdir::DirEntry;
35 34
36pub use crate::io::TaskResult as VfsTask; 35pub use crate::io::TaskResult as VfsTask;
36pub use crate::watcher::{Watcher, WatcherChange};
37 37
38/// `RootFilter` is a predicate that checks if a file can belong to a root. If 38/// `RootFilter` is a predicate that checks if a file can belong to a root. If
39/// several filters match a file (nested dirs), the most nested one wins. 39/// several filters match a file (nested dirs), the most nested one wins.
@@ -85,6 +85,7 @@ pub struct Vfs {
85 pending_changes: Vec<VfsChange>, 85 pending_changes: Vec<VfsChange>,
86 worker: io::Worker, 86 worker: io::Worker,
87 worker_handle: WorkerHandle, 87 worker_handle: WorkerHandle,
88 watcher: Watcher,
88} 89}
89 90
90impl fmt::Debug for Vfs { 91impl fmt::Debug for Vfs {
@@ -97,12 +98,15 @@ impl Vfs {
97 pub fn new(mut roots: Vec<PathBuf>) -> (Vfs, Vec<VfsRoot>) { 98 pub fn new(mut roots: Vec<PathBuf>) -> (Vfs, Vec<VfsRoot>) {
98 let (worker, worker_handle) = io::start(); 99 let (worker, worker_handle) = io::start();
99 100
101 let watcher = Watcher::new().unwrap(); // TODO return Result?
102
100 let mut res = Vfs { 103 let mut res = Vfs {
101 roots: Arena::default(), 104 roots: Arena::default(),
102 files: Arena::default(), 105 files: Arena::default(),
103 root2files: FxHashMap::default(), 106 root2files: FxHashMap::default(),
104 worker, 107 worker,
105 worker_handle, 108 worker_handle,
109 watcher,
106 pending_changes: Vec::new(), 110 pending_changes: Vec::new(),
107 }; 111 };
108 112
@@ -129,6 +133,7 @@ impl Vfs {
129 filter: Box::new(filter), 133 filter: Box::new(filter),
130 }; 134 };
131 res.worker.inp.send(task).unwrap(); 135 res.worker.inp.send(task).unwrap();
136 res.watcher.watch(path).unwrap();
132 } 137 }
133 let roots = res.roots.iter().map(|(id, _)| id).collect(); 138 let roots = res.roots.iter().map(|(id, _)| id).collect();
134 (res, roots) 139 (res, roots)
@@ -183,6 +188,10 @@ impl Vfs {
183 &self.worker.out 188 &self.worker.out
184 } 189 }
185 190
191 pub fn change_receiver(&self) -> &Receiver<WatcherChange> {
192 &self.watcher.change_receiver()
193 }
194
186 pub fn handle_task(&mut self, task: io::TaskResult) { 195 pub fn handle_task(&mut self, task: io::TaskResult) {
187 let mut files = Vec::new(); 196 let mut files = Vec::new();
188 // While we were scanning the root in the backgound, a file might have 197 // While we were scanning the root in the backgound, a file might have
@@ -209,22 +218,41 @@ impl Vfs {
209 self.pending_changes.push(change); 218 self.pending_changes.push(change);
210 } 219 }
211 220
212 pub fn add_file_overlay(&mut self, path: &Path, text: String) -> Option<VfsFile> { 221 pub fn handle_change(&mut self, change: WatcherChange) {
222 match change {
223 WatcherChange::Create(path) => {
224 self.add_file_overlay(&path, None);
225 }
226 WatcherChange::Remove(path) => {
227 self.remove_file_overlay(&path);
228 }
229 WatcherChange::Rename(src, dst) => {
230 self.remove_file_overlay(&src);
231 self.add_file_overlay(&dst, None);
232 }
233 WatcherChange::Write(path) => {
234 self.change_file_overlay(&path, None);
235 }
236 }
237 }
238
239 pub fn add_file_overlay(&mut self, path: &Path, text: Option<String>) -> Option<VfsFile> {
213 let mut res = None; 240 let mut res = None;
214 if let Some((root, path, file)) = self.find_root(path) { 241 if let Some((root, rel_path, file)) = self.find_root(path) {
242 let text = text.unwrap_or_else(|| fs::read_to_string(&path).unwrap_or_default());
215 let text = Arc::new(text); 243 let text = Arc::new(text);
216 let change = if let Some(file) = file { 244 let change = if let Some(file) = file {
217 res = Some(file); 245 res = Some(file);
218 self.change_file(file, Arc::clone(&text)); 246 self.change_file(file, Arc::clone(&text));
219 VfsChange::ChangeFile { file, text } 247 VfsChange::ChangeFile { file, text }
220 } else { 248 } else {
221 let file = self.add_file(root, path.clone(), Arc::clone(&text)); 249 let file = self.add_file(root, rel_path.clone(), Arc::clone(&text));
222 res = Some(file); 250 res = Some(file);
223 VfsChange::AddFile { 251 VfsChange::AddFile {
224 file, 252 file,
225 text, 253 text,
226 root, 254 root,
227 path, 255 path: rel_path,
228 } 256 }
229 }; 257 };
230 self.pending_changes.push(change); 258 self.pending_changes.push(change);
@@ -232,8 +260,10 @@ impl Vfs {
232 res 260 res
233 } 261 }
234 262
235 pub fn change_file_overlay(&mut self, path: &Path, new_text: String) { 263 pub fn change_file_overlay(&mut self, path: &Path, new_text: Option<String>) {
236 if let Some((_root, _path, file)) = self.find_root(path) { 264 if let Some((_root, _path, file)) = self.find_root(path) {
265 let new_text =
266 new_text.unwrap_or_else(|| fs::read_to_string(&path).unwrap_or_default());
237 let file = file.expect("can't change a file which wasn't added"); 267 let file = file.expect("can't change a file which wasn't added");
238 let text = Arc::new(new_text); 268 let text = Arc::new(new_text);
239 self.change_file(file, Arc::clone(&text)); 269 self.change_file(file, Arc::clone(&text));
@@ -267,6 +297,7 @@ impl Vfs {
267 297
268 /// Sutdown the VFS and terminate the background watching thread. 298 /// Sutdown the VFS and terminate the background watching thread.
269 pub fn shutdown(self) -> thread::Result<()> { 299 pub fn shutdown(self) -> thread::Result<()> {
300 let _ = self.watcher.shutdown();
270 let _ = self.worker.shutdown(); 301 let _ = self.worker.shutdown();
271 self.worker_handle.shutdown() 302 self.worker_handle.shutdown()
272 } 303 }