33//!
44//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
55
6- use std:: { mem , sync:: Arc , time:: Instant } ;
6+ use std:: { sync:: Arc , time:: Instant } ;
77
88use crossbeam_channel:: { unbounded, Receiver , Sender } ;
99use flycheck:: FlycheckHandle ;
@@ -179,10 +179,9 @@ impl GlobalState {
179179
180180 pub ( crate ) fn process_changes ( & mut self ) -> bool {
181181 let _p = profile:: span ( "GlobalState::process_changes" ) ;
182- // A file was added or deleted
183- let mut has_structure_changes = false ;
184182 let mut workspace_structure_change = None ;
185183
184+ let mut file_changes = FxHashMap :: default ( ) ;
186185 let ( change, changed_files) = {
187186 let mut change = Change :: new ( ) ;
188187 let ( vfs, line_endings_map) = & mut * self . vfs . write ( ) ;
@@ -191,57 +190,56 @@ impl GlobalState {
191190 return false ;
192191 }
193192
194- // important: this needs to be a stable sort, the order between changes is relevant
195- // for the same file ids
196- changed_files. sort_by_key ( |file| file. file_id ) ;
197- // We need to fix up the changed events a bit, if we have a create or modify for a file
198- // id that is followed by a delete we actually no longer observe the file text from the
199- // create or modify which may cause problems later on
200- let mut collapsed_create_delete = false ;
201- changed_files. dedup_by ( |a, b| {
193+ // We need to fix up the changed events a bit. If we have a create or modify for a file
194+ // id that is followed by a delete we actually skip observing the file text from the
195+ // earlier event, to avoid problems later on.
196+ for changed_file in & changed_files {
202197 use vfs:: ChangeKind :: * ;
203198
204- let has_collapsed_create_delete = mem:: replace ( & mut collapsed_create_delete, false ) ;
199+ file_changes
200+ . entry ( changed_file. file_id )
201+ . and_modify ( |( change, just_created) | {
202+ // None -> Delete => keep
203+ // Create -> Delete => collapse
204+ //
205+ match ( change, just_created, changed_file. change_kind ) {
206+ // latter `Delete` wins
207+ ( change, _, Delete ) => * change = Delete ,
208+ // merge `Create` with `Create` or `Modify`
209+ ( Create , _, Create | Modify ) => { }
210+ // collapse identical `Modify`es
211+ ( Modify , _, Modify ) => { }
212+ // equivalent to `Modify`
213+ ( change @ Delete , just_created, Create ) => {
214+ * change = Modify ;
215+ * just_created = true ;
216+ }
217+ // shouldn't occur, but collapse into `Create`
218+ ( change @ Delete , just_created, Modify ) => {
219+ * change = Create ;
220+ * just_created = true ;
221+ }
222+ // shouldn't occur, but collapse into `Modify`
223+ ( Modify , _, Create ) => { }
224+ }
225+ } )
226+ . or_insert ( (
227+ changed_file. change_kind ,
228+ matches ! ( changed_file. change_kind, Create ) ,
229+ ) ) ;
230+ }
205231
206- if a. file_id != b. file_id {
207- return false ;
208- }
232+ changed_files. extend (
233+ file_changes
234+ . into_iter ( )
235+ . filter ( |( _, ( change_kind, just_created) ) | {
236+ !matches ! ( ( change_kind, just_created) , ( vfs:: ChangeKind :: Delete , true ) )
237+ } )
238+ . map ( |( file_id, ( change_kind, _) ) | vfs:: ChangedFile { file_id, change_kind } ) ,
239+ ) ;
209240
210- // true => delete the second element (a), we swap them here as they are inverted by dedup_by
211- match ( b. change_kind , a. change_kind ) {
212- // duplicate can be merged
213- ( Create , Create ) | ( Modify , Modify ) | ( Delete , Delete ) => true ,
214- // just leave the create, modify is irrelevant
215- ( Create , Modify ) => true ,
216- // modify becomes irrelevant if the file is deleted
217- ( Modify , Delete ) => {
218- mem:: swap ( a, b) ;
219- true
220- }
221- // Remove the create message, and in the following loop, also remove the delete
222- ( Create , Delete ) => {
223- collapsed_create_delete = true ;
224- b. change_kind = Delete ;
225- true
226- }
227- // trailing delete from earlier
228- ( Delete , Create | Modify ) if has_collapsed_create_delete => {
229- b. change_kind = Create ;
230- true
231- }
232- // this is equivalent to a modify
233- ( Delete , Create ) => {
234- b. change_kind = Modify ;
235- true
236- }
237- // can't really occur
238- ( Modify , Create ) => false ,
239- ( Delete , Modify ) => false ,
240- }
241- } ) ;
242- if collapsed_create_delete {
243- changed_files. pop ( ) ;
244- }
241+ // A file was added or deleted
242+ let mut has_structure_changes = false ;
245243 for file in & changed_files {
246244 if let Some ( path) = vfs. file_path ( file. file_id ) . as_path ( ) {
247245 let path = path. to_path_buf ( ) ;
0 commit comments