Implement applying transactions to mark sets.
This commit is contained in:
parent
fa55afeebe
commit
9087019542
|
@ -128,6 +128,10 @@ impl MarkSet {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.marks.len()
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.main_mark_idx = 0;
|
||||
self.marks.clear();
|
||||
|
|
|
@ -359,8 +359,52 @@ impl Transaction {
|
|||
}
|
||||
|
||||
/// Applies the Transaction to a set of Marks.
|
||||
pub fn apply_to_marks(&self, _marks: &mut MarkSet) {
|
||||
todo!()
|
||||
pub fn apply_to_marks(&self, marks: &mut MarkSet) {
|
||||
marks.make_consistent();
|
||||
|
||||
// We do this in two passes: first heads, then tails.
|
||||
for tail in 0..=1 {
|
||||
let mut mark_idx = 0;
|
||||
let mut byte_idx_old = 0;
|
||||
let mut byte_idx_new = 0;
|
||||
for op in self.ops.iter() {
|
||||
let old_len = op.len_pre();
|
||||
let new_len = op.len_post();
|
||||
|
||||
while mark_idx < marks.len() {
|
||||
let idx = if tail == 1 {
|
||||
&mut marks[mark_idx].tail
|
||||
} else {
|
||||
&mut marks[mark_idx].head
|
||||
};
|
||||
|
||||
if *idx < byte_idx_old {
|
||||
mark_idx += 1;
|
||||
} else if *idx < (byte_idx_old + old_len) {
|
||||
*idx = *idx + byte_idx_new - byte_idx_old;
|
||||
*idx = (*idx).min(byte_idx_new + new_len);
|
||||
mark_idx += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
byte_idx_old += old_len;
|
||||
byte_idx_new += new_len;
|
||||
}
|
||||
|
||||
while mark_idx < marks.len() {
|
||||
let idx = if tail == 1 {
|
||||
&mut marks[mark_idx].tail
|
||||
} else {
|
||||
&mut marks[mark_idx].head
|
||||
};
|
||||
*idx = *idx + byte_idx_new - byte_idx_old;
|
||||
mark_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
marks.make_consistent();
|
||||
}
|
||||
|
||||
/// Applies the inverse of the Transaction to a set of Marks.
|
||||
|
@ -368,8 +412,52 @@ impl Transaction {
|
|||
/// This is essentially an "undo" of the Transaction. 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) {
|
||||
todo!()
|
||||
pub fn apply_inverse_to_marks(&self, marks: &mut MarkSet) {
|
||||
marks.make_consistent();
|
||||
|
||||
// We do this in two passes: first heads, then tails.
|
||||
for tail in 0..=1 {
|
||||
let mut mark_idx = 0;
|
||||
let mut byte_idx_old = 0;
|
||||
let mut byte_idx_new = 0;
|
||||
for op in self.ops.iter() {
|
||||
let old_len = op.len_post();
|
||||
let new_len = op.len_pre();
|
||||
|
||||
while mark_idx < marks.len() {
|
||||
let idx = if tail == 1 {
|
||||
&mut marks[mark_idx].tail
|
||||
} else {
|
||||
&mut marks[mark_idx].head
|
||||
};
|
||||
|
||||
if *idx < byte_idx_old {
|
||||
mark_idx += 1;
|
||||
} else if *idx < (byte_idx_old + old_len) {
|
||||
*idx = *idx + byte_idx_new - byte_idx_old;
|
||||
*idx = (*idx).min(byte_idx_new + new_len);
|
||||
mark_idx += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
byte_idx_old += old_len;
|
||||
byte_idx_new += new_len;
|
||||
}
|
||||
|
||||
while mark_idx < marks.len() {
|
||||
let idx = if tail == 1 {
|
||||
&mut marks[mark_idx].tail
|
||||
} else {
|
||||
&mut marks[mark_idx].head
|
||||
};
|
||||
*idx = *idx + byte_idx_new - byte_idx_old;
|
||||
mark_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
marks.make_consistent();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -455,3 +543,143 @@ impl std::fmt::Debug for Transaction {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::marks::{Mark, MarkSet};
|
||||
|
||||
#[test]
|
||||
fn apply_to_marks_01() {
|
||||
let trans = Transaction::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);
|
||||
assert_eq!(mark_set.marks[0].head, 4);
|
||||
assert_eq!(mark_set.marks[0].tail, 4);
|
||||
assert_eq!(mark_set.marks[1].head, 7);
|
||||
assert_eq!(mark_set.marks[1].tail, 7);
|
||||
assert_eq!(mark_set.marks[2].head, 8);
|
||||
assert_eq!(mark_set.marks[2].tail, 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_to_marks_02() {
|
||||
let trans = Transaction {
|
||||
ops: vec![
|
||||
Op::Retain(5),
|
||||
Op::Replace {
|
||||
old: (0, 0),
|
||||
new: (0, 1),
|
||||
},
|
||||
Op::Replace {
|
||||
old: (0, 0),
|
||||
new: (1, 2),
|
||||
},
|
||||
],
|
||||
buffer: "hi".into(),
|
||||
};
|
||||
|
||||
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);
|
||||
assert_eq!(mark_set.marks[0].head, 4);
|
||||
assert_eq!(mark_set.marks[0].tail, 4);
|
||||
assert_eq!(mark_set.marks[1].head, 7);
|
||||
assert_eq!(mark_set.marks[1].tail, 7);
|
||||
assert_eq!(mark_set.marks[2].head, 8);
|
||||
assert_eq!(mark_set.marks[2].tail, 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_to_marks_03() {
|
||||
let trans = Transaction::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);
|
||||
assert_eq!(mark_set.marks[0].head, 4);
|
||||
assert_eq!(mark_set.marks[0].tail, 4);
|
||||
assert_eq!(mark_set.marks[1].head, 5);
|
||||
assert_eq!(mark_set.marks[1].tail, 5);
|
||||
assert_eq!(mark_set.marks[2].head, 6);
|
||||
assert_eq!(mark_set.marks[2].tail, 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_to_marks_04() {
|
||||
let trans = Transaction {
|
||||
ops: vec![
|
||||
Op::Retain(5),
|
||||
Op::Replace {
|
||||
old: (0, 1),
|
||||
new: (0, 0),
|
||||
},
|
||||
Op::Replace {
|
||||
old: (1, 2),
|
||||
new: (0, 0),
|
||||
},
|
||||
],
|
||||
buffer: "hi".into(),
|
||||
};
|
||||
|
||||
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);
|
||||
assert_eq!(mark_set.marks[0].head, 4);
|
||||
assert_eq!(mark_set.marks[0].tail, 4);
|
||||
assert_eq!(mark_set.marks[1].head, 5);
|
||||
assert_eq!(mark_set.marks[1].tail, 5);
|
||||
assert_eq!(mark_set.marks[2].head, 6);
|
||||
assert_eq!(mark_set.marks[2].tail, 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_inverse_to_marks_01() {
|
||||
let trans = Transaction::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);
|
||||
assert_eq!(mark_set.marks[0].head, 4);
|
||||
assert_eq!(mark_set.marks[0].tail, 4);
|
||||
assert_eq!(mark_set.marks[1].head, 7);
|
||||
assert_eq!(mark_set.marks[1].tail, 7);
|
||||
assert_eq!(mark_set.marks[2].head, 8);
|
||||
assert_eq!(mark_set.marks[2].tail, 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_inverse_to_marks_02() {
|
||||
let trans = Transaction::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);
|
||||
assert_eq!(mark_set.marks[0].head, 4);
|
||||
assert_eq!(mark_set.marks[0].tail, 4);
|
||||
assert_eq!(mark_set.marks[1].head, 5);
|
||||
assert_eq!(mark_set.marks[1].tail, 5);
|
||||
assert_eq!(mark_set.marks[2].head, 6);
|
||||
assert_eq!(mark_set.marks[2].tail, 6);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user