wip

Max Brunsfeld created

Change summary

Cargo.lock                          |  1 
zed/Cargo.toml                      |  1 
zed/src/editor/buffer/mod.rs        | 33 +++++++++++++++---------
zed/src/editor/buffer_view.rs       | 15 ++++++-----
zed/src/workspace/workspace_view.rs | 41 +++++++++++++++---------------
5 files changed, 50 insertions(+), 41 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -2241,6 +2241,7 @@ dependencies = [
  "crossbeam-channel 0.5.0",
  "dirs",
  "easy-parallel",
+ "futures-core",
  "gpui",
  "ignore",
  "lazy_static",

zed/Cargo.toml 🔗

@@ -20,6 +20,7 @@ dirs = "3.0"
 easy-parallel = "3.1.0"
 gpui = {path = "../gpui"}
 ignore = {git = "https://github.com/zed-industries/ripgrep", rev = "1d152118f35b3e3590216709b86277062d79b8a0"}
+futures-core = "0.3"
 lazy_static = "1.4.0"
 libc = "0.2"
 log = "0.4"

zed/src/editor/buffer/mod.rs 🔗

@@ -3,6 +3,7 @@ mod point;
 mod text;
 
 pub use anchor::*;
+use futures_core::future::LocalBoxFuture;
 pub use point::*;
 pub use text::*;
 
@@ -14,7 +15,7 @@ use crate::{
     worktree::FileHandle,
 };
 use anyhow::{anyhow, Result};
-use gpui::{AppContext, Entity, ModelContext, Task};
+use gpui::{AppContext, Entity, ModelContext};
 use lazy_static::lazy_static;
 use rand::prelude::*;
 use std::{
@@ -243,23 +244,25 @@ impl Buffer {
         }
     }
 
-    pub fn save(&mut self, ctx: &mut ModelContext<Self>) -> Option<Task<Result<()>>> {
+    pub fn save(&mut self, ctx: &mut ModelContext<Self>) -> LocalBoxFuture<'static, Result<()>> {
         if let Some(file) = &self.file {
             let snapshot = self.snapshot();
-
-            let result = file.save(snapshot, ctx.app());
-
-            // TODO - don't do this until the save has finished
-            self.did_save(ctx);
-
-            Some(result)
+            let version = self.version.clone();
+            let save_task = file.save(snapshot, ctx.app());
+            let task = ctx.spawn(save_task, |me, save_result, ctx| {
+                if save_result.is_ok() {
+                    me.did_save(version, ctx);
+                }
+                save_result
+            });
+            Box::pin(task)
         } else {
-            None
+            Box::pin(async { Ok(()) })
         }
     }
 
-    fn did_save(&mut self, ctx: &mut ModelContext<Buffer>) {
-        self.persisted_version = self.fragments.summary().max_version;
+    fn did_save(&mut self, version: time::Global, ctx: &mut ModelContext<Buffer>) {
+        self.persisted_version = version;
         ctx.emit(Event::Saved);
     }
 
@@ -429,7 +432,7 @@ impl Buffer {
                 ctx.notify();
                 let changes = self.edits_since(old_version).collect::<Vec<_>>();
                 if !changes.is_empty() {
-                    ctx.emit(Event::Edited(changes))
+                    self.did_edit(changes, ctx);
                 }
             }
 
@@ -447,6 +450,10 @@ impl Buffer {
         Ok(ops)
     }
 
+    fn did_edit(&self, changes: Vec<Edit>, ctx: &mut ModelContext<Self>) {
+        ctx.emit(Event::Edited(changes))
+    }
+
     pub fn simulate_typing<T: Rng>(&mut self, rng: &mut T) {
         let end = rng.gen_range(0..self.len() + 1);
         let start = rng.gen_range(0..end + 1);

zed/src/editor/buffer_view.rs 🔗

@@ -5,12 +5,13 @@ use super::{
 use crate::{
     settings::Settings,
     watch,
-    workspace::{self, ItemEventEffect},
+    workspace::{self, WorkspaceEvent},
 };
 use anyhow::Result;
+use futures_core::future::LocalBoxFuture;
 use gpui::{
     fonts::Properties as FontProperties, keymap::Binding, text_layout, App, AppContext, Element,
-    ElementBox, Entity, FontCache, ModelHandle, Task, View, ViewContext, WeakViewHandle,
+    ElementBox, Entity, FontCache, ModelHandle, View, ViewContext, WeakViewHandle,
 };
 use gpui::{geometry::vector::Vector2F, TextLayoutCache};
 use parking_lot::Mutex;
@@ -1152,11 +1153,11 @@ impl workspace::Item for Buffer {
 }
 
 impl workspace::ItemView for BufferView {
-    fn event_effect(event: &Self::Event) -> ItemEventEffect {
+    fn to_workspace_event(event: &Self::Event) -> Option<WorkspaceEvent> {
         match event {
-            Event::Activate => ItemEventEffect::Activate,
-            Event::Edited => ItemEventEffect::ChangeTab,
-            _ => ItemEventEffect::None,
+            Event::Activate => Some(WorkspaceEvent::Activate),
+            Event::Saved => Some(WorkspaceEvent::TabStateChanged),
+            _ => None,
         }
     }
 
@@ -1184,7 +1185,7 @@ impl workspace::ItemView for BufferView {
         Some(clone)
     }
 
-    fn save(&self, ctx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
+    fn save(&self, ctx: &mut ViewContext<Self>) -> LocalBoxFuture<'static, Result<()>> {
         self.buffer.update(ctx, |buffer, ctx| buffer.save(ctx))
     }
 

zed/src/workspace/workspace_view.rs 🔗

@@ -1,8 +1,9 @@
 use super::{pane, Pane, PaneGroup, SplitDirection, Workspace};
 use crate::{settings::Settings, watch};
+use futures_core::future::LocalBoxFuture;
 use gpui::{
     color::rgbu, elements::*, keymap::Binding, AnyViewHandle, App, AppContext, Entity, ModelHandle,
-    MutableAppContext, Task, View, ViewContext, ViewHandle,
+    MutableAppContext, View, ViewContext, ViewHandle,
 };
 use log::{error, info};
 use std::{collections::HashSet, path::PathBuf};
@@ -12,14 +13,13 @@ pub fn init(app: &mut App) {
     app.add_bindings(vec![Binding::new("cmd-s", "workspace:save", None)]);
 }
 
-pub enum ItemEventEffect {
-    None,
-    ChangeTab,
+pub enum WorkspaceEvent {
+    TabStateChanged,
     Activate,
 }
 
 pub trait ItemView: View {
-    fn event_effect(event: &Self::Event) -> ItemEventEffect;
+    fn to_workspace_event(event: &Self::Event) -> Option<WorkspaceEvent>;
     fn title(&self, app: &AppContext) -> String;
     fn entry_id(&self, app: &AppContext) -> Option<(usize, usize)>;
     fn clone_on_split(&self, _: &mut ViewContext<Self>) -> Option<Self>
@@ -31,8 +31,8 @@ pub trait ItemView: View {
     fn is_modified(&self, _: &AppContext) -> bool {
         false
     }
-    fn save(&self, _: &mut ViewContext<Self>) -> Option<Task<anyhow::Result<()>>> {
-        None
+    fn save(&self, _: &mut ViewContext<Self>) -> LocalBoxFuture<'static, anyhow::Result<()>> {
+        Box::pin(async { Ok(()) })
     }
 }
 
@@ -45,7 +45,7 @@ pub trait ItemViewHandle: Send + Sync {
     fn id(&self) -> usize;
     fn to_any(&self) -> AnyViewHandle;
     fn is_modified(&self, ctx: &AppContext) -> bool;
-    fn save(&self, ctx: &mut MutableAppContext) -> Option<Task<anyhow::Result<()>>>;
+    fn save(&self, ctx: &mut MutableAppContext) -> LocalBoxFuture<'static, anyhow::Result<()>>;
 }
 
 impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
@@ -71,21 +71,21 @@ impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
     fn set_parent_pane(&self, pane: &ViewHandle<Pane>, app: &mut MutableAppContext) {
         pane.update(app, |_, ctx| {
             ctx.subscribe_to_view(self, |pane, item, event, ctx| {
-                match T::event_effect(event) {
-                    ItemEventEffect::Activate => {
+                match T::to_workspace_event(event) {
+                    Some(WorkspaceEvent::Activate) => {
                         if let Some(ix) = pane.item_index(&item) {
                             pane.activate_item(ix, ctx);
                             pane.activate(ctx);
                         }
                     }
-                    ItemEventEffect::ChangeTab => ctx.notify(),
+                    Some(WorkspaceEvent::TabStateChanged) => ctx.notify(),
                     _ => {}
                 }
             })
         })
     }
 
-    fn save(&self, ctx: &mut MutableAppContext) -> Option<Task<anyhow::Result<()>>> {
+    fn save(&self, ctx: &mut MutableAppContext) -> LocalBoxFuture<'static, anyhow::Result<()>> {
         self.update(ctx, |item, ctx| item.save(ctx))
     }
 
@@ -240,15 +240,14 @@ impl WorkspaceView {
     pub fn save_active_item(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
         self.active_pane.update(ctx, |pane, ctx| {
             if let Some(item) = pane.active_item() {
-                if let Some(task) = item.save(ctx.app_mut()) {
-                    ctx.spawn(task, |_, result, _| {
-                        if let Err(e) = result {
-                            // TODO - present this error to the user
-                            error!("failed to save item: {:?}, ", e);
-                        }
-                    })
-                    .detach();
-                }
+                let task = item.save(ctx.app_mut());
+                ctx.spawn(task, |_, result, _| {
+                    if let Err(e) = result {
+                        // TODO - present this error to the user
+                        error!("failed to save item: {:?}, ", e);
+                    }
+                })
+                .detach()
             }
         });
     }