aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helix-core/src/transaction.rs61
1 files changed, 61 insertions, 0 deletions
diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs
index 7da5b7dd..c0f27abe 100644
--- a/helix-core/src/transaction.rs
+++ b/helix-core/src/transaction.rs
@@ -390,6 +390,10 @@ impl ChangeSet {
}
new_pos
}
+
+ pub fn changes_iter(&self) -> ChangeIterator {
+ ChangeIterator::new(self)
+ }
}
/// Transaction represents a single undoable unit of changes. Several changes can be grouped into
@@ -502,6 +506,10 @@ impl Transaction {
(range.head, range.head, Some(text.clone()))
})
}
+
+ pub fn changes_iter(&self) -> ChangeIterator {
+ self.changes.changes_iter()
+ }
}
impl From<ChangeSet> for Transaction {
@@ -513,6 +521,51 @@ impl From<ChangeSet> for Transaction {
}
}
+pub struct ChangeIterator<'a> {
+ iter: std::iter::Peekable<std::slice::Iter<'a, Operation>>,
+ pos: usize,
+}
+
+impl<'a> ChangeIterator<'a> {
+ fn new(changeset: &'a ChangeSet) -> Self {
+ let iter = changeset.changes.iter().peekable();
+ Self { iter, pos: 0 }
+ }
+}
+
+impl<'a> Iterator for ChangeIterator<'a> {
+ type Item = Change;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ use Operation::*;
+
+ loop {
+ match self.iter.next()? {
+ Retain(len) => {
+ self.pos += len;
+ }
+ Delete(len) => {
+ let start = self.pos;
+ self.pos += len;
+ return Some((start, self.pos, None));
+ }
+ Insert(s) => {
+ let start = self.pos;
+ // a subsequent delete means a replace, consume it
+ if let Some(Delete(len)) = self.iter.peek() {
+ self.iter.next();
+
+ self.pos += len;
+ return Some((start, self.pos, Some(s.clone())));
+ } else {
+ return Some((start, start, Some(s.clone())));
+ }
+ }
+ }
+ }
+ }
+}
+
#[cfg(test)]
mod test {
use super::*;
@@ -627,6 +680,14 @@ mod test {
}
#[test]
+ fn changes_iter() {
+ let mut state = State::new("hello world!\ntest 123".into());
+ let changes = vec![(6, 11, Some("void".into())), (12, 17, None)];
+ let transaction = Transaction::change(&state.doc, changes.clone().into_iter());
+ assert_eq!(transaction.changes_iter().collect::<Vec<_>>(), changes);
+ }
+
+ #[test]
fn optimized_composition() {
let mut state = State::new("".into());
let t1 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('h'));