diff --git a/sub_crates/backend/src/buffer.rs b/sub_crates/backend/src/buffer.rs index 25698a3..b149312 100644 --- a/sub_crates/backend/src/buffer.rs +++ b/sub_crates/backend/src/buffer.rs @@ -7,7 +7,7 @@ use std::{ use ropey::{LineType, Rope}; -use crate::{history::History, marks::MarkSet, transaction::Transaction}; +use crate::{change::Change, history::History, marks::MarkSet}; /// The line type that should be used as the standard line metric in a buffer. pub const BUFLINE: LineType = LineType::LF_CR; @@ -25,10 +25,12 @@ pub enum BufferPath { /// An open text buffer, currently being edited. #[derive(Debug, Clone)] pub struct Buffer { + pub text: Rope, // The actual text content. + pub mark_sets: Vec, // MarkSets for cursors. + pub path: BufferPath, pub edits_since_saved: i64, // Tracks whether this buffer is out of sync with the last save. - pub text: Rope, // The actual text content. - pub mark_sets: Vec, // MarkSets for cursors, view positions, etc. + history: History, } @@ -86,65 +88,65 @@ impl Buffer { (byte_idx_range.1, byte_idx_range.0) }; - // Build the transaction. - let trans = Transaction::from_edit(start, &Cow::from(self.text.slice(start..end)), text); + // Build the change. + let change = Change::from_edit(start, &Cow::from(self.text.slice(start..end)), text); // Update mark sets. for mark_set in self.mark_sets.iter_mut() { - trans.apply_to_marks(mark_set); + change.apply_to_marks(mark_set); mark_set.make_consistent(); } // Apply the edit to the document. - trans.apply(&mut self.text); + change.apply(&mut self.text); // Update undo stack. - self.history.push_edit(trans); + self.history.push_edit(change); } /// Un-does the last edit if there is one, and returns the - /// Transaction that was inverse-applied, in case it's needed for + /// Change that was inverse-applied, in case it's needed for /// further processing. /// /// Returns None if there is no edit to undo. - pub fn undo(&mut self) -> Option<&Transaction> { - if let Some(trans) = self.history.undo() { + pub fn undo(&mut self) -> Option<&Change> { + if let Some(change) = self.history.undo() { self.edits_since_saved = self.edits_since_saved.wrapping_sub(1); // Update mark sets. for mark_set in self.mark_sets.iter_mut() { - trans.apply_inverse_to_marks(mark_set); + change.apply_inverse_to_marks(mark_set); mark_set.make_consistent(); } // Apply the edit to the document. - trans.apply_inverse(&mut self.text); + change.apply_inverse(&mut self.text); - return Some(trans); + return Some(change); } else { return None; } } /// Re-does the last edit if there is one, and returns the - /// Transaction that was applied, in case it's needed for further + /// Change that was applied, in case it's needed for further /// processing. /// /// Returns None if there is no edit to redo. - pub fn redo(&mut self) -> Option<&Transaction> { - if let Some(trans) = self.history.redo() { + pub fn redo(&mut self) -> Option<&Change> { + if let Some(change) = self.history.redo() { self.edits_since_saved = self.edits_since_saved.wrapping_add(1); // Update mark sets. for mark_set in self.mark_sets.iter_mut() { - trans.apply_to_marks(mark_set); + change.apply_to_marks(mark_set); mark_set.make_consistent(); } // Apply the edit to the document. - trans.apply(&mut self.text); + change.apply(&mut self.text); - return Some(trans); + return Some(change); } else { return None; } diff --git a/sub_crates/backend/src/transaction.rs b/sub_crates/backend/src/change.rs similarity index 85% rename from sub_crates/backend/src/transaction.rs rename to sub_crates/backend/src/change.rs index 6174896..3fce2e1 100644 --- a/sub_crates/backend/src/transaction.rs +++ b/sub_crates/backend/src/change.rs @@ -7,7 +7,7 @@ enum Op { Retain(usize), // In bytes. Replace { // These both represent strings, and are byte-index ranges into - // the Transaction's `buffer` where their actual string data is + // the Change's `buffer` where their actual string data is // stored. `(0, 0)` can be used to indicate no string data. old: (usize, usize), new: (usize, usize), @@ -36,21 +36,21 @@ impl Op { /// A reversable set of edits treated as an atomic unit. #[derive(Clone)] -pub struct Transaction { +pub struct Change { ops: Vec, buffer: String, } -impl Transaction { - pub fn new() -> Transaction { - Transaction { +impl Change { + pub fn new() -> Change { + Change { ops: Vec::new(), buffer: String::new(), } } - /// Creates a Transaction from a single edit. - pub fn from_edit(byte_idx: usize, old: &str, new: &str) -> Transaction { + /// Creates a Change from a single edit. + pub fn from_edit(byte_idx: usize, old: &str, new: &str) -> Change { let mut buffer = String::new(); buffer.push_str(old); buffer.push_str(new); @@ -63,13 +63,13 @@ impl Transaction { }, ]; - Transaction { + Change { ops: ops, buffer: buffer, } } - /// Creates a Transaction from a sorted, non-overlapping set of + /// Creates a Change from a sorted, non-overlapping set of /// simultaneous edits. /// /// Takes an iterator that yields `(byte_index, old_text, replacement_text)` @@ -78,26 +78,26 @@ impl Transaction { /// the original text--this function does _not_ treat them as a /// sequence of progressively applied edits, but rather as a set of /// edits applied simultaneously. - pub fn from_ordered_edit_set<'a, I>(edit_iter: I) -> Transaction + pub fn from_ordered_edit_set<'a, I>(edit_iter: I) -> Change where I: Iterator + 'a, { - let mut trans = Transaction::new(); + let mut change = Change::new(); let mut i = 0; let mut len_delta = 0isize; for (byte_idx, old, new) in edit_iter { let adjusted_byte_idx = (byte_idx as isize + len_delta) as usize; let retained = adjusted_byte_idx - i; - let old_range = (trans.buffer.len(), trans.buffer.len() + old.len()); - trans.buffer.push_str(old); - let new_range = (trans.buffer.len(), trans.buffer.len() + new.len()); - trans.buffer.push_str(new); + let old_range = (change.buffer.len(), change.buffer.len() + old.len()); + change.buffer.push_str(old); + let new_range = (change.buffer.len(), change.buffer.len() + new.len()); + change.buffer.push_str(new); if retained > 0 { - trans.ops.push(Op::Retain(retained)); + change.ops.push(Op::Retain(retained)); } - trans.ops.push(Op::Replace { + change.ops.push(Op::Replace { old: old_range, new: new_range, }); @@ -105,38 +105,38 @@ impl Transaction { i += retained + new.len(); len_delta += new.len() as isize - old.len() as isize; } - trans + change } - /// Build a Transaction that is functionally identical to applying + /// Build a Change that is functionally identical to applying /// first `self` and then `other` sequentially. #[must_use] - pub fn compose(&self, other: &Transaction) -> Transaction { + pub fn compose(&self, other: &Change) -> Change { use Op::*; - let mut trans = Transaction::new(); + let mut change = Change::new(); let mut ops1 = self.ops.iter().copied(); let mut ops2 = other.ops.iter().copied(); let mut next_op1 = ops1.next(); let mut next_op2 = ops2.next(); - // We progress through both transaction's ops such that their + // We progress through both change's ops such that their // heads stay in sync. To do this, we have to split ops - // sometimes, fragmenting the transaction. + // sometimes, fragmenting the change. loop { match (next_op1, next_op2) { // Done! (None, None) => break, - // One of the transactions is empty, so just append the + // One of the changes is empty, so just append the // remaining ops from the other one. (Some(op), None) => { - trans.push_op(op, &self.buffer); + change.push_op(op, &self.buffer); next_op1 = ops1.next(); } (None, Some(op)) => { - trans.push_op(op, &other.buffer); + change.push_op(op, &other.buffer); next_op2 = ops2.next(); } @@ -144,15 +144,15 @@ impl Transaction { // Retain, Retain (Some(Retain(bc1)), Some(Retain(bc2))) => { if bc1 < bc2 { - trans.retain(bc1); + change.retain(bc1); next_op1 = ops1.next(); next_op2 = Some(Retain(bc2 - bc1)); } else if bc2 < bc1 { - trans.retain(bc2); + change.retain(bc2); next_op1 = Some(Retain(bc1 - bc2)); next_op2 = ops2.next(); } else { - trans.retain(bc1); + change.retain(bc1); next_op1 = ops1.next(); next_op2 = ops2.next(); } @@ -170,7 +170,7 @@ impl Transaction { Some(Retain(bc2)), ) => { if op1.len_post() < bc2 { - trans.push_op(op1, &self.buffer); + change.push_op(op1, &self.buffer); next_op1 = ops1.next(); next_op2 = Some(Retain(bc2 - op1.len_post())); } else if op1.len_post() > bc2 { @@ -182,11 +182,11 @@ impl Transaction { old: (0, 0), new: (new1.0 + bc2, new1.1), }; - trans.push_op(op1a, &self.buffer); + change.push_op(op1a, &self.buffer); next_op1 = Some(op1b); next_op2 = ops2.next(); } else { - trans.push_op(op1, &self.buffer); + change.push_op(op1, &self.buffer); next_op1 = ops1.next(); next_op2 = ops2.next(); } @@ -204,7 +204,7 @@ impl Transaction { let op2 = next_op2.unwrap(); if bc1 < op2.len_pre() { - trans.push_op( + change.push_op( Replace { old: (old2.0, old2.0 + bc1), new: (0, 0), @@ -217,11 +217,11 @@ impl Transaction { new: new2, }); } else if bc1 > op2.len_pre() { - trans.push_op(op2, &other.buffer); + change.push_op(op2, &other.buffer); next_op1 = Some(Retain(bc1 - op2.len_pre())); next_op2 = ops2.next(); } else { - trans.push_op(op2, &other.buffer); + change.push_op(op2, &other.buffer); next_op1 = ops1.next(); next_op2 = ops2.next(); } @@ -243,7 +243,7 @@ impl Transaction { let op2 = next_op2.unwrap(); if op1.len_post() < op2.len_pre() { - trans.push_op( + change.push_op( Replace { old: old1, new: (0, 0), @@ -256,14 +256,14 @@ impl Transaction { new: new2, }); } else if op1.len_post() > op2.len_pre() { - trans.push_op( + change.push_op( Replace { old: old1, new: (0, 0), }, &self.buffer, ); - trans.push_op( + change.push_op( Replace { old: (0, 0), new: new2, @@ -276,7 +276,7 @@ impl Transaction { }); next_op2 = ops2.next(); } else { - trans.push_op_separate_buf( + change.push_op_separate_buf( Replace { old: old1, new: new2, @@ -291,13 +291,13 @@ impl Transaction { } } - trans + change } - /// Creates a transaction that is the inverse of this one (i.e. the "undo" - /// of this transaction). - pub fn inverse(&self) -> Transaction { - let mut inv = Transaction::new(); + /// Creates a change that is the inverse of this one (i.e. the "undo" + /// of this change). + pub fn inverse(&self) -> Change { + let mut inv = Change::new(); for op in self.ops.iter() { match op { @@ -320,7 +320,7 @@ impl Transaction { inv } - /// Applies the Transaction to a Rope. + /// Applies the Change to a Rope. pub fn apply(&self, text: &mut Rope) { let mut i = 0; for op in self.ops.iter() { @@ -347,9 +347,9 @@ impl Transaction { debug_assert!(i <= text.len()); } - /// Applies the inverse of the Transaction to a Rope. + /// Applies the inverse of the Change to a Rope. /// - /// This is an "undo" of the Transaction. + /// This is an "undo" of the Change. pub fn apply_inverse(&self, text: &mut Rope) { let mut i = 0; for op in self.ops.iter() { @@ -380,7 +380,7 @@ impl Transaction { debug_assert!(i <= text.len()); } - /// Applies the Transaction to a set of Marks. + /// Applies the Change to a set of Marks. pub fn apply_to_marks(&self, marks: &mut MarkSet) { marks.make_consistent(); @@ -429,9 +429,9 @@ impl Transaction { marks.make_consistent(); } - /// Applies the inverse of the Transaction to a set of Marks. + /// Applies the inverse of the Change to a set of Marks. /// - /// This is essentially an "undo" of the Transaction. However, on + /// This is essentially an "undo" of the Change. However, on /// marks this is a lossy operation and is not guaranteed to return /// the marks to their original count and position. pub fn apply_inverse_to_marks(&self, marks: &mut MarkSet) { @@ -484,7 +484,7 @@ impl Transaction { //--------------------------------------------------------- - /// Pushes a retain op onto the transaction operations. + /// Pushes a retain op onto the change operations. #[inline(always)] fn retain(&mut self, byte_count: usize) { if let Some(Op::Retain(ref mut last_byte_count)) = self.ops.last_mut() { @@ -494,7 +494,7 @@ impl Transaction { } } - /// Pushes a replace op onto the transaction operations. + /// Pushes a replace op onto the change operations. #[inline(always)] fn replace(&mut self, old: &str, new: &str) { if !old.is_empty() || !new.is_empty() { @@ -513,7 +513,7 @@ impl Transaction { } } - /// Pushes an op onto the transaction operations. + /// Pushes an op onto the change operations. /// /// - op: the operation. /// - buffer: the string buffer the op points into if it's a `Replace`. @@ -522,7 +522,7 @@ impl Transaction { self.push_op_separate_buf(op, buffer, buffer); } - /// Pushes an op onto the transaction operations. + /// Pushes an op onto the change operations. /// /// - op: the operation. /// - buf_old: the string buffer that `Replace { old }` points into. @@ -538,9 +538,9 @@ impl Transaction { } } -impl std::fmt::Debug for Transaction { +impl std::fmt::Debug for Change { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - f.write_str("Transaction {\n")?; + f.write_str("Change {\n")?; f.write_str(" ops: [\n")?; for op in self.ops.iter() { match op { @@ -573,14 +573,14 @@ mod tests { #[test] fn apply_to_marks_01() { - let trans = Transaction::from_edit(5, "", "hi"); + let change = Change::from_edit(5, "", "hi"); let mut mark_set = MarkSet::new(); mark_set.add_mark(Mark::new(4, 4)); mark_set.add_mark(Mark::new(5, 5)); mark_set.add_mark(Mark::new(6, 6)); - trans.apply_to_marks(&mut mark_set); + change.apply_to_marks(&mut mark_set); assert_eq!(mark_set.marks[0].head, 4); assert_eq!(mark_set.marks[0].tail, 4); assert_eq!(mark_set.marks[1].head, 7); @@ -591,7 +591,7 @@ mod tests { #[test] fn apply_to_marks_02() { - let trans = Transaction { + let change = Change { ops: vec![ Op::Retain(5), Op::Replace { @@ -611,7 +611,7 @@ mod tests { mark_set.add_mark(Mark::new(5, 5)); mark_set.add_mark(Mark::new(6, 6)); - trans.apply_to_marks(&mut mark_set); + change.apply_to_marks(&mut mark_set); assert_eq!(mark_set.marks[0].head, 4); assert_eq!(mark_set.marks[0].tail, 4); assert_eq!(mark_set.marks[1].head, 7); @@ -622,14 +622,14 @@ mod tests { #[test] fn apply_to_marks_03() { - let trans = Transaction::from_edit(5, "hi", ""); + let change = Change::from_edit(5, "hi", ""); let mut mark_set = MarkSet::new(); mark_set.add_mark(Mark::new(4, 4)); mark_set.add_mark(Mark::new(6, 6)); mark_set.add_mark(Mark::new(8, 8)); - trans.apply_to_marks(&mut mark_set); + change.apply_to_marks(&mut mark_set); assert_eq!(mark_set.marks[0].head, 4); assert_eq!(mark_set.marks[0].tail, 4); assert_eq!(mark_set.marks[1].head, 5); @@ -640,7 +640,7 @@ mod tests { #[test] fn apply_to_marks_04() { - let trans = Transaction { + let change = Change { ops: vec![ Op::Retain(5), Op::Replace { @@ -660,7 +660,7 @@ mod tests { mark_set.add_mark(Mark::new(6, 6)); mark_set.add_mark(Mark::new(8, 8)); - trans.apply_to_marks(&mut mark_set); + change.apply_to_marks(&mut mark_set); assert_eq!(mark_set.marks[0].head, 4); assert_eq!(mark_set.marks[0].tail, 4); assert_eq!(mark_set.marks[1].head, 5); @@ -671,14 +671,14 @@ mod tests { #[test] fn apply_inverse_to_marks_01() { - let trans = Transaction::from_edit(5, "hi", ""); + let change = Change::from_edit(5, "hi", ""); let mut mark_set = MarkSet::new(); mark_set.add_mark(Mark::new(4, 4)); mark_set.add_mark(Mark::new(5, 5)); mark_set.add_mark(Mark::new(6, 6)); - trans.apply_inverse_to_marks(&mut mark_set); + change.apply_inverse_to_marks(&mut mark_set); assert_eq!(mark_set.marks[0].head, 4); assert_eq!(mark_set.marks[0].tail, 4); assert_eq!(mark_set.marks[1].head, 7); @@ -689,14 +689,14 @@ mod tests { #[test] fn apply_inverse_to_marks_02() { - let trans = Transaction::from_edit(5, "", "hi"); + let change = Change::from_edit(5, "", "hi"); let mut mark_set = MarkSet::new(); mark_set.add_mark(Mark::new(4, 4)); mark_set.add_mark(Mark::new(6, 6)); mark_set.add_mark(Mark::new(8, 8)); - trans.apply_inverse_to_marks(&mut mark_set); + change.apply_inverse_to_marks(&mut mark_set); assert_eq!(mark_set.marks[0].head, 4); assert_eq!(mark_set.marks[0].tail, 4); assert_eq!(mark_set.marks[1].head, 5); diff --git a/sub_crates/backend/src/history.rs b/sub_crates/backend/src/history.rs index a723765..5d68f96 100644 --- a/sub_crates/backend/src/history.rs +++ b/sub_crates/backend/src/history.rs @@ -1,8 +1,8 @@ -use crate::transaction::Transaction; +use crate::change::Change; #[derive(Debug, Clone)] pub struct History { - edits: Vec, + edits: Vec, position: usize, // Where we are in the history. } @@ -14,13 +14,13 @@ impl History { } } - pub fn push_edit(&mut self, edit: Transaction) { + pub fn push_edit(&mut self, edit: Change) { self.commit(); self.edits.push(edit); self.position += 1; } - pub fn undo(&mut self) -> Option<&Transaction> { + pub fn undo(&mut self) -> Option<&Change> { if self.position > 0 { self.position -= 1; Some(&self.edits[self.position]) @@ -29,7 +29,7 @@ impl History { } } - pub fn redo(&mut self) -> Option<&Transaction> { + pub fn redo(&mut self) -> Option<&Change> { if self.position < self.edits.len() { let edit = &self.edits[self.position]; self.position += 1; @@ -39,14 +39,14 @@ impl History { } } - /// Takes the current undo state, and pushes that as another transaction on + /// Takes the current undo state, and pushes that as another change on /// top of the existing undo stack, without deleting any existing items. pub fn commit(&mut self) { if self.position == self.edits.len() { return; } - let mut undo_trans = Transaction::new(); + let mut undo_trans = Change::new(); for trans in self.edits[self.position..].iter().rev() { undo_trans = undo_trans.compose(&trans.inverse()); } diff --git a/sub_crates/backend/src/lib.rs b/sub_crates/backend/src/lib.rs index b49a686..cf1bfbb 100644 --- a/sub_crates/backend/src/lib.rs +++ b/sub_crates/backend/src/lib.rs @@ -2,8 +2,8 @@ extern crate ropey; extern crate unicode_segmentation; pub mod buffer; +pub mod change; pub mod editor; pub mod history; pub mod marks; pub mod project; -pub mod transaction; diff --git a/sub_crates/backend/tests/transaction.proptest-regressions b/sub_crates/backend/tests/change.proptest-regressions similarity index 100% rename from sub_crates/backend/tests/transaction.proptest-regressions rename to sub_crates/backend/tests/change.proptest-regressions diff --git a/sub_crates/backend/tests/transaction.rs b/sub_crates/backend/tests/change.rs similarity index 83% rename from sub_crates/backend/tests/transaction.rs rename to sub_crates/backend/tests/change.rs index fef3a81..db43301 100644 --- a/sub_crates/backend/tests/transaction.rs +++ b/sub_crates/backend/tests/change.rs @@ -6,7 +6,7 @@ use proptest::test_runner::Config; use ropey::Rope; -use backend::transaction::Transaction; +use backend::change::Change; fn make_edit_list_valid(edits: &mut Vec<(usize, usize, String)>, start_text: &str) { edits.sort_by_key(|e| e.0); @@ -41,24 +41,24 @@ proptest! { ) { // Make edits1 valid and compute the post-edits1 string. make_edit_list_valid(&mut edits1, start_text); - let trans1 = Transaction::from_ordered_edit_set(edits1.iter().map(|e| { + let change1 = Change::from_ordered_edit_set(edits1.iter().map(|e| { (e.0, &start_text[e.0..(e.0+e.1)], &e.2[..]) })); let mut r1 = Rope::from_str(start_text); - trans1.apply(&mut r1); + change1.apply(&mut r1); let text1: String = r1.clone().into(); // Make edits2 valid and compute the post-edits2 string. make_edit_list_valid(&mut edits2, &text1); - let trans2 = Transaction::from_ordered_edit_set(edits2.iter().map(|e| { + let change2 = Change::from_ordered_edit_set(edits2.iter().map(|e| { (e.0, &text1[e.0..(e.0+e.1)], &e.2[..]) })); - trans2.apply(&mut r1); + change2.apply(&mut r1); // Do the test! - let trans3 = trans1.compose(&trans2); + let change3 = change1.compose(&change2); let mut r2 = Rope::from_str(start_text); - trans3.apply(&mut r2); + change3.apply(&mut r2); assert_eq!(r1, r2); }