@@ -9,6 +9,7 @@ use helix_core::text_annotations::TextAnnotations;
99use helix_core::Range;
1010use helix_vcs::{DiffHandle, DiffProviderRegistry};
1111
12+use ::parking_lot::Mutex;
1213use serde::de::{self, Deserialize, Deserializer};
1314use serde::Serialize;
1415use std::borrow::Cow;
@@ -18,7 +19,7 @@ use std::fmt::Display;
1819use std::future::Future;
1920use std::path::{Path, PathBuf};
2021use std::str::FromStr;
21−use std::sync::Arc;
22+use std::sync::{Arc, Weak};
2223use std::time::SystemTime;
2324
2425use helix_core::{
@@ -105,6 +106,13 @@ pub struct DocumentSavedEvent {
105106pub type DocumentSavedEventResult = Result<DocumentSavedEvent, anyhow::Error>;
106107pub type DocumentSavedEventFuture = BoxFuture<'static, DocumentSavedEventResult>;
107108
109+#[derive(Debug)]
110+pub struct SavePoint {
111+ /// The view this savepoint is associated with
112+ pub view: ViewId,
113+ revert: Mutex<Transaction>,
114+}
115+
108116pub struct Document {
109117 pub(crate) id: DocumentId,
110118 text: Rope,
@@ -136,7 +144,7 @@ pub struct Document {
136144 pub history: Cell<History>,
137145 pub config: Arc<dyn DynAccess<Config>>,
138146
139− pub savepoint: Option<Transaction>,
147+ savepoints: Vec<Weak<SavePoint>>,
140148
141149 // Last time we wrote to the file. This will carry the time the file was last opened if there
142150 // were no saves.
@@ -389,7 +397,7 @@ impl Document {
389397 diagnostics: Vec::new(),
390398 version: 0,
391399 history: Cell::new(History::default()),
392− savepoint: None,
400+ savepoints: Vec::new(),
393401 last_saved_time: SystemTime::now(),
394402 last_saved_revision: 0,
395403 modified_since_accessed: false,
@@ -846,11 +854,18 @@ impl Document {
846854 }
847855
848856 // generate revert to savepoint
849− if self.savepoint.is_some() {
850− take_with(&mut self.savepoint, |prev_revert| {
851− let revert = transaction.invert(&old_doc);
852− Some(revert.compose(prev_revert.unwrap()))
853− });
857+ if !self.savepoints.is_empty() {
858+ let revert = transaction.invert(&old_doc);
859+ self.savepoints
860+ .retain_mut(|save_point| match save_point.upgrade() {
861+ Some(savepoint) => {
862+ let mut revert_to_savepoint = savepoint.revert.lock();
863+ *revert_to_savepoint =
864+ revert.clone().compose(mem::take(&mut revert_to_savepoint));
865+ true
866+ }
867+ None => false,
868+ })
854869 }
855870
856871 // update tree-sitter syntax tree
@@ -940,15 +955,39 @@ impl Document {
940955 self.undo_redo_impl(view, false)
941956 }
942957
943− pub fn savepoint(&mut self) {
944− self.savepoint =
945− Some(Transaction::new(self.text()).with_selection(self.selection(view.id).clone()));
958+ /// Creates a reference counted snapshot (called savpepoint) of the document.
959+ ///
960+ /// The snapshot will remain valid (and updated) idenfinitly as long as ereferences to it exist.
961+ /// Restoring the snapshot will restore the selection and the contents of the document to
962+ /// the state it had when this function was called.
963+ pub fn savepoint(&mut self, view: &View) -> Arc<SavePoint> {
964+ let revert = Transaction::new(self.text()).with_selection(self.selection(view.id).clone());
965+ let savepoint = Arc::new(SavePoint {
966+ view: view.id,
967+ revert: Mutex::new(revert),
968+ });
969+ self.savepoints.push(Arc::downgrade(&savepoint));
970+ savepoint
946971 }
947972
948− pub fn restore(&mut self, view: &mut View) {
949− if let Some(revert) = self.savepoint.take() {
950− self.apply(&revert, view.id);
951− }
973+ pub fn restore(&mut self, view: &mut View, savepoint: &SavePoint) {
974+ assert_eq!(
975+ savepoint.view, view.id,
976+ "Savepoint must not be used with a different view!"
977+ );
978+ // search and remove savepoint using a ptr comparison
979+ // this avoids a deadlock as we need to lock the mutex
980+ let savepoint_idx = self
981+ .savepoints
982+ .iter()
983+ .position(|savepoint_ref| savepoint_ref.as_ptr() == savepoint as *const _)
984+ .expect("Savepoint must belong to this document");
985+
986+ let savepoint_ref = self.savepoints.remove(savepoint_idx);
987+ let mut revert = savepoint.revert.lock();
988+ self.apply(&revert, view.id);
989+ *revert = Transaction::new(self.text()).with_selection(self.selection(view.id).clone());
990+ self.savepoints.push(savepoint_ref)
952991 }
953992
954993 fn earlier_later_impl(&mut self, view: &mut View, uk: UndoKind, earlier: bool) -> bool {