From 056a19a003a290b7914c7b442ebd640b93eaba0c Mon Sep 17 00:00:00 2001
From: Michael Davis <mcarsondavis@gmail.com>
Date: Sun, 27 Nov 2022 10:45:17 -0600
Subject: [PATCH] Sync changes between doc and view on switch

---
 helix-view/src/editor.rs |  7 ++++++-
 helix-view/src/view.rs   | 40 ++++++++++++++++++++++++++++++++++++----
 2 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs
index 6eaa89aa..e54c7497 100644
--- a/helix-view/src/editor.rs
+++ b/helix-view/src/editor.rs
@@ -959,7 +959,8 @@ impl Editor {
     fn _refresh(&mut self) {
         let config = self.config();
         for (view, _) in self.tree.views_mut() {
-            let doc = &self.documents[&view.doc];
+            let doc = doc_mut!(self, &view.doc);
+            view.sync_changes(doc);
             view.ensure_cursor_in_view(doc, config.scrolloff)
         }
     }
@@ -971,6 +972,7 @@ impl Editor {
 
         let doc = doc_mut!(self, &doc_id);
         doc.ensure_view_init(view.id);
+        view.sync_changes(doc);
 
         align_view(doc, view, Align::Center);
     }
@@ -1239,6 +1241,9 @@ impl Editor {
         // within view
         if prev_id != view_id {
             self.mode = Mode::Normal;
+            let view = view_mut!(self, view_id);
+            let doc = doc_mut!(self, &view.doc);
+            view.sync_changes(doc);
             self.ensure_cursor_in_view(view_id);
         }
     }
diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs
index c917a1ab..845a5458 100644
--- a/helix-view/src/view.rs
+++ b/helix-view/src/view.rs
@@ -3,7 +3,10 @@ use helix_core::{
     pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction,
 };
 
-use std::{collections::VecDeque, fmt};
+use std::{
+    collections::{HashMap, VecDeque},
+    fmt,
+};
 
 const JUMP_LIST_CAPACITY: usize = 30;
 
@@ -102,6 +105,11 @@ pub struct View {
     pub object_selections: Vec<Selection>,
     /// GutterTypes used to fetch Gutter (constructor) and width for rendering
     gutters: Vec<GutterType>,
+    /// A mapping between documents and the last history revision the view was updated at.
+    /// Changes between documents and views are synced lazily when switching windows. This
+    /// mapping keeps track of the last applied history revision so that only new changes
+    /// are applied.
+    doc_revisions: HashMap<DocumentId, usize>,
 }
 
 impl fmt::Debug for View {
@@ -126,6 +134,7 @@ impl View {
             last_modified_docs: [None, None],
             object_selections: Vec::new(),
             gutters: gutter_types,
+            doc_revisions: HashMap::new(),
         }
     }
 
@@ -349,10 +358,33 @@ impl View {
     /// Applies a [`Transaction`] to the view.
     /// Instead of calling this function directly, use [crate::apply_transaction]
     /// which applies a transaction to the [`Document`] and view together.
-    pub fn apply(&mut self, transaction: &Transaction, doc: &Document) -> bool {
+    pub fn apply(&mut self, transaction: &Transaction, doc: &mut Document) {
         self.jumps.apply(transaction, doc);
-        // TODO: remove the boolean return. This is unused.
-        true
+        self.doc_revisions
+            .insert(doc.id(), doc.get_current_revision());
+    }
+
+    pub fn sync_changes(&mut self, doc: &mut Document) {
+        let latest_revision = doc.get_current_revision();
+        let current_revision = *self
+            .doc_revisions
+            .entry(doc.id())
+            .or_insert(latest_revision);
+
+        if current_revision == latest_revision {
+            return;
+        }
+
+        log::debug!(
+            "Syncing view {:?} between {} and {}",
+            self.id,
+            current_revision,
+            latest_revision
+        );
+
+        if let Some(transaction) = doc.history.get_mut().changes_since(current_revision) {
+            self.apply(&transaction, doc);
+        }
     }
 }