@@ -19,6 +19,7 @@ use std::future::Future;
19use std::path::{Path, PathBuf};
19use std::path::{Path, PathBuf};
20use std::str::FromStr;
20use std::str::FromStr;
21use std::sync::Arc;
21use std::sync::Arc;
22+use std::time::SystemTime;
23use helix_core::{
24use helix_core::{
@@ -135,6 +136,10 @@ pub struct Document {
136 pub savepoint: Option<Transaction>,
137 pub savepoint: Option<Transaction>,
139+ // Last time we wrote to the file. This will carry the time the file was last opened if there
141+ last_saved_time: SystemTime,
138 last_saved_revision: usize,
143 last_saved_revision: usize,
139 version: i32, // should be usize?
144 version: i32, // should be usize?
140 pub(crate) modified_since_accessed: bool,
145 pub(crate) modified_since_accessed: bool,
@@ -160,6 +165,7 @@ impl fmt::Debug for Document {
160 .field("changes", &self.changes)
165 .field("changes", &self.changes)
161 .field("old_state", &self.old_state)
166 .field("old_state", &self.old_state)
162 // .field("history", &self.history)
167 // .field("history", &self.history)
168+ .field("last_saved_time", &self.last_saved_time)
163 .field("last_saved_revision", &self.last_saved_revision)
169 .field("last_saved_revision", &self.last_saved_revision)
164 .field("version", &self.version)
170 .field("version", &self.version)
165 .field("modified_since_accessed", &self.modified_since_accessed)
171 .field("modified_since_accessed", &self.modified_since_accessed)
@@ -382,6 +388,7 @@ impl Document {
382 version: 0,
388 version: 0,
383 history: Cell::new(History::default()),
389 history: Cell::new(History::default()),
384 savepoint: None,
390 savepoint: None,
391+ last_saved_time: SystemTime::now(),
385 last_saved_revision: 0,
392 last_saved_revision: 0,
386 modified_since_accessed: false,
393 modified_since_accessed: false,
387 language_server: None,
394 language_server: None,
@@ -577,9 +584,11 @@ impl Document {
578 let encoding = self.encoding;
585 let encoding = self.encoding;
587+ let last_saved_time = self.last_saved_time;
580 // We encode the file according to the `Document`'s encoding.
589 // We encode the file according to the `Document`'s encoding.
581 let future = async move {
590 let future = async move {
582− use tokio::fs::File;
591+ use tokio::{fs, fs::File};
583 if let Some(parent) = path.parent() {
592 if let Some(parent) = path.parent() {
584 // TODO: display a prompt asking the user if the directories should be created
593 // TODO: display a prompt asking the user if the directories should be created
585 if !parent.exists() {
594 if !parent.exists() {
@@ -591,6 +600,17 @@ impl Document {
603+ // Protect against overwriting changes made externally
605+ if let Ok(metadata) = fs::metadata(&path).await {
606+ if let Ok(mtime) = metadata.modified() {
607+ if last_saved_time < mtime {
608+ bail!("file modified by an external process, use :w! to overwrite");
594 let mut file = File::create(&path).await?;
614 let mut file = File::create(&path).await?;
595 to_writer(&mut file, encoding, &text).await?;
615 to_writer(&mut file, encoding, &text).await?;
@@ -668,6 +688,8 @@ impl Document {
668 self.append_changes_to_history(view);
688 self.append_changes_to_history(view);
669 self.reset_modified();
689 self.reset_modified();
691+ self.last_saved_time = SystemTime::now();
671 self.detect_indent_and_line_ending();
693 self.detect_indent_and_line_ending();
673 match provider_registry.get_diff_base(&path) {
695 match provider_registry.get_diff_base(&path) {
@@ -1016,6 +1038,7 @@ impl Document {
1018 self.last_saved_revision = rev;
1040 self.last_saved_revision = rev;
1041+ self.last_saved_time = SystemTime::now();
1021 /// Get the document's latest saved revision.
1044 /// Get the document's latest saved revision.