Skip to content

Commit be76f35

Browse files
committed
Auto merge of rust-lang#14034 - lnicola:tweak-change-collapsing, r=Veykril
internal: Tweak change collapsing CC rust-lang/rust-analyzer#14025 (comment).
2 parents b75803a + deff5f2 commit be76f35

File tree

1 file changed

+48
-50
lines changed

1 file changed

+48
-50
lines changed

crates/rust-analyzer/src/global_state.rs

+48-50
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
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

88
use crossbeam_channel::{unbounded, Receiver, Sender};
99
use 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

Comments
 (0)