Relay the saved mtime when saving a buffer

Antonio Scandurra created

Change summary

zed-rpc/proto/zed.proto  |  1 +
zed/src/editor/buffer.rs | 34 +++++++++++++++++++---------------
zed/src/worktree.rs      | 25 +++++++++++++++++++------
3 files changed, 39 insertions(+), 21 deletions(-)

Detailed changes

zed-rpc/proto/zed.proto 🔗

@@ -109,6 +109,7 @@ message BufferSaved {
     uint64 worktree_id = 1;
     uint64 buffer_id = 2;
     repeated VectorClockEntry version = 3;
+    Timestamp mtime = 4;
 }
 
 message User {

zed/src/editor/buffer.rs 🔗

@@ -666,7 +666,10 @@ impl Buffer {
         self.file.as_mut()
     }
 
-    pub fn save(&mut self, cx: &mut ModelContext<Self>) -> Result<Task<Result<time::Global>>> {
+    pub fn save(
+        &mut self,
+        cx: &mut ModelContext<Self>,
+    ) -> Result<Task<Result<(time::Global, SystemTime)>>> {
         let file = self
             .file
             .as_ref()
@@ -675,11 +678,11 @@ impl Buffer {
         let version = self.version.clone();
         let save = file.save(self.remote_id, text, version, cx.as_mut());
         Ok(cx.spawn(|this, mut cx| async move {
-            let version = save.await?;
+            let (version, mtime) = save.await?;
             this.update(&mut cx, |this, cx| {
-                this.did_save(version.clone(), cx).unwrap();
+                this.did_save(version.clone(), mtime, cx);
             });
-            Ok(version)
+            Ok((version, mtime))
         }))
     }
 
@@ -702,22 +705,23 @@ impl Buffer {
         cx.spawn(|this, mut cx| async move {
             save_as.await.map(|new_file| {
                 this.update(&mut cx, |this, cx| {
+                    let mtime = new_file.mtime;
                     this.file = Some(new_file);
-                    this.did_save(version, cx).unwrap();
+                    this.did_save(version, mtime, cx);
                 });
             })
         })
     }
 
-    pub fn did_save(&mut self, version: time::Global, cx: &mut ModelContext<Self>) -> Result<()> {
-        if let Some(file) = self.file.as_ref() {
-            self.saved_mtime = file.mtime;
-            self.saved_version = version;
-            cx.emit(Event::Saved);
-            Ok(())
-        } else {
-            Err(anyhow!("buffer has no file"))
-        }
+    pub fn did_save(
+        &mut self,
+        version: time::Global,
+        mtime: SystemTime,
+        cx: &mut ModelContext<Self>,
+    ) {
+        self.saved_mtime = mtime;
+        self.saved_version = version;
+        cx.emit(Event::Saved);
     }
 
     pub fn file_updated(
@@ -3235,7 +3239,7 @@ mod tests {
             assert!(buffer.is_dirty());
             assert_eq!(*events.borrow(), &[Event::Edited, Event::Dirtied]);
             events.borrow_mut().clear();
-            buffer.did_save(buffer.version(), cx).unwrap();
+            buffer.did_save(buffer.version(), buffer.file().unwrap().mtime, cx);
         });
 
         // after saving, the buffer is not dirty, and emits a saved event.

zed/src/worktree.rs 🔗

@@ -386,7 +386,13 @@ impl Worktree {
                 .and_then(|buf| buf.upgrade(&cx))
             {
                 buffer.update(cx, |buffer, cx| {
-                    buffer.did_save(message.version.try_into()?, cx)
+                    let version = message.version.try_into()?;
+                    let mtime = message
+                        .mtime
+                        .ok_or_else(|| anyhow!("missing mtime"))?
+                        .into();
+                    buffer.did_save(version, mtime, cx);
+                    Result::<_, anyhow::Error>::Ok(())
                 })?;
             }
             Ok(())
@@ -1423,22 +1429,23 @@ impl File {
         text: Rope,
         version: time::Global,
         cx: &mut MutableAppContext,
-    ) -> Task<Result<time::Global>> {
+    ) -> Task<Result<(time::Global, SystemTime)>> {
         self.worktree.update(cx, |worktree, cx| match worktree {
             Worktree::Local(worktree) => {
                 let rpc = worktree.rpc.clone();
                 let save = worktree.save(self.path.clone(), text, cx);
                 cx.spawn(|_, _| async move {
-                    save.await?;
+                    let entry = save.await?;
                     if let Some((rpc, worktree_id)) = rpc {
                         rpc.send(proto::BufferSaved {
                             worktree_id,
                             buffer_id,
                             version: (&version).into(),
+                            mtime: Some(entry.mtime.into()),
                         })
                         .await?;
                     }
-                    Ok(version)
+                    Ok((version, entry.mtime))
                 })
             }
             Worktree::Remote(worktree) => {
@@ -1451,7 +1458,12 @@ impl File {
                             buffer_id,
                         })
                         .await?;
-                    Ok(response.version.try_into()?)
+                    let version = response.version.try_into()?;
+                    let mtime = response
+                        .mtime
+                        .ok_or_else(|| anyhow!("missing mtime"))?
+                        .into();
+                    Ok((version, mtime))
                 })
             }
         })
@@ -2477,13 +2489,14 @@ mod remote {
                 .and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
                 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
         })?;
-        let version = buffer.update(cx, |buffer, cx| buffer.save(cx))?.await?;
+        let (version, mtime) = buffer.update(cx, |buffer, cx| buffer.save(cx))?.await?;
         rpc.respond(
             envelope.receipt(),
             proto::BufferSaved {
                 worktree_id: envelope.payload.worktree_id,
                 buffer_id: envelope.payload.buffer_id,
                 version: (&version).into(),
+                mtime: Some(mtime.into()),
             },
         )
         .await?;