1- //! Owned fork of rust-analyzer's virtual file system (tinymist-style).
1+ //! Virtual file system: interned paths, content change log, and loader
2+ //! interface.
23//!
3- //! Upstream: <https://github.com/rust-lang/rust-analyzer/tree/master/crates/vfs>
4- //!
5- //! # Virtual File System
6- //!
7- //! VFS records all file changes pushed to it via [`set_file_contents`].
8- //! As such it only ever stores changes, not the actual content of a file at any
9- //! given moment. All file changes are logged, and can be retrieved via
10- //! [`take_changes`] method. The pack of changes is then pushed to `salsa` and
11- //! triggers incremental recomputation.
12- //!
13- //! Files in VFS are identified with [`FileId`]s -- interned paths. The notion
14- //! of the path, [`VfsPath`] is somewhat abstract: at the moment, it is
15- //! represented as an [`std::path::PathBuf`] internally, but this is an
16- //! implementation detail.
17- //!
18- //! VFS doesn't do IO or file watching itself. For that, see the [`loader`]
19- //! module. [`loader::Handle`] is an object-safe trait which abstracts both file
20- //! loading and file watching. [`Handle`] is dynamically configured with a set
21- //! of directory entries which should be scanned and watched. [`Handle`] then
22- //! asynchronously pushes file changes. Directory entries are configured in
23- //! free-form via list of globs, it's up to the [`Handle`] to interpret the
24- //! globs in any specific way.
25- //!
26- //! VFS stores a flat list of files. [`file_set::FileSet`] can partition this
27- //! list of files into disjoint sets of files. Traversal-like operations
28- //! (including getting the neighbor file by the relative path) are handled by
29- //! the [`FileSet`]. [`FileSet`]s are also pushed to salsa and cause it to
30- //! re-check `mod foo;` declarations when files are created or deleted.
31- //!
32- //! [`FileSet`] and [`loader::Entry`] play similar, but different roles.
33- //! Both specify the "set of paths/files", one is geared towards file watching,
34- //! the other towards salsa changes. In particular, single [`FileSet`]
35- //! may correspond to several [`loader::Entry`]. For example, a crate from
36- //! crates.io which uses code generation would have two [`Entries`] -- for
37- //! sources in `~/.cargo`, and for generated code in `./target/debug/build`. It
38- //! will have a single [`FileSet`] which unions the two sources.
4+ //! Based on rust-analyzer's `vfs` crate
5+ //! (<https://github.com/rust-lang/rust-analyzer/tree/master/crates/vfs>).
6+ //! IO and watching live in [`loader`] backends ([`notify`], [`dummy`]).
397//!
408//! [`set_file_contents`]: Vfs::set_file_contents
419//! [`take_changes`]: Vfs::take_changes
42- //! [`FileSet`]: file_set::FileSet
43- //! [`Handle`]: loader::Handle
44- //! [`Entries`]: loader::Entry
4510
4611mod anchored_path;
4712pub mod dummy;
@@ -81,12 +46,9 @@ fn hash_once<Hasher: std::hash::Hasher + Default>(thing: impl std::hash::Hash) -
8146 h. finish ( )
8247}
8348
84- /// Handle to a file in [`Vfs`]
85- ///
86- /// Most functions in rust-analyzer use this when they need to refer to a file.
49+ /// Interned file identity in [`Vfs`].
8750#[ derive( Copy , Clone , Debug , Ord , PartialOrd , Eq , PartialEq , Hash ) ]
8851pub struct FileId ( u32 ) ;
89- // pub struct FileId(NonMaxU32);
9052
9153impl FileId {
9254 const MAX : u32 = 0x7fff_ffff ;
@@ -166,7 +128,7 @@ impl ChangedFile {
166128 }
167129 }
168130
169- /// UTF-8 file text for analysis ; invalid UTF-8 becomes empty.
131+ /// UTF-8 text; invalid UTF-8 becomes empty.
170132 pub fn text ( & self ) -> Option < triomphe:: Arc < str > > {
171133 let bytes = match & self . change {
172134 Change :: Create ( bytes, _) | Change :: Modify ( bytes, _) => bytes. as_slice ( ) ,
@@ -176,29 +138,25 @@ impl ChangedFile {
176138 Some ( triomphe:: Arc :: < str > :: from ( text) )
177139 }
178140
179- /// Bytes for Create/Modify; `None` for Delete.
180141 pub fn contents ( & self ) -> Option < & [ u8 ] > {
181142 match & self . change {
182143 Change :: Create ( bytes, _) | Change :: Modify ( bytes, _) => Some ( bytes. as_slice ( ) ) ,
183144 Change :: Delete => None ,
184145 }
185146 }
186147
187- /// Test/host helper: create a file with UTF-8 text contents.
188148 pub fn create ( file_id : FileId , text : impl AsRef < str > ) -> Self {
189149 let bytes = text. as_ref ( ) . as_bytes ( ) . to_vec ( ) ;
190150 let hash = hash_once :: < FxHasher > ( & * bytes) ;
191151 Self { file_id, change : Change :: Create ( bytes, hash) }
192152 }
193153
194- /// Test/host helper: modify a file with UTF-8 text contents.
195154 pub fn modify ( file_id : FileId , text : impl AsRef < str > ) -> Self {
196155 let bytes = text. as_ref ( ) . as_bytes ( ) . to_vec ( ) ;
197156 let hash = hash_once :: < FxHasher > ( & * bytes) ;
198157 Self { file_id, change : Change :: Modify ( bytes, hash) }
199158 }
200159
201- /// Test/host helper: delete a file.
202160 pub fn delete ( file_id : FileId ) -> Self {
203161 Self { file_id, change : Change :: Delete }
204162 }
@@ -339,7 +297,6 @@ impl Vfs {
339297 }
340298 // shouldn't occur, but collapse into `Create`
341299 ( change @ Delete , Modify ( new, new_hash) ) => {
342- // Shouldn't occur; collapse into Create like upstream.
343300 * change = Create ( new, new_hash) ;
344301 }
345302 // shouldn't occur, but keep the Create
0 commit comments