From f7804d3f19941897c59f799b4c5fff78bd4c670d Mon Sep 17 00:00:00 2001 From: Nikolay Minaev Date: Sat, 27 Jul 2024 19:47:23 +0400 Subject: [PATCH] Use fs' mtime to avoid saving problem on out-of-synced network fs (#11142) In the case of network file systems, if the server time is ahead of the local system time, then helix could annoy with messages that the file has already been modified by another application. --- helix-term/src/application.rs | 2 +- helix-view/src/document.rs | 36 ++++++++++++++++++++++++++++++----- helix-view/src/editor.rs | 2 +- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 60bc5b7cf23a..7da96b08a480 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -575,7 +575,7 @@ impl Application { doc_save_event.revision ); - doc.set_last_saved_revision(doc_save_event.revision); + doc.set_last_saved_revision(doc_save_event.revision, doc_save_event.save_time); let lines = doc_save_event.text.len_lines(); let bytes = doc_save_event.text.len_bytes(); diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 4895551129c8..346f04ed8f5f 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -106,6 +106,7 @@ impl Serialize for Mode { #[derive(Debug, Clone)] pub struct DocumentSavedEvent { pub revision: usize, + pub save_time: SystemTime, pub doc_id: DocumentId, pub path: PathBuf, pub text: Rope, @@ -965,6 +966,11 @@ impl Document { } .await; + let save_time = match fs::metadata(&write_path).await { + Ok(metadata) => metadata.modified().map_or(SystemTime::now(), |mtime| mtime), + Err(_) => SystemTime::now(), + }; + if let Some(backup) = backup { if write_result.is_err() { // restore backup @@ -987,6 +993,7 @@ impl Document { let event = DocumentSavedEvent { revision: current_rev, + save_time, doc_id, path, text: text.clone(), @@ -1045,6 +1052,26 @@ impl Document { } } + pub fn pickup_last_saved_time(&mut self) { + self.last_saved_time = match self.path.as_mut().unwrap().metadata() { + Ok(metadata) => match metadata.modified() { + Ok(mtime) => mtime, + Err(_) => { + log::error!( + "Use a system time instead of fs' mtime not supported on this platform" + ); + SystemTime::now() + } + }, + Err(e) => { + log::error!( + "Use a system time instead of fs' mtime: failed to file's metadata: {e}" + ); + SystemTime::now() + } + }; + } + // Detect if the file is readonly and change the readonly field if necessary (unix only) pub fn detect_readonly(&mut self) { // Allows setting the flag for files the user cannot modify, like root files @@ -1082,9 +1109,7 @@ impl Document { self.apply(&transaction, view.id); self.append_changes_to_history(view); self.reset_modified(); - - self.last_saved_time = SystemTime::now(); - + self.pickup_last_saved_time(); self.detect_indent_and_line_ending(); match provider_registry.get_diff_base(&path) { @@ -1123,6 +1148,7 @@ impl Document { self.path = path; self.detect_readonly(); + self.pickup_last_saved_time(); } /// Set the programming language for the file and load associated data (e.g. highlighting) @@ -1603,7 +1629,7 @@ impl Document { } /// Set the document's latest saved revision to the given one. - pub fn set_last_saved_revision(&mut self, rev: usize) { + pub fn set_last_saved_revision(&mut self, rev: usize, save_time: SystemTime) { log::debug!( "doc {} revision updated {} -> {}", self.id, @@ -1611,7 +1637,7 @@ impl Document { rev ); self.last_saved_revision = rev; - self.last_saved_time = SystemTime::now(); + self.last_saved_time = save_time; } /// Get the document's latest saved revision. diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index ba7337f22339..4249db1d5d09 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -2083,7 +2083,7 @@ impl Editor { }; let doc = doc_mut!(self, &save_event.doc_id); - doc.set_last_saved_revision(save_event.revision); + doc.set_last_saved_revision(save_event.revision, save_event.save_time); } }