@@ -9,6 +9,7 @@ use helix_core::text_annotations::TextAnnotations;
9use helix_core::Range;
9use helix_core::Range;
10use helix_vcs::{DiffHandle, DiffProviderRegistry};
10use helix_vcs::{DiffHandle, DiffProviderRegistry};
12+use ::parking_lot::Mutex;
12use serde::de::{self, Deserialize, Deserializer};
13use serde::de::{self, Deserialize, Deserializer};
13use serde::Serialize;
14use serde::Serialize;
14use std::borrow::Cow;
15use std::borrow::Cow;
@@ -18,7 +19,7 @@ use std::fmt::Display;
18use std::future::Future;
19use std::future::Future;
19use std::path::{Path, PathBuf};
20use std::path::{Path, PathBuf};
20use std::str::FromStr;
21use std::str::FromStr;
21−use std::sync::Arc;
22+use std::sync::{Arc, Weak};
22use std::time::SystemTime;
23use std::time::SystemTime;
24use helix_core::{
25use helix_core::{
@@ -105,6 +106,13 @@ pub struct DocumentSavedEvent {
105pub type DocumentSavedEventResult = Result<DocumentSavedEvent, anyhow::Error>;
106pub type DocumentSavedEventResult = Result<DocumentSavedEvent, anyhow::Error>;
106pub type DocumentSavedEventFuture = BoxFuture<'static, DocumentSavedEventResult>;
107pub type DocumentSavedEventFuture = BoxFuture<'static, DocumentSavedEventResult>;
110+pub struct SavePoint {
111+ /// The view this savepoint is associated with
113+ revert: Mutex<Transaction>,
108pub struct Document {
116pub struct Document {
109 pub(crate) id: DocumentId,
117 pub(crate) id: DocumentId,
110 text: Rope,
118 text: Rope,
@@ -136,7 +144,7 @@ pub struct Document {
136 pub history: Cell<History>,
144 pub history: Cell<History>,
137 pub config: Arc<dyn DynAccess<Config>>,
145 pub config: Arc<dyn DynAccess<Config>>,
139− pub savepoint: Option<Transaction>,
147+ savepoints: Vec<Weak<SavePoint>>,
141 // Last time we wrote to the file. This will carry the time the file was last opened if there
149 // Last time we wrote to the file. This will carry the time the file was last opened if there
142 // were no saves.
150 // were no saves.
@@ -389,7 +397,7 @@ impl Document {
389 diagnostics: Vec::new(),
397 diagnostics: Vec::new(),
390 version: 0,
398 version: 0,
391 history: Cell::new(History::default()),
399 history: Cell::new(History::default()),
392− savepoint: None,
400+ savepoints: Vec::new(),
393 last_saved_time: SystemTime::now(),
401 last_saved_time: SystemTime::now(),
394 last_saved_revision: 0,
402 last_saved_revision: 0,
395 modified_since_accessed: false,
403 modified_since_accessed: false,
@@ -846,11 +854,18 @@ impl Document {
848 // generate revert to savepoint
856 // generate revert to savepoint
849− if self.savepoint.is_some() {
857+ if !self.savepoints.is_empty() {
850− take_with(&mut self.savepoint, |prev_revert| {
851− let revert = transaction.invert(&old_doc);
858+ let revert = transaction.invert(&old_doc);
852− Some(revert.compose(prev_revert.unwrap()))
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));
856 // update tree-sitter syntax tree
871 // update tree-sitter syntax tree
@@ -940,15 +955,39 @@ impl Document {
940 self.undo_redo_impl(view, false)
955 self.undo_redo_impl(view, false)
958+ /// Creates a reference counted snapshot (called savpepoint) of the document.
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.
943− pub fn savepoint(&mut self) {
963+ pub fn savepoint(&mut self, view: &View) -> Arc<SavePoint> {
945− Some(Transaction::new(self.text()).with_selection(self.selection(view.id).clone()));
964+ let revert = Transaction::new(self.text()).with_selection(self.selection(view.id).clone());
965+ let savepoint = Arc::new(SavePoint {
967+ revert: Mutex::new(revert),
969+ self.savepoints.push(Arc::downgrade(&savepoint));
948− pub fn restore(&mut self, view: &mut View) {
973+ pub fn restore(&mut self, view: &mut View, savepoint: &SavePoint) {
949− if let Some(revert) = self.savepoint.take() {
974+ assert_eq!(
975+ savepoint.view, view.id,
976+ "Savepoint must not be used with a different view!"
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
983+ .position(|savepoint_ref| savepoint_ref.as_ptr() == savepoint as *const _)
984+ .expect("Savepoint must belong to this document");
986+ let savepoint_ref = self.savepoints.remove(savepoint_idx);
987+ let mut revert = savepoint.revert.lock();
950− self.apply(&revert, view.id);
988+ self.apply(&revert, view.id);
951− }
989+ *revert = Transaction::new(self.text()).with_selection(self.selection(view.id).clone());
990+ self.savepoints.push(savepoint_ref)
954 fn earlier_later_impl(&mut self, view: &mut View, uk: UndoKind, earlier: bool) -> bool {
993 fn earlier_later_impl(&mut self, view: &mut View, uk: UndoKind, earlier: bool) -> bool {