aboutsummaryrefslogtreecommitdiff
path: root/helix-view/src/document.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-view/src/document.rs')
-rw-r--r--helix-view/src/document.rs69
1 files changed, 54 insertions, 15 deletions
diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs
index 13ffe794..db12fb92 100644
--- a/helix-view/src/document.rs
+++ b/helix-view/src/document.rs
@@ -9,6 +9,7 @@ use helix_core::text_annotations::TextAnnotations;
use helix_core::Range;
use helix_vcs::{DiffHandle, DiffProviderRegistry};
+use ::parking_lot::Mutex;
use serde::de::{self, Deserialize, Deserializer};
use serde::Serialize;
use std::borrow::Cow;
@@ -18,7 +19,7 @@ use std::fmt::Display;
use std::future::Future;
use std::path::{Path, PathBuf};
use std::str::FromStr;
-use std::sync::Arc;
+use std::sync::{Arc, Weak};
use std::time::SystemTime;
use helix_core::{
@@ -105,6 +106,13 @@ pub struct DocumentSavedEvent {
pub type DocumentSavedEventResult = Result<DocumentSavedEvent, anyhow::Error>;
pub type DocumentSavedEventFuture = BoxFuture<'static, DocumentSavedEventResult>;
+#[derive(Debug)]
+pub struct SavePoint {
+ /// The view this savepoint is associated with
+ pub view: ViewId,
+ revert: Mutex<Transaction>,
+}
+
pub struct Document {
pub(crate) id: DocumentId,
text: Rope,
@@ -136,7 +144,7 @@ pub struct Document {
pub history: Cell<History>,
pub config: Arc<dyn DynAccess<Config>>,
- pub savepoint: Option<Transaction>,
+ savepoints: Vec<Weak<SavePoint>>,
// Last time we wrote to the file. This will carry the time the file was last opened if there
// were no saves.
@@ -389,7 +397,7 @@ impl Document {
diagnostics: Vec::new(),
version: 0,
history: Cell::new(History::default()),
- savepoint: None,
+ savepoints: Vec::new(),
last_saved_time: SystemTime::now(),
last_saved_revision: 0,
modified_since_accessed: false,
@@ -846,11 +854,18 @@ impl Document {
}
// generate revert to savepoint
- if self.savepoint.is_some() {
- take_with(&mut self.savepoint, |prev_revert| {
- let revert = transaction.invert(&old_doc);
- Some(revert.compose(prev_revert.unwrap()))
- });
+ if !self.savepoints.is_empty() {
+ let revert = transaction.invert(&old_doc);
+ self.savepoints
+ .retain_mut(|save_point| match save_point.upgrade() {
+ Some(savepoint) => {
+ let mut revert_to_savepoint = savepoint.revert.lock();
+ *revert_to_savepoint =
+ revert.clone().compose(mem::take(&mut revert_to_savepoint));
+ true
+ }
+ None => false,
+ })
}
// update tree-sitter syntax tree
@@ -940,15 +955,39 @@ impl Document {
self.undo_redo_impl(view, false)
}
- pub fn savepoint(&mut self) {
- self.savepoint =
- Some(Transaction::new(self.text()).with_selection(self.selection(view.id).clone()));
+ /// Creates a reference counted snapshot (called savpepoint) of the document.
+ ///
+ /// The snapshot will remain valid (and updated) idenfinitly as long as ereferences to it exist.
+ /// Restoring the snapshot will restore the selection and the contents of the document to
+ /// the state it had when this function was called.
+ pub fn savepoint(&mut self, view: &View) -> Arc<SavePoint> {
+ let revert = Transaction::new(self.text()).with_selection(self.selection(view.id).clone());
+ let savepoint = Arc::new(SavePoint {
+ view: view.id,
+ revert: Mutex::new(revert),
+ });
+ self.savepoints.push(Arc::downgrade(&savepoint));
+ savepoint
}
- pub fn restore(&mut self, view: &mut View) {
- if let Some(revert) = self.savepoint.take() {
- self.apply(&revert, view.id);
- }
+ pub fn restore(&mut self, view: &mut View, savepoint: &SavePoint) {
+ assert_eq!(
+ savepoint.view, view.id,
+ "Savepoint must not be used with a different view!"
+ );
+ // search and remove savepoint using a ptr comparison
+ // this avoids a deadlock as we need to lock the mutex
+ let savepoint_idx = self
+ .savepoints
+ .iter()
+ .position(|savepoint_ref| savepoint_ref.as_ptr() == savepoint as *const _)
+ .expect("Savepoint must belong to this document");
+
+ let savepoint_ref = self.savepoints.remove(savepoint_idx);
+ let mut revert = savepoint.revert.lock();
+ self.apply(&revert, view.id);
+ *revert = Transaction::new(self.text()).with_selection(self.selection(view.id).clone());
+ self.savepoints.push(savepoint_ref)
}
fn earlier_later_impl(&mut self, view: &mut View, uk: UndoKind, earlier: bool) -> bool {