3
3
//!
4
4
//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
5
5
6
- use std:: { mem , sync:: Arc , time:: Instant } ;
6
+ use std:: { sync:: Arc , time:: Instant } ;
7
7
8
8
use crossbeam_channel:: { unbounded, Receiver , Sender } ;
9
9
use flycheck:: FlycheckHandle ;
@@ -179,10 +179,9 @@ impl GlobalState {
179
179
180
180
pub ( crate ) fn process_changes ( & mut self ) -> bool {
181
181
let _p = profile:: span ( "GlobalState::process_changes" ) ;
182
- // A file was added or deleted
183
- let mut has_structure_changes = false ;
184
182
let mut workspace_structure_change = None ;
185
183
184
+ let mut file_changes = FxHashMap :: default ( ) ;
186
185
let ( change, changed_files) = {
187
186
let mut change = Change :: new ( ) ;
188
187
let ( vfs, line_endings_map) = & mut * self . vfs . write ( ) ;
@@ -191,57 +190,56 @@ impl GlobalState {
191
190
return false ;
192
191
}
193
192
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 {
202
197
use vfs:: ChangeKind :: * ;
203
198
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
+ }
205
231
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
+ ) ;
209
240
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 ;
245
243
for file in & changed_files {
246
244
if let Some ( path) = vfs. file_path ( file. file_id ) . as_path ( ) {
247
245
let path = path. to_path_buf ( ) ;
0 commit comments