on master help sign in
Transaction: Add a changes_iter() that can convert back to a list of Changes
commit1d96cbfbd2ef1d937490b1aaa19152dfc0ea0f76 authorBlaž Hrastnik <blaz@mxxn.io> dateMon 29 Mar 2021, 14:56 (6 years ago) parenta74ff6b
1 file changed+61
helix-core/src/transaction.rs+61
helix-core/src/transaction.rs+61
@@ -390,6 +390,10 @@ impl ChangeSet {
390390 }
391391 new_pos
392392 }
393+
394+ pub fn changes_iter(&self) -> ChangeIterator {
395+ ChangeIterator::new(self)
396+ }
393397}
394398
395399/// Transaction represents a single undoable unit of changes. Several changes can be grouped into
@@ -502,6 +506,10 @@ impl Transaction {
502506 (range.head, range.head, Some(text.clone()))
503507 })
504508 }
509+
510+ pub fn changes_iter(&self) -> ChangeIterator {
511+ self.changes.changes_iter()
512+ }
505513}
506514
507515impl From<ChangeSet> for Transaction {
@@ -513,6 +521,51 @@ impl From<ChangeSet> for Transaction {
513521 }
514522}
515523
524+pub struct ChangeIterator<'a> {
525+ iter: std::iter::Peekable<std::slice::Iter<'a, Operation>>,
526+ pos: usize,
527+}
528+
529+impl<'a> ChangeIterator<'a> {
530+ fn new(changeset: &'a ChangeSet) -> Self {
531+ let iter = changeset.changes.iter().peekable();
532+ Self { iter, pos: 0 }
533+ }
534+}
535+
536+impl<'a> Iterator for ChangeIterator<'a> {
537+ type Item = Change;
538+
539+ fn next(&mut self) -> Option<Self::Item> {
540+ use Operation::*;
541+
542+ loop {
543+ match self.iter.next()? {
544+ Retain(len) => {
545+ self.pos += len;
546+ }
547+ Delete(len) => {
548+ let start = self.pos;
549+ self.pos += len;
550+ return Some((start, self.pos, None));
551+ }
552+ Insert(s) => {
553+ let start = self.pos;
554+ // a subsequent delete means a replace, consume it
555+ if let Some(Delete(len)) = self.iter.peek() {
556+ self.iter.next();
557+
558+ self.pos += len;
559+ return Some((start, self.pos, Some(s.clone())));
560+ } else {
561+ return Some((start, start, Some(s.clone())));
562+ }
563+ }
564+ }
565+ }
566+ }
567+}
568+
516569#[cfg(test)]
517570mod test {
518571 use super::*;
@@ -626,6 +679,14 @@ mod test {
626679 assert_eq!(state.doc, Rope::from_str("hello void! 123"));
627680 }
628681
682+ #[test]
683+ fn changes_iter() {
684+ let mut state = State::new("hello world!\ntest 123".into());
685+ let changes = vec![(6, 11, Some("void".into())), (12, 17, None)];
686+ let transaction = Transaction::change(&state.doc, changes.clone().into_iter());
687+ assert_eq!(transaction.changes_iter().collect::<Vec<_>>(), changes);
688+ }
689+
629690 #[test]
630691 fn optimized_composition() {
631692 let mut state = State::new("".into());