|
|
@ -390,6 +390,10 @@ impl ChangeSet {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
new_pos
|
|
|
|
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
|
|
|
|
/// 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()))
|
|
|
|
(range.head, range.head, Some(text.clone()))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn changes_iter(&self) -> ChangeIterator {
|
|
|
|
|
|
|
|
self.changes.changes_iter()
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl From<ChangeSet> for Transaction {
|
|
|
|
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)]
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
use super::*;
|
|
|
@ -626,6 +679,14 @@ mod test {
|
|
|
|
assert_eq!(state.doc, Rope::from_str("hello void! 123"));
|
|
|
|
assert_eq!(state.doc, Rope::from_str("hello void! 123"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[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]
|
|
|
|
#[test]
|
|
|
|
fn optimized_composition() {
|
|
|
|
fn optimized_composition() {
|
|
|
|
let mut state = State::new("".into());
|
|
|
|
let mut state = State::new("".into());
|
|
|
|