diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 2db5bfcf..e2bd9402 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -860,6 +860,7 @@ fn align_selections(cx: &mut Context) {
 
     let transaction = Transaction::change(doc.text(), changes.into_iter());
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
 }
 
 fn goto_window(cx: &mut Context, align: Align) {
@@ -1290,6 +1291,7 @@ fn replace(cx: &mut Context) {
             });
 
             doc.apply(&transaction, view.id);
+            view.apply(&transaction, doc);
         }
     })
 }
@@ -1307,6 +1309,7 @@ where
     });
 
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
 }
 
 fn switch_case(cx: &mut Context) {
@@ -2113,6 +2116,7 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) {
         (range.from(), range.to(), None)
     });
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
 
     match op {
         Operation::Delete => {
@@ -2126,7 +2130,7 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) {
 }
 
 #[inline]
-fn delete_selection_insert_mode(doc: &mut Document, view: &View, selection: &Selection) {
+fn delete_selection_insert_mode(doc: &mut Document, view: &mut View, selection: &Selection) {
     let view_id = view.id;
 
     // then delete
@@ -2134,6 +2138,7 @@ fn delete_selection_insert_mode(doc: &mut Document, view: &View, selection: &Sel
         (range.from(), range.to(), None)
     });
     doc.apply(&transaction, view_id);
+    view.apply(&transaction, doc);
 }
 
 fn delete_selection(cx: &mut Context) {
@@ -2230,6 +2235,7 @@ fn append_mode(cx: &mut Context) {
             [(end, end, Some(doc.line_ending.as_str().into()))].into_iter(),
         );
         doc.apply(&transaction, view.id);
+        view.apply(&transaction, doc);
     }
 
     let selection = doc.selection(view.id).clone().transform(|range| {
@@ -2530,6 +2536,7 @@ async fn make_format_callback(
         let view = view_mut!(editor);
         if doc.version() == doc_version {
             doc.apply(&format, view.id);
+            view.apply(&format, doc);
             doc.append_changes_to_history(view.id);
             doc.detect_indent_and_line_ending();
             view.ensure_cursor_in_view(doc, scrolloff);
@@ -2617,6 +2624,7 @@ fn open(cx: &mut Context, open: Open) {
     transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index()));
 
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
 }
 
 // o inserts a new line after each line with a selection
@@ -2637,7 +2645,7 @@ fn normal_mode(cx: &mut Context) {
     cx.editor.mode = Mode::Normal;
     let (view, doc) = current!(cx.editor);
 
-    try_restore_indent(doc, view.id);
+    try_restore_indent(doc, view);
 
     // if leaving append mode, move cursor back by 1
     if doc.restore_cursor {
@@ -2654,7 +2662,7 @@ fn normal_mode(cx: &mut Context) {
     }
 }
 
-fn try_restore_indent(doc: &mut Document, view_id: ViewId) {
+fn try_restore_indent(doc: &mut Document, view: &mut View) {
     use helix_core::chars::char_is_whitespace;
     use helix_core::Operation;
 
@@ -2673,18 +2681,19 @@ fn try_restore_indent(doc: &mut Document, view_id: ViewId) {
 
     let doc_changes = doc.changes().changes();
     let text = doc.text().slice(..);
-    let range = doc.selection(view_id).primary();
+    let range = doc.selection(view.id).primary();
     let pos = range.cursor(text);
     let line_end_pos = line_end_char_index(&text, range.cursor_line(text));
 
     if inserted_a_new_blank_line(doc_changes, pos, line_end_pos) {
         // Removes tailing whitespaces.
         let transaction =
-            Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
+            Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
                 let line_start_pos = text.line_to_char(range.cursor_line(text));
                 (line_start_pos, pos, None)
             });
-        doc.apply(&transaction, view_id);
+        doc.apply(&transaction, view.id);
+        view.apply(&transaction, doc);
     }
 }
 
@@ -2999,6 +3008,7 @@ pub mod insert {
         let (view, doc) = current!(cx.editor);
         if let Some(t) = transaction {
             doc.apply(&t, view.id);
+            view.apply(&t, doc);
         }
 
         // TODO: need a post insert hook too for certain triggers (autocomplete, signature help, etc)
@@ -3021,6 +3031,7 @@ pub mod insert {
             indent,
         );
         doc.apply(&transaction, view.id);
+        view.apply(&transaction, doc);
     }
 
     pub fn insert_newline(cx: &mut Context) {
@@ -3108,6 +3119,7 @@ pub mod insert {
 
         let (view, doc) = current!(cx.editor);
         doc.apply(&transaction, view.id);
+        view.apply(&transaction, doc);
     }
 
     pub fn delete_char_backward(cx: &mut Context) {
@@ -3202,6 +3214,7 @@ pub mod insert {
             });
         let (view, doc) = current!(cx.editor);
         doc.apply(&transaction, view.id);
+        view.apply(&transaction, doc);
 
         lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic);
     }
@@ -3220,6 +3233,7 @@ pub mod insert {
                 )
             });
         doc.apply(&transaction, view.id);
+        view.apply(&transaction, doc);
 
         lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic);
     }
@@ -3413,7 +3427,7 @@ enum Paste {
     Cursor,
 }
 
-fn paste_impl(values: &[String], doc: &mut Document, view: &View, action: Paste, count: usize) {
+fn paste_impl(values: &[String], doc: &mut Document, view: &mut View, action: Paste, count: usize) {
     let repeat = std::iter::repeat(
         values
             .last()
@@ -3457,6 +3471,7 @@ fn paste_impl(values: &[String], doc: &mut Document, view: &View, action: Paste,
         (pos, pos, values.next())
     });
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
 }
 
 pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) {
@@ -3549,6 +3564,7 @@ fn replace_with_yanked(cx: &mut Context) {
             });
 
             doc.apply(&transaction, view.id);
+            view.apply(&transaction, doc);
         }
     }
 }
@@ -3572,6 +3588,7 @@ fn replace_selections_with_clipboard_impl(
             });
 
             doc.apply(&transaction, view.id);
+            view.apply(&transaction, doc);
             doc.append_changes_to_history(view.id);
             Ok(())
         }
@@ -3642,6 +3659,7 @@ fn indent(cx: &mut Context) {
         }),
     );
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
 }
 
 fn unindent(cx: &mut Context) {
@@ -3681,6 +3699,7 @@ fn unindent(cx: &mut Context) {
     let transaction = Transaction::change(doc.text(), changes.into_iter());
 
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
 }
 
 fn format_selections(cx: &mut Context) {
@@ -3728,6 +3747,7 @@ fn format_selections(cx: &mut Context) {
         // );
 
         // doc.apply(&transaction, view.id);
+        // view.apply(&transaction, doc);
     }
 }
 
@@ -3783,6 +3803,7 @@ fn join_selections_inner(cx: &mut Context, select_space: bool) {
     };
 
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
 }
 
 fn keep_or_remove_selections_impl(cx: &mut Context, remove: bool) {
@@ -3936,6 +3957,7 @@ fn toggle_comments(cx: &mut Context) {
     let transaction = comment::toggle_line_comments(doc.text(), doc.selection(view.id), token);
 
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
     exit_select_mode(cx);
 }
 
@@ -3992,6 +4014,7 @@ fn rotate_selection_contents(cx: &mut Context, direction: Direction) {
     );
 
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
 }
 
 fn rotate_selection_contents_forward(cx: &mut Context) {
@@ -4488,6 +4511,7 @@ fn surround_add(cx: &mut Context) {
 
         let transaction = Transaction::change(doc.text(), changes.into_iter());
         doc.apply(&transaction, view.id);
+        view.apply(&transaction, doc);
     })
 }
 
@@ -4527,6 +4551,7 @@ fn surround_replace(cx: &mut Context) {
                 }),
             );
             doc.apply(&transaction, view.id);
+            view.apply(&transaction, doc);
         });
     })
 }
@@ -4554,6 +4579,7 @@ fn surround_delete(cx: &mut Context) {
         let transaction =
             Transaction::change(doc.text(), change_pos.into_iter().map(|p| (p, p + 1, None)));
         doc.apply(&transaction, view.id);
+        view.apply(&transaction, doc);
     })
 }
 
@@ -4729,6 +4755,7 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
     if behavior != &ShellBehavior::Ignore {
         let transaction = Transaction::change(doc.text(), changes.into_iter());
         doc.apply(&transaction, view.id);
+        view.apply(&transaction, doc);
         doc.append_changes_to_history(view.id);
     }
 
@@ -4792,6 +4819,7 @@ fn add_newline_impl(cx: &mut Context, open: Open) {
 
     let transaction = Transaction::change(text, changes);
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
 }
 
 /// Increment object under cursor by count.
@@ -4885,6 +4913,7 @@ fn increment_impl(cx: &mut Context, amount: i64) {
         let transaction = transaction.with_selection(selection.clone());
 
         doc.apply(&transaction, view.id);
+        view.apply(&transaction, doc);
     }
 }
 
diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs
index 1113b44e..726aec67 100644
--- a/helix-term/src/commands/lsp.rs
+++ b/helix-term/src/commands/lsp.rs
@@ -596,9 +596,7 @@ pub fn apply_workspace_edit(
             }
         };
 
-        let doc = editor
-            .document_mut(doc_id)
-            .expect("Document for document_changes not found");
+        let doc = doc_mut!(editor, &doc_id);
 
         // Need to determine a view for apply/append_changes_to_history
         let selections = doc.selections();
@@ -620,6 +618,7 @@ pub fn apply_workspace_edit(
             offset_encoding,
         );
         doc.apply(&transaction, view_id);
+        view_mut!(editor, view_id).apply(&transaction, doc);
         doc.append_changes_to_history(view_id);
     };
 
diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs
index 96ff75c5..574e895b 100644
--- a/helix-term/src/commands/typed.rs
+++ b/helix-term/src/commands/typed.rs
@@ -463,6 +463,7 @@ fn set_line_ending(
         }),
     );
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
     doc.append_changes_to_history(view.id);
 
     Ok(())
@@ -884,6 +885,7 @@ fn replace_selections_with_clipboard_impl(
             });
 
             doc.apply(&transaction, view.id);
+            view.apply(&transaction, doc);
             doc.append_changes_to_history(view.id);
             Ok(())
         }
@@ -1004,7 +1006,7 @@ fn reload(
 
     let scrolloff = cx.editor.config().scrolloff;
     let (view, doc) = current!(cx.editor);
-    doc.reload(view.id).map(|_| {
+    doc.reload(view).map(|_| {
         view.ensure_cursor_in_view(doc, scrolloff);
     })
 }
@@ -1399,6 +1401,7 @@ fn sort_impl(
     );
 
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
     doc.append_changes_to_history(view.id);
 
     Ok(())
@@ -1443,6 +1446,7 @@ fn reflow(
     });
 
     doc.apply(&transaction, view.id);
+    view.apply(&transaction, doc);
     doc.append_changes_to_history(view.id);
     view.ensure_cursor_in_view(doc, scrolloff);
 
diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs
index 2d7d4f92..c0a5da2e 100644
--- a/helix-term/src/ui/completion.rs
+++ b/helix-term/src/ui/completion.rs
@@ -143,11 +143,11 @@ impl Completion {
             let (view, doc) = current!(editor);
 
             // if more text was entered, remove it
-            doc.restore(view.id);
+            doc.restore(view);
 
             match event {
                 PromptEvent::Abort => {
-                    doc.restore(view.id);
+                    doc.restore(view);
                     editor.last_completion = None;
                 }
                 PromptEvent::Update => {
@@ -165,6 +165,7 @@ impl Completion {
                     // initialize a savepoint
                     doc.savepoint();
                     doc.apply(&transaction, view.id);
+                    view.apply(&transaction, doc);
 
                     editor.last_completion = Some(CompleteAction {
                         trigger_offset,
@@ -184,6 +185,7 @@ impl Completion {
                     );
 
                     doc.apply(&transaction, view.id);
+                    view.apply(&transaction, doc);
 
                     editor.last_completion = Some(CompleteAction {
                         trigger_offset,
@@ -214,6 +216,7 @@ impl Completion {
                                 offset_encoding, // TODO: should probably transcode in Client
                             );
                             doc.apply(&transaction, view.id);
+                            view.apply(&transaction, doc);
                         }
                     }
                 }
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index 18e1271f..3b71748b 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -988,7 +988,7 @@ impl EditorView {
                         InsertEvent::CompletionApply(compl) => {
                             let (view, doc) = current!(cxt.editor);
 
-                            doc.restore(view.id);
+                            doc.restore(view);
 
                             let text = doc.text().slice(..);
                             let cursor = doc.selection(view.id).primary().cursor(text);
@@ -1003,6 +1003,7 @@ impl EditorView {
                                 }),
                             );
                             doc.apply(&tx, view.id);
+                            view.apply(&tx, doc);
                         }
                         InsertEvent::TriggerCompletion => {
                             let (_, doc) = current!(cxt.editor);
diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs
index b6b2f664..631c540b 100644
--- a/helix-view/src/document.rs
+++ b/helix-view/src/document.rs
@@ -24,7 +24,7 @@ use helix_core::{
     DEFAULT_LINE_ENDING,
 };
 
-use crate::{DocumentId, Editor, ViewId};
+use crate::{DocumentId, Editor, View, ViewId};
 
 /// 8kB of buffer space for encoding and decoding `Rope`s.
 const BUF_SIZE: usize = 8192;
@@ -601,7 +601,7 @@ impl Document {
     }
 
     /// Reload the document from its path.
-    pub fn reload(&mut self, view_id: ViewId) -> Result<(), Error> {
+    pub fn reload(&mut self, view: &mut View) -> Result<(), Error> {
         let encoding = &self.encoding;
         let path = self.path().filter(|path| path.exists());
 
@@ -617,8 +617,9 @@ impl Document {
         // This is not considered a modification of the contents of the file regardless
         // of the encoding.
         let transaction = helix_core::diff::compare_ropes(self.text(), &rope);
-        self.apply(&transaction, view_id);
-        self.append_changes_to_history(view_id);
+        self.apply(&transaction, view.id);
+        view.apply(&transaction, self);
+        self.append_changes_to_history(view.id);
         self.reset_modified();
 
         self.detect_indent_and_line_ending();
@@ -862,9 +863,10 @@ impl Document {
         self.savepoint = Some(Transaction::new(self.text()));
     }
 
-    pub fn restore(&mut self, view_id: ViewId) {
+    pub fn restore(&mut self, view: &mut View) {
         if let Some(revert) = self.savepoint.take() {
-            self.apply(&revert, view_id);
+            self.apply(&revert, view.id);
+            view.apply(&revert, self);
         }
     }