Separate document history into Cell

As history is used separately from the rest of the edits, separating it
can avoid needless borrowing and cloning. But one need to be aware later.
imgbot
Ivan Tham 4 years ago
parent 0a6672c626
commit f5f46b1fed

@ -65,9 +65,7 @@ impl History {
self.cursor == 0 self.cursor == 0
} }
// TODO: I'd like to pass Transaction by reference but it fights with the borrowck pub fn undo(&mut self) -> Option<&Transaction> {
pub fn undo(&mut self) -> Option<Transaction> {
if self.at_root() { if self.at_root() {
// We're at the root of undo, nothing to do. // We're at the root of undo, nothing to do.
return None; return None;
@ -77,17 +75,17 @@ impl History {
self.cursor = current_revision.parent; self.cursor = current_revision.parent;
Some(current_revision.revert.clone()) Some(&current_revision.revert)
} }
pub fn redo(&mut self) -> Option<Transaction> { pub fn redo(&mut self) -> Option<&Transaction> {
let current_revision = &self.revisions[self.cursor]; let current_revision = &self.revisions[self.cursor];
// for now, simply pick the latest child (linear undo / redo) // for now, simply pick the latest child (linear undo / redo)
if let Some((index, transaction)) = current_revision.children.last() { if let Some((index, transaction)) = current_revision.children.last() {
self.cursor = *index; self.cursor = *index;
return Some(transaction.clone()); return Some(&transaction);
} }
None None
} }

@ -415,7 +415,7 @@ impl ChangeSet {
/// Transaction represents a single undoable unit of changes. Several changes can be grouped into /// Transaction represents a single undoable unit of changes. Several changes can be grouped into
/// a single transaction. /// a single transaction.
#[derive(Debug, Clone)] #[derive(Debug, Default, Clone)]
pub struct Transaction { pub struct Transaction {
changes: ChangeSet, changes: ChangeSet,
selection: Option<Selection>, selection: Option<Selection>,

@ -1,4 +1,5 @@
use anyhow::{Context, Error}; use anyhow::{Context, Error};
use std::cell::Cell;
use std::future::Future; use std::future::Future;
use std::path::{Component, Path, PathBuf}; use std::path::{Component, Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
@ -40,7 +41,10 @@ pub struct Document {
/// State at last commit. Used for calculating reverts. /// State at last commit. Used for calculating reverts.
old_state: Option<State>, old_state: Option<State>,
/// Undo tree. /// Undo tree.
history: History, // It can be used as a cell where we will take it out to get some parts of the history and put
// it back as it separated from the edits. We could split out the parts manually but that will
// be more troublesome.
history: Cell<History>,
last_saved_revision: usize, last_saved_revision: usize,
version: i32, // should be usize? version: i32, // should be usize?
@ -121,7 +125,7 @@ impl Document {
old_state, old_state,
diagnostics: Vec::new(), diagnostics: Vec::new(),
version: 0, version: 0,
history: History::default(), history: Cell::new(History::default()),
last_saved_revision: 0, last_saved_revision: 0,
language_server: None, language_server: None,
} }
@ -190,7 +194,9 @@ impl Document {
let language_server = self.language_server.clone(); let language_server = self.language_server.clone();
// reset the modified flag // reset the modified flag
self.last_saved_revision = self.history.current_revision(); let history = self.history.take();
self.last_saved_revision = history.current_revision();
self.history.set(history);
async move { async move {
use tokio::{fs::File, io::AsyncWriteExt}; use tokio::{fs::File, io::AsyncWriteExt};
@ -335,7 +341,8 @@ impl Document {
} }
pub fn undo(&mut self, view_id: ViewId) -> bool { pub fn undo(&mut self, view_id: ViewId) -> bool {
if let Some(transaction) = self.history.undo() { let mut history = self.history.take();
if let Some(transaction) = history.undo() {
let success = self._apply(&transaction, view_id); let success = self._apply(&transaction, view_id);
// reset changeset to fix len // reset changeset to fix len
@ -343,11 +350,13 @@ impl Document {
return success; return success;
} }
self.history.set(history);
false false
} }
pub fn redo(&mut self, view_id: ViewId) -> bool { pub fn redo(&mut self, view_id: ViewId) -> bool {
if let Some(transaction) = self.history.redo() { let mut history = self.history.take();
if let Some(transaction) = history.redo() {
let success = self._apply(&transaction, view_id); let success = self._apply(&transaction, view_id);
// reset changeset to fix len // reset changeset to fix len
@ -355,6 +364,7 @@ impl Document {
return success; return success;
} }
self.history.set(history);
false false
} }
@ -373,7 +383,9 @@ impl Document {
// HAXX: we need to reconstruct the state as it was before the changes.. // HAXX: we need to reconstruct the state as it was before the changes..
let old_state = self.old_state.take().expect("no old_state available"); let old_state = self.old_state.take().expect("no old_state available");
self.history.commit_revision(&transaction, &old_state); let mut history = self.history.take();
history.commit_revision(&transaction, &old_state);
self.history.set(history);
} }
#[inline] #[inline]
@ -383,9 +395,11 @@ impl Document {
#[inline] #[inline]
pub fn is_modified(&self) -> bool { pub fn is_modified(&self) -> bool {
let history = self.history.take();
let current_revision = history.current_revision();
self.history.set(history);
self.path.is_some() self.path.is_some()
&& (self.history.current_revision() != self.last_saved_revision && (current_revision != self.last_saved_revision || !self.changes.is_empty())
|| !self.changes.is_empty())
} }
#[inline] #[inline]

Loading…
Cancel
Save