]> git.lizzy.rs Git - rust.git/blob - crates/ra_vfs/src/lib.rs
vfs crate scaffold
[rust.git] / crates / ra_vfs / src / lib.rs
1 //! VFS stands for Virtual File System.
2 //!
3 //! When doing analysis, we don't want to do any IO, we want to keep all source
4 //! code in memory. However, the actual source code is stored on disk, so you
5 //! need to get it into the memory in the first place somehow. VFS is the
6 //! component which does this.
7 //!
8 //! It also is responsible for watching the disk for changes, and for merging
9 //! editor state (modified, unsaved files) with disk state.
10 //!
11 //! VFS is based on a concept of roots: a set of directories on the file system
12 //! whihc are watched for changes. Typically, there will be a root for each
13 //! Cargo package.
14 mod arena;
15 mod io;
16
17 use std::{
18     thread,
19     cmp::Reverse,
20     path::{Path, PathBuf},
21     ffi::OsStr,
22     sync::Arc,
23 };
24
25 use relative_path::RelativePathBuf;
26 use thread_worker::{WorkerHandle, Worker};
27
28 use crate::{
29     arena::{ArenaId, Arena},
30     io::FileEvent,
31 };
32
33 /// `RootFilter` is a predicate that checks if a file can belong to a root
34 struct RootFilter {
35     root: PathBuf,
36     file_filter: fn(&Path) -> bool,
37 }
38
39 impl RootFilter {
40     fn new(root: PathBuf) -> RootFilter {
41         RootFilter {
42             root,
43             file_filter: rs_extension_filter,
44         }
45     }
46     fn can_contain(&self, path: &Path) -> bool {
47         (self.file_filter)(path) && path.starts_with(&self.root)
48     }
49 }
50
51 fn rs_extension_filter(p: &Path) -> bool {
52     p.extension() == Some(OsStr::new("rs"))
53 }
54
55 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
56 pub struct VfsRoot(u32);
57
58 impl ArenaId for VfsRoot {
59     fn from_u32(idx: u32) -> VfsRoot {
60         VfsRoot(idx)
61     }
62     fn to_u32(self) -> u32 {
63         self.0
64     }
65 }
66
67 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
68 pub struct VfsFile(u32);
69
70 impl ArenaId for VfsFile {
71     fn from_u32(idx: u32) -> VfsFile {
72         VfsFile(idx)
73     }
74     fn to_u32(self) -> u32 {
75         self.0
76     }
77 }
78
79 struct VfsFileData {
80     root: VfsRoot,
81     path: RelativePathBuf,
82     text: Arc<String>,
83 }
84
85 struct Vfs {
86     roots: Arena<VfsRoot, RootFilter>,
87     files: Arena<VfsFile, VfsFileData>,
88     // pending_changes: Vec<PendingChange>,
89     worker: Worker<PathBuf, (PathBuf, Vec<FileEvent>)>,
90     worker_handle: WorkerHandle,
91 }
92
93 impl Vfs {
94     pub fn new(mut roots: Vec<PathBuf>) -> Vfs {
95         let (worker, worker_handle) = io::start();
96
97         let mut res = Vfs {
98             roots: Arena::default(),
99             files: Arena::default(),
100             worker,
101             worker_handle,
102         };
103
104         roots.sort_by_key(|it| Reverse(it.as_os_str().len()));
105
106         for path in roots {
107             res.roots.alloc(RootFilter::new(path));
108         }
109         res
110     }
111
112     pub fn add_file_overlay(&mut self, path: &Path, content: String) {}
113
114     pub fn change_file_overlay(&mut self, path: &Path, new_content: String) {}
115
116     pub fn remove_file_overlay(&mut self, path: &Path) {}
117
118     pub fn commit_changes(&mut self) -> Vec<VfsChange> {
119         unimplemented!()
120     }
121
122     pub fn shutdown(self) -> thread::Result<()> {
123         let _ = self.worker.shutdown();
124         self.worker_handle.shutdown()
125     }
126 }
127
128 #[derive(Debug, Clone)]
129 pub enum VfsChange {
130     AddRoot {
131         root: VfsRoot,
132         files: Vec<(VfsFile, RelativePathBuf, Arc<String>)>,
133     },
134     AddFile {
135         file: VfsFile,
136         root: VfsRoot,
137         path: RelativePathBuf,
138         text: Arc<String>,
139     },
140     RemoveFile {
141         file: VfsFile,
142     },
143     ChangeFile {
144         file: VfsFile,
145         text: Arc<String>,
146     },
147 }