Simplify changeset tracking.

pull/4/head
Blaž Hrastnik 4 years ago
parent 518426b9f4
commit 490e23b645

@ -25,7 +25,8 @@ pub struct State {
// //
pub syntax: Option<Syntax>, pub syntax: Option<Syntax>,
pub changes: Option<ChangeSet>, /// Pending changes since last history commit.
pub changes: ChangeSet,
pub old_state: Option<(Rope, Selection)>, pub old_state: Option<(Rope, Selection)>,
} }
@ -45,6 +46,8 @@ pub enum Granularity {
impl State { impl State {
#[must_use] #[must_use]
pub fn new(doc: Rope) -> Self { pub fn new(doc: Rope) -> Self {
let changes = ChangeSet::new(&doc);
Self { Self {
path: None, path: None,
doc, doc,
@ -52,7 +55,7 @@ impl State {
mode: Mode::Normal, mode: Mode::Normal,
restore_cursor: false, restore_cursor: false,
syntax: None, syntax: None,
changes: None, changes,
old_state: None, old_state: None,
} }
} }

@ -342,6 +342,22 @@ pub struct Transaction {
// scroll_into_view // 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 { impl Transaction {
/// Create a new, empty transaction. /// Create a new, empty transaction.
pub fn new(state: &mut State) -> Self { pub fn new(state: &mut State) -> Self {
@ -364,11 +380,9 @@ impl Transaction {
} }
// Compose this transaction with the previous one // Compose this transaction with the previous one
let old_changes = state.changes.take(); take_with(&mut state.changes, |changes| {
state.changes = Some(old_changes.map_or_else( changes.compose(self.changes.clone()).unwrap()
|| self.changes.clone(), });
|changes| changes.compose(self.changes.clone()).unwrap(),
));
if let Some(syntax) = &mut state.syntax { if let Some(syntax) = &mut state.syntax {
// TODO: no unwrap // TODO: no unwrap

@ -368,22 +368,26 @@ pub fn open_below(view: &mut View, _count: usize) {
// O inserts a new line before each line with a selection // O inserts a new line before each line with a selection
fn append_changes_to_history(view: &mut View) { fn append_changes_to_history(view: &mut View) {
if let Some(changes) = view.state.changes.take() { if view.state.changes.is_empty() {
return;
}
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 // 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. // annotations either add a new layer or compose into the previous one.
let transaction = Transaction::from(changes).with_selection(view.state.selection().clone()); 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 (doc, selection) = view.state.old_state.take().unwrap();
let mut old_state = State::new(doc); let mut old_state = State::new(doc);
old_state.selection = selection; old_state.selection = selection;
// TODO: take transaction by value? // TODO: take transaction by value?
view.history.commit_revision(&transaction, &old_state); view.history.commit_revision(&transaction, &old_state);
}
// TODO: need to start the state with these vals // TODO: need to start the state with these vals
// HAXX // HAXX
view.state.changes = Some(ChangeSet::new(view.state.doc()));
view.state.old_state = Some((view.state.doc().clone(), view.state.selection.clone())); view.state.old_state = Some((view.state.doc().clone(), view.state.selection.clone()));
} }

Loading…
Cancel
Save