@@ -91,12 +91,21 @@ impl nohash_hasher::IsEnabled for FileId {}
9191pub struct Vfs {
9292 interner : PathInterner ,
9393 data : Vec < FileState > ,
94+ // FIXME: This should be a HashMap<FileId, ChangeFile>
95+ // right now we do a nasty deduplication in GlobalState::process_changes that would be a lot
96+ // easier to handle here on insertion.
9497 changes : Vec < ChangedFile > ,
98+ // The above FIXME would then also get rid of this probably
99+ created_this_cycle : Vec < FileId > ,
95100}
96101
97- #[ derive( Copy , PartialEq , PartialOrd , Clone ) ]
102+ #[ derive( Copy , Clone , Debug , PartialEq , PartialOrd ) ]
98103pub enum FileState {
104+ /// The file has been created this cycle.
105+ Created ,
106+ /// The file exists.
99107 Exists ,
108+ /// The file is deleted.
100109 Deleted ,
101110}
102111
@@ -121,6 +130,11 @@ impl ChangedFile {
121130 matches ! ( self . change, Change :: Create ( _) | Change :: Delete )
122131 }
123132
133+ /// Returns `true` if the change is [`Create`](ChangeKind::Create).
134+ pub fn is_created ( & self ) -> bool {
135+ matches ! ( self . change, Change :: Create ( _) )
136+ }
137+
124138 /// Returns `true` if the change is [`Modify`](ChangeKind::Modify).
125139 pub fn is_modified ( & self ) -> bool {
126140 matches ! ( self . change, Change :: Modify ( _) )
@@ -160,7 +174,9 @@ pub enum ChangeKind {
160174impl Vfs {
161175 /// Id of the given path if it exists in the `Vfs` and is not deleted.
162176 pub fn file_id ( & self , path : & VfsPath ) -> Option < FileId > {
163- self . interner . get ( path) . filter ( |& it| matches ! ( self . get( it) , FileState :: Exists ) )
177+ self . interner
178+ . get ( path)
179+ . filter ( |& it| matches ! ( self . get( it) , FileState :: Exists | FileState :: Created ) )
164180 }
165181
166182 /// File path corresponding to the given `file_id`.
@@ -178,7 +194,9 @@ impl Vfs {
178194 pub fn iter ( & self ) -> impl Iterator < Item = ( FileId , & VfsPath ) > + ' _ {
179195 ( 0 ..self . data . len ( ) )
180196 . map ( |it| FileId ( it as u32 ) )
181- . filter ( move |& file_id| matches ! ( self . get( file_id) , FileState :: Exists ) )
197+ . filter ( move |& file_id| {
198+ matches ! ( self . get( file_id) , FileState :: Exists | FileState :: Created )
199+ } )
182200 . map ( move |file_id| {
183201 let path = self . interner . lookup ( file_id) ;
184202 ( file_id, path)
@@ -193,27 +211,43 @@ impl Vfs {
193211 /// [`FileId`] for it.
194212 pub fn set_file_contents ( & mut self , path : VfsPath , contents : Option < Vec < u8 > > ) -> bool {
195213 let file_id = self . alloc_file_id ( path) ;
196- let change_kind = match ( self . get ( file_id) , contents) {
214+ let state = self . get ( file_id) ;
215+ let change_kind = match ( state, contents) {
197216 ( FileState :: Deleted , None ) => return false ,
198217 ( FileState :: Deleted , Some ( v) ) => Change :: Create ( v) ,
199- ( FileState :: Exists , None ) => Change :: Delete ,
200- ( FileState :: Exists , Some ( v) ) => Change :: Modify ( v) ,
218+ ( FileState :: Exists | FileState :: Created , None ) => Change :: Delete ,
219+ ( FileState :: Exists | FileState :: Created , Some ( v) ) => Change :: Modify ( v) ,
220+ } ;
221+ self . data [ file_id. 0 as usize ] = match change_kind {
222+ Change :: Create ( _) => {
223+ self . created_this_cycle . push ( file_id) ;
224+ FileState :: Created
225+ }
226+ // If the file got created this cycle, make sure we keep it that way even
227+ // if a modify comes in
228+ Change :: Modify ( _) if matches ! ( state, FileState :: Created ) => FileState :: Created ,
229+ Change :: Modify ( _) => FileState :: Exists ,
230+ Change :: Delete => FileState :: Deleted ,
201231 } ;
202232 let changed_file = ChangedFile { file_id, change : change_kind } ;
203- self . data [ file_id. 0 as usize ] =
204- if changed_file. exists ( ) { FileState :: Exists } else { FileState :: Deleted } ;
205233 self . changes . push ( changed_file) ;
206234 true
207235 }
208236
209237 /// Drain and returns all the changes in the `Vfs`.
210238 pub fn take_changes ( & mut self ) -> Vec < ChangedFile > {
239+ for file_id in self . created_this_cycle . drain ( ..) {
240+ if self . data [ file_id. 0 as usize ] == FileState :: Created {
241+ // downgrade the file from `Created` to `Exists` as the cycle is done
242+ self . data [ file_id. 0 as usize ] = FileState :: Exists ;
243+ }
244+ }
211245 mem:: take ( & mut self . changes )
212246 }
213247
214248 /// Provides a panic-less way to verify file_id validity.
215249 pub fn exists ( & self , file_id : FileId ) -> bool {
216- matches ! ( self . get( file_id) , FileState :: Exists )
250+ matches ! ( self . get( file_id) , FileState :: Exists | FileState :: Created )
217251 }
218252
219253 /// Returns the id associated with `path`
0 commit comments