From 17b2b112bc0f1f1af59e3dae6cde37752837dac1 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 16 Nov 2023 18:02:49 -0800 Subject: [PATCH] Don't update file's saved mtime when reload is aborted --- crates/language/src/buffer.rs | 2 +- crates/language2/src/buffer.rs | 30 ++++++++++++++++------------ crates/project2/src/project_tests.rs | 13 +++++++----- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 6d5684e6d7..7feffbf3ed 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -646,7 +646,7 @@ impl Buffer { prev_version, Rope::text_fingerprint(&new_text), this.line_ending(), - new_mtime, + this.saved_mtime, cx, ); } diff --git a/crates/language2/src/buffer.rs b/crates/language2/src/buffer.rs index e191f408e7..51ed192b99 100644 --- a/crates/language2/src/buffer.rs +++ b/crates/language2/src/buffer.rs @@ -61,9 +61,14 @@ pub struct Buffer { diff_base: Option, git_diff: git::diff::BufferDiff, file: Option>, - saved_version: clock::Global, - saved_version_fingerprint: RopeFingerprint, + /// The mtime of the file when this buffer was last loaded from + /// or saved to disk. saved_mtime: SystemTime, + /// The version vector when this buffer was last loaded from + /// or saved to disk. + saved_version: clock::Global, + /// A hash of the current contents of the buffer's file. + file_fingerprint: RopeFingerprint, transaction_depth: usize, was_dirty_before_starting_transaction: Option, reload_task: Option>>, @@ -386,8 +391,7 @@ impl Buffer { .ok_or_else(|| anyhow!("missing line_ending"))?, )); this.saved_version = proto::deserialize_version(&message.saved_version); - this.saved_version_fingerprint = - proto::deserialize_fingerprint(&message.saved_version_fingerprint)?; + this.file_fingerprint = proto::deserialize_fingerprint(&message.saved_version_fingerprint)?; this.saved_mtime = message .saved_mtime .ok_or_else(|| anyhow!("invalid saved_mtime"))? @@ -403,7 +407,7 @@ impl Buffer { diff_base: self.diff_base.as_ref().map(|h| h.to_string()), line_ending: proto::serialize_line_ending(self.line_ending()) as i32, saved_version: proto::serialize_version(&self.saved_version), - saved_version_fingerprint: proto::serialize_fingerprint(self.saved_version_fingerprint), + saved_version_fingerprint: proto::serialize_fingerprint(self.file_fingerprint), saved_mtime: Some(self.saved_mtime.into()), } } @@ -473,7 +477,7 @@ impl Buffer { Self { saved_mtime, saved_version: buffer.version(), - saved_version_fingerprint: buffer.as_rope().fingerprint(), + file_fingerprint: buffer.as_rope().fingerprint(), reload_task: None, transaction_depth: 0, was_dirty_before_starting_transaction: None, @@ -540,7 +544,7 @@ impl Buffer { } pub fn saved_version_fingerprint(&self) -> RopeFingerprint { - self.saved_version_fingerprint + self.file_fingerprint } pub fn saved_mtime(&self) -> SystemTime { @@ -568,7 +572,7 @@ impl Buffer { cx: &mut ModelContext, ) { self.saved_version = version; - self.saved_version_fingerprint = fingerprint; + self.file_fingerprint = fingerprint; self.saved_mtime = mtime; cx.emit(Event::Saved); cx.notify(); @@ -611,7 +615,7 @@ impl Buffer { prev_version, Rope::text_fingerprint(&new_text), this.line_ending(), - new_mtime, + this.saved_mtime, cx, ); } @@ -631,14 +635,14 @@ impl Buffer { cx: &mut ModelContext, ) { self.saved_version = version; - self.saved_version_fingerprint = fingerprint; + self.file_fingerprint = fingerprint; self.text.set_line_ending(line_ending); self.saved_mtime = mtime; if let Some(file) = self.file.as_ref().and_then(|f| f.as_local()) { file.buffer_reloaded( self.remote_id(), &self.saved_version, - self.saved_version_fingerprint, + self.file_fingerprint, self.line_ending(), self.saved_mtime, cx, @@ -1282,12 +1286,12 @@ impl Buffer { } pub fn is_dirty(&self) -> bool { - self.saved_version_fingerprint != self.as_rope().fingerprint() + self.file_fingerprint != self.as_rope().fingerprint() || self.file.as_ref().map_or(false, |file| file.is_deleted()) } pub fn has_conflict(&self) -> bool { - self.saved_version_fingerprint != self.as_rope().fingerprint() + self.file_fingerprint != self.as_rope().fingerprint() && self .file .as_ref() diff --git a/crates/project2/src/project_tests.rs b/crates/project2/src/project_tests.rs index 4c5905ff7e..e607b30766 100644 --- a/crates/project2/src/project_tests.rs +++ b/crates/project2/src/project_tests.rs @@ -2587,7 +2587,7 @@ async fn test_save_file(cx: &mut gpui::TestAppContext) { assert_eq!(new_text, buffer.update(cx, |buffer, _| buffer.text())); } -#[gpui::test(iterations = 10)] +#[gpui::test(iterations = 30)] async fn test_file_changes_multiple_times_on_disk(cx: &mut gpui::TestAppContext) { init_test(cx); @@ -2638,14 +2638,17 @@ async fn test_file_changes_multiple_times_on_disk(cx: &mut gpui::TestAppContext) buffer.read_with(cx, |buffer, _| { let buffer_text = buffer.text(); if buffer_text == on_disk_text { - assert!(!buffer.is_dirty(), "buffer shouldn't be dirty. text: {buffer_text:?}, disk text: {on_disk_text:?}"); + assert!( + !buffer.is_dirty() && !buffer.has_conflict(), + "buffer shouldn't be dirty. text: {buffer_text:?}, disk text: {on_disk_text:?}", + ); } // If the file change occurred while the buffer was processing the first - // change, the buffer may be in a conflicting state. + // change, the buffer will be in a conflicting state. else { assert!( - buffer.is_dirty(), - "buffer should report that it is dirty. text: {buffer_text:?}, disk text: {on_disk_text:?}" + buffer.is_dirty() && buffer.has_conflict(), + "buffer should report that it has a conflict. text: {buffer_text:?}, disk text: {on_disk_text:?}" ); } });