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.rs92
1 files changed, 54 insertions, 38 deletions
diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs
index 7f555a3c0..808c138df 100644
--- a/crates/ra_vfs/src/lib.rs
+++ b/crates/ra_vfs/src/lib.rs
@@ -25,7 +25,6 @@ use std::{
25}; 25};
26 26
27use crossbeam_channel::Receiver; 27use crossbeam_channel::Receiver;
28use ra_arena::{impl_arena_id, Arena, RawId, map::ArenaMap};
29use relative_path::{RelativePath, RelativePathBuf}; 28use relative_path::{RelativePath, RelativePathBuf};
30use rustc_hash::{FxHashMap, FxHashSet}; 29use rustc_hash::{FxHashMap, FxHashSet};
31 30
@@ -34,14 +33,23 @@ use crate::{
34 roots::Roots, 33 roots::Roots,
35}; 34};
36 35
37pub use crate::{ 36pub use crate::roots::VfsRoot;
38 io::TaskResult as VfsTask, 37
39 roots::VfsRoot, 38/// Opaque wrapper around file-system event.
40}; 39///
40/// Calling code is expected to just pass `VfsTask` to `handle_task` method. It
41/// is exposed as a public API so that the caller can plug vfs events into the
42/// main event loop and be notified when changes happen.
43pub struct VfsTask(TaskResult);
44
45impl fmt::Debug for VfsTask {
46 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47 f.write_str("VfsTask { ... }")
48 }
49}
41 50
42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 51#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
43pub struct VfsFile(pub RawId); 52pub struct VfsFile(pub u32);
44impl_arena_id!(VfsFile);
45 53
46struct VfsFileData { 54struct VfsFileData {
47 root: VfsRoot, 55 root: VfsRoot,
@@ -52,8 +60,8 @@ struct VfsFileData {
52 60
53pub struct Vfs { 61pub struct Vfs {
54 roots: Arc<Roots>, 62 roots: Arc<Roots>,
55 files: Arena<VfsFile, VfsFileData>, 63 files: Vec<VfsFileData>,
56 root2files: ArenaMap<VfsRoot, FxHashSet<VfsFile>>, 64 root2files: FxHashMap<VfsRoot, FxHashSet<VfsFile>>,
57 pending_changes: Vec<VfsChange>, 65 pending_changes: Vec<VfsChange>,
58 worker: Worker, 66 worker: Worker,
59} 67}
@@ -68,18 +76,25 @@ impl fmt::Debug for Vfs {
68 } 76 }
69} 77}
70 78
79#[derive(Debug, Clone)]
80pub enum VfsChange {
81 AddRoot { root: VfsRoot, files: Vec<(VfsFile, RelativePathBuf, Arc<String>)> },
82 AddFile { root: VfsRoot, file: VfsFile, path: RelativePathBuf, text: Arc<String> },
83 RemoveFile { root: VfsRoot, file: VfsFile, path: RelativePathBuf },
84 ChangeFile { file: VfsFile, text: Arc<String> },
85}
86
71impl Vfs { 87impl Vfs {
72 pub fn new(roots: Vec<PathBuf>) -> (Vfs, Vec<VfsRoot>) { 88 pub fn new(roots: Vec<PathBuf>) -> (Vfs, Vec<VfsRoot>) {
73 let roots = Arc::new(Roots::new(roots)); 89 let roots = Arc::new(Roots::new(roots));
74 let worker = io::start(Arc::clone(&roots)); 90 let worker = io::start(Arc::clone(&roots));
75 let mut root2files = ArenaMap::default(); 91 let mut root2files = FxHashMap::default();
76 92
77 for root in roots.iter() { 93 for root in roots.iter() {
78 root2files.insert(root, Default::default()); 94 root2files.insert(root, Default::default());
79 worker.sender().send(io::Task::AddRoot { root }).unwrap(); 95 worker.sender.send(io::Task::AddRoot { root }).unwrap();
80 } 96 }
81 let res = 97 let res = Vfs { roots, files: Vec::new(), root2files, worker, pending_changes: Vec::new() };
82 Vfs { roots, files: Arena::default(), root2files, worker, pending_changes: Vec::new() };
83 let vfs_roots = res.roots.iter().collect(); 98 let vfs_roots = res.roots.iter().collect();
84 (res, vfs_roots) 99 (res, vfs_roots)
85 } 100 }
@@ -96,8 +111,8 @@ impl Vfs {
96 } 111 }
97 112
98 pub fn file2path(&self, file: VfsFile) -> PathBuf { 113 pub fn file2path(&self, file: VfsFile) -> PathBuf {
99 let rel_path = &self.files[file].path; 114 let rel_path = &self.file(file).path;
100 let root_path = &self.roots.path(self.files[file].root); 115 let root_path = &self.roots.path(self.file(file).root);
101 rel_path.to_path(root_path) 116 rel_path.to_path(root_path)
102 } 117 }
103 118
@@ -154,23 +169,23 @@ impl Vfs {
154 mem::replace(&mut self.pending_changes, Vec::new()) 169 mem::replace(&mut self.pending_changes, Vec::new())
155 } 170 }
156 171
157 pub fn task_receiver(&self) -> &Receiver<io::TaskResult> { 172 pub fn task_receiver(&self) -> &Receiver<VfsTask> {
158 self.worker.receiver() 173 &self.worker.receiver
159 } 174 }
160 175
161 pub fn handle_task(&mut self, task: io::TaskResult) { 176 pub fn handle_task(&mut self, task: VfsTask) {
162 match task { 177 match task.0 {
163 TaskResult::BulkLoadRoot { root, files } => { 178 TaskResult::BulkLoadRoot { root, files } => {
164 let mut cur_files = Vec::new(); 179 let mut cur_files = Vec::new();
165 // While we were scanning the root in the background, a file might have 180 // While we were scanning the root in the background, a file might have
166 // been open in the editor, so we need to account for that. 181 // been open in the editor, so we need to account for that.
167 let existing = self.root2files[root] 182 let existing = self.root2files[&root]
168 .iter() 183 .iter()
169 .map(|&file| (self.files[file].path.clone(), file)) 184 .map(|&file| (self.file(file).path.clone(), file))
170 .collect::<FxHashMap<_, _>>(); 185 .collect::<FxHashMap<_, _>>();
171 for (path, text) in files { 186 for (path, text) in files {
172 if let Some(&file) = existing.get(&path) { 187 if let Some(&file) = existing.get(&path) {
173 let text = Arc::clone(&self.files[file].text); 188 let text = Arc::clone(&self.file(file).text);
174 cur_files.push((file, path, text)); 189 cur_files.push((file, path, text));
175 continue; 190 continue;
176 } 191 }
@@ -184,7 +199,7 @@ impl Vfs {
184 } 199 }
185 TaskResult::SingleFile { root, path, text } => { 200 TaskResult::SingleFile { root, path, text } => {
186 let existing_file = self.find_file(root, &path); 201 let existing_file = self.find_file(root, &path);
187 if existing_file.map(|file| self.files[file].is_overlayed) == Some(true) { 202 if existing_file.map(|file| self.file(file).is_overlayed) == Some(true) {
188 return; 203 return;
189 } 204 }
190 match (existing_file, text) { 205 match (existing_file, text) {
@@ -240,23 +255,24 @@ impl Vfs {
240 is_overlayed: bool, 255 is_overlayed: bool,
241 ) -> VfsFile { 256 ) -> VfsFile {
242 let data = VfsFileData { root, path, text, is_overlayed }; 257 let data = VfsFileData { root, path, text, is_overlayed };
243 let file = self.files.alloc(data); 258 let file = VfsFile(self.files.len() as u32);
244 self.root2files.get_mut(root).unwrap().insert(file); 259 self.files.push(data);
260 self.root2files.get_mut(&root).unwrap().insert(file);
245 file 261 file
246 } 262 }
247 263
248 fn raw_change_file(&mut self, file: VfsFile, new_text: Arc<String>, is_overlayed: bool) { 264 fn raw_change_file(&mut self, file: VfsFile, new_text: Arc<String>, is_overlayed: bool) {
249 let mut file_data = &mut self.files[file]; 265 let mut file_data = &mut self.file_mut(file);
250 file_data.text = new_text; 266 file_data.text = new_text;
251 file_data.is_overlayed = is_overlayed; 267 file_data.is_overlayed = is_overlayed;
252 } 268 }
253 269
254 fn raw_remove_file(&mut self, file: VfsFile) { 270 fn raw_remove_file(&mut self, file: VfsFile) {
255 // FIXME: use arena with removal 271 // FIXME: use arena with removal
256 self.files[file].text = Default::default(); 272 self.file_mut(file).text = Default::default();
257 self.files[file].path = Default::default(); 273 self.file_mut(file).path = Default::default();
258 let root = self.files[file].root; 274 let root = self.file(file).root;
259 let removed = self.root2files.get_mut(root).unwrap().remove(&file); 275 let removed = self.root2files.get_mut(&root).unwrap().remove(&file);
260 assert!(removed); 276 assert!(removed);
261 } 277 }
262 278
@@ -267,14 +283,14 @@ impl Vfs {
267 } 283 }
268 284
269 fn find_file(&self, root: VfsRoot, path: &RelativePath) -> Option<VfsFile> { 285 fn find_file(&self, root: VfsRoot, path: &RelativePath) -> Option<VfsFile> {
270 self.root2files[root].iter().map(|&it| it).find(|&file| self.files[file].path == path) 286 self.root2files[&root].iter().map(|&it| it).find(|&file| self.file(file).path == path)
271 } 287 }
272}
273 288
274#[derive(Debug, Clone)] 289 fn file(&self, file: VfsFile) -> &VfsFileData {
275pub enum VfsChange { 290 &self.files[file.0 as usize]
276 AddRoot { root: VfsRoot, files: Vec<(VfsFile, RelativePathBuf, Arc<String>)> }, 291 }
277 AddFile { root: VfsRoot, file: VfsFile, path: RelativePathBuf, text: Arc<String> }, 292
278 RemoveFile { root: VfsRoot, file: VfsFile, path: RelativePathBuf }, 293 fn file_mut(&mut self, file: VfsFile) -> &mut VfsFileData {
279 ChangeFile { file: VfsFile, text: Arc<String> }, 294 &mut self.files[file.0 as usize]
295 }
280} 296}