From 490e23b645311fef86d8e8045f97f514927d2867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Wed, 7 Oct 2020 22:22:50 +0900 Subject: [PATCH] Simplify changeset tracking. --- helix-core/src/state.rs | 7 +++++-- helix-core/src/transaction.rs | 24 +++++++++++++++++++----- helix-view/src/commands.rs | 28 ++++++++++++++++------------ 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/helix-core/src/state.rs b/helix-core/src/state.rs index d8aa3ed4c..fde6a8666 100644 --- a/helix-core/src/state.rs +++ b/helix-core/src/state.rs @@ -25,7 +25,8 @@ pub struct State { // pub syntax: Option, - pub changes: Option, + /// Pending changes since last history commit. + pub changes: ChangeSet, pub old_state: Option<(Rope, Selection)>, } @@ -45,6 +46,8 @@ pub enum Granularity { impl State { #[must_use] pub fn new(doc: Rope) -> Self { + let changes = ChangeSet::new(&doc); + Self { path: None, doc, @@ -52,7 +55,7 @@ impl State { mode: Mode::Normal, restore_cursor: false, syntax: None, - changes: None, + changes, old_state: None, } } diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index dfb1bbe1e..86fc0bc81 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -342,6 +342,22 @@ pub struct Transaction { // scroll_into_view } +/// Like std::mem::replace() except it allows the replacement value to be mapped from the +/// original value. +pub fn take_with(mut_ref: &mut T, closure: F) +where + F: FnOnce(T) -> T, +{ + use std::{panic, ptr}; + + unsafe { + let old_t = ptr::read(mut_ref); + let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| closure(old_t))) + .unwrap_or_else(|_| ::std::process::abort()); + ptr::write(mut_ref, new_t); + } +} + impl Transaction { /// Create a new, empty transaction. pub fn new(state: &mut State) -> Self { @@ -364,11 +380,9 @@ impl Transaction { } // Compose this transaction with the previous one - let old_changes = state.changes.take(); - state.changes = Some(old_changes.map_or_else( - || self.changes.clone(), - |changes| changes.compose(self.changes.clone()).unwrap(), - )); + take_with(&mut state.changes, |changes| { + changes.compose(self.changes.clone()).unwrap() + }); if let Some(syntax) = &mut state.syntax { // TODO: no unwrap diff --git a/helix-view/src/commands.rs b/helix-view/src/commands.rs index aafc6202f..e5e3244d0 100644 --- a/helix-view/src/commands.rs +++ b/helix-view/src/commands.rs @@ -368,22 +368,26 @@ pub fn open_below(view: &mut View, _count: usize) { // O inserts a new line before each line with a selection fn append_changes_to_history(view: &mut View) { - if let Some(changes) = view.state.changes.take() { - // Instead of doing this messy merge we could always commit, and based on transaction - // annotations either add a new layer or compose into the previous one. - let transaction = Transaction::from(changes).with_selection(view.state.selection().clone()); - let (doc, selection) = view.state.old_state.take().unwrap(); - let mut old_state = State::new(doc); - old_state.selection = selection; - - // TODO: take transaction by value? - view.history.commit_revision(&transaction, &old_state); + if view.state.changes.is_empty() { + return; } - // TODO: need to start the state with these vals + let new_changeset = ChangeSet::new(view.state.doc()); + let changes = std::mem::replace(&mut view.state.changes, new_changeset); + // Instead of doing this messy merge we could always commit, and based on transaction + // annotations either add a new layer or compose into the previous one. + let transaction = Transaction::from(changes).with_selection(view.state.selection().clone()); + + // HAXX: we need to reconstruct the state as it was before the changes.. + let (doc, selection) = view.state.old_state.take().unwrap(); + let mut old_state = State::new(doc); + old_state.selection = selection; + // TODO: take transaction by value? + view.history.commit_revision(&transaction, &old_state); + + // TODO: need to start the state with these vals // HAXX - view.state.changes = Some(ChangeSet::new(view.state.doc())); view.state.old_state = Some((view.state.doc().clone(), view.state.selection.clone())); }