diff options
Diffstat (limited to 'crates/ra_vfs/src/lib.rs')
-rw-r--r-- | crates/ra_vfs/src/lib.rs | 92 |
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 | ||
27 | use crossbeam_channel::Receiver; | 27 | use crossbeam_channel::Receiver; |
28 | use ra_arena::{impl_arena_id, Arena, RawId, map::ArenaMap}; | ||
29 | use relative_path::{RelativePath, RelativePathBuf}; | 28 | use relative_path::{RelativePath, RelativePathBuf}; |
30 | use rustc_hash::{FxHashMap, FxHashSet}; | 29 | use rustc_hash::{FxHashMap, FxHashSet}; |
31 | 30 | ||
@@ -34,14 +33,23 @@ use crate::{ | |||
34 | roots::Roots, | 33 | roots::Roots, |
35 | }; | 34 | }; |
36 | 35 | ||
37 | pub use crate::{ | 36 | pub 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. | ||
43 | pub struct VfsTask(TaskResult); | ||
44 | |||
45 | impl 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)] |
43 | pub struct VfsFile(pub RawId); | 52 | pub struct VfsFile(pub u32); |
44 | impl_arena_id!(VfsFile); | ||
45 | 53 | ||
46 | struct VfsFileData { | 54 | struct VfsFileData { |
47 | root: VfsRoot, | 55 | root: VfsRoot, |
@@ -52,8 +60,8 @@ struct VfsFileData { | |||
52 | 60 | ||
53 | pub struct Vfs { | 61 | pub 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)] | ||
80 | pub 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 | |||
71 | impl Vfs { | 87 | impl 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 { |
275 | pub 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 | } |