summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helix-core/src/state.rs7
-rw-r--r--helix-core/src/transaction.rs24
-rw-r--r--helix-view/src/commands.rs28
3 files changed, 40 insertions, 19 deletions
diff --git a/helix-core/src/state.rs b/helix-core/src/state.rs
index d8aa3ed4..fde6a866 100644
--- a/helix-core/src/state.rs
+++ b/helix-core/src/state.rs
@@ -25,7 +25,8 @@ pub struct State {
//
pub syntax: Option<Syntax>,
- pub changes: Option<ChangeSet>,
+ /// 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 dfb1bbe1..86fc0bc8 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<T, F>(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 aafc6202..e5e3244d 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()));
}