Implement `MultiBuffer::{is_dirty,has_conflict}`

Antonio Scandurra created

Change summary

crates/diagnostics/src/diagnostics.rs | 21 ++++++++++++++++++++-
crates/editor/src/editor.rs           |  1 +
crates/editor/src/items.rs            |  4 ++--
crates/editor/src/multi_buffer.rs     | 25 +++++++++++++++++--------
4 files changed, 40 insertions(+), 11 deletions(-)

Detailed changes

crates/diagnostics/src/diagnostics.rs 🔗

@@ -20,6 +20,8 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(ProjectDiagnosticsEditor::toggle);
 }
 
+type Event = editor::Event;
+
 struct ProjectDiagnostics {
     project: ModelHandle<Project>,
 }
@@ -41,7 +43,7 @@ impl Entity for ProjectDiagnostics {
 }
 
 impl Entity for ProjectDiagnosticsEditor {
-    type Event = ();
+    type Event = Event;
 }
 
 impl View for ProjectDiagnosticsEditor {
@@ -68,6 +70,8 @@ impl ProjectDiagnosticsEditor {
         let build_settings = editor::settings_builder(excerpts.downgrade(), settings.clone());
         let editor =
             cx.add_view(|cx| Editor::for_buffer(excerpts.clone(), build_settings.clone(), cx));
+        cx.subscribe(&editor, |_, _, event, cx| cx.emit(*event))
+            .detach();
         Self {
             excerpts,
             editor,
@@ -240,6 +244,21 @@ impl workspace::ItemView for ProjectDiagnosticsEditor {
     ) -> gpui::Task<anyhow::Result<()>> {
         todo!()
     }
+
+    fn is_dirty(&self, cx: &AppContext) -> bool {
+        self.excerpts.read(cx).read(cx).is_dirty()
+    }
+
+    fn has_conflict(&self, cx: &AppContext) -> bool {
+        self.excerpts.read(cx).read(cx).has_conflict()
+    }
+
+    fn should_update_tab_on_event(event: &Event) -> bool {
+        matches!(
+            event,
+            Event::Saved | Event::Dirtied | Event::FileHandleChanged
+        )
+    }
 }
 
 #[cfg(test)]

crates/editor/src/editor.rs 🔗

@@ -3638,6 +3638,7 @@ fn compute_scroll_position(
     scroll_position
 }
 
+#[derive(Copy, Clone)]
 pub enum Event {
     Activate,
     Edited,

crates/editor/src/items.rs 🔗

@@ -181,11 +181,11 @@ impl ItemView for Editor {
     }
 
     fn is_dirty(&self, cx: &AppContext) -> bool {
-        self.buffer().read(cx).is_dirty(cx)
+        self.buffer().read(cx).read(cx).is_dirty()
     }
 
     fn has_conflict(&self, cx: &AppContext) -> bool {
-        self.buffer().read(cx).has_conflict(cx)
+        self.buffer().read(cx).read(cx).has_conflict()
     }
 }
 

crates/editor/src/multi_buffer.rs 🔗

@@ -82,6 +82,8 @@ pub struct MultiBufferSnapshot {
     excerpts: SumTree<Excerpt>,
     parse_count: usize,
     diagnostics_update_count: usize,
+    is_dirty: bool,
+    has_conflict: bool,
 }
 
 pub type RenderHeaderFn = Arc<dyn 'static + Send + Sync + Fn(&AppContext) -> ElementBox>;
@@ -681,14 +683,6 @@ impl MultiBuffer {
         self.as_singleton().unwrap().read(cx).file()
     }
 
-    pub fn is_dirty(&self, cx: &AppContext) -> bool {
-        self.as_singleton().unwrap().read(cx).is_dirty()
-    }
-
-    pub fn has_conflict(&self, cx: &AppContext) -> bool {
-        self.as_singleton().unwrap().read(cx).has_conflict()
-    }
-
     #[cfg(test)]
     pub fn is_parsing(&self, cx: &AppContext) -> bool {
         self.as_singleton().unwrap().read(cx).is_parsing()
@@ -699,6 +693,8 @@ impl MultiBuffer {
         let mut excerpts_to_edit = Vec::new();
         let mut reparsed = false;
         let mut diagnostics_updated = false;
+        let mut is_dirty = false;
+        let mut has_conflict = false;
         for buffer_state in self.buffers.values() {
             let buffer = buffer_state.buffer.read(cx);
             let buffer_edited = buffer.version().gt(&buffer_state.last_version);
@@ -716,6 +712,8 @@ impl MultiBuffer {
 
             reparsed |= buffer_reparsed;
             diagnostics_updated |= buffer_diagnostics_updated;
+            is_dirty |= buffer.is_dirty();
+            has_conflict |= buffer.has_conflict();
         }
         if reparsed {
             snapshot.parse_count += 1;
@@ -723,6 +721,9 @@ impl MultiBuffer {
         if diagnostics_updated {
             snapshot.diagnostics_update_count += 1;
         }
+        snapshot.is_dirty = is_dirty;
+        snapshot.has_conflict = has_conflict;
+
         excerpts_to_edit.sort_unstable_by_key(|(excerpt_id, _, _)| *excerpt_id);
 
         let mut edits = Vec::new();
@@ -1493,6 +1494,14 @@ impl MultiBufferSnapshot {
             .and_then(|excerpt| excerpt.buffer.language())
     }
 
+    pub fn is_dirty(&self) -> bool {
+        self.is_dirty
+    }
+
+    pub fn has_conflict(&self) -> bool {
+        self.has_conflict
+    }
+
     pub fn diagnostic_group<'a, O>(
         &'a self,
         group_id: usize,