cursor: next op with length

This commit is contained in:
appflowy 2021-08-13 14:13:31 +08:00
parent bc7da582a3
commit 93cf9712dc
10 changed files with 376 additions and 157 deletions

View File

@ -40,21 +40,21 @@ class Rules {
final List<Rule> _rules; final List<Rule> _rules;
static final Rules _instance = Rules([ static final Rules _instance = Rules([
const FormatLinkAtCaretPositionRule(), // const FormatLinkAtCaretPositionRule(),
const ResolveLineFormatRule(), // const ResolveLineFormatRule(),
const ResolveInlineFormatRule(), const ResolveInlineFormatRule(),
const InsertEmbedsRule(), // const InsertEmbedsRule(),
const ForceNewlineForInsertsAroundEmbedRule(), // const ForceNewlineForInsertsAroundEmbedRule(),
const AutoExitBlockRule(), // const AutoExitBlockRule(),
const PreserveBlockStyleOnInsertRule(), // const PreserveBlockStyleOnInsertRule(),
const PreserveLineStyleOnSplitRule(), // const PreserveLineStyleOnSplitRule(),
const ResetLineFormatOnNewLineRule(), const ResetLineFormatOnNewLineRule(),
const AutoFormatLinksRule(), // const AutoFormatLinksRule(),
const PreserveInlineStylesRule(), const PreserveInlineStylesRule(),
const CatchAllInsertRule(), const CatchAllInsertRule(),
const EnsureEmbedLineRule(), // const EnsureEmbedLineRule(),
const PreserveLineStyleOnMergeRule(), // const PreserveLineStyleOnMergeRule(),
const CatchAllDeleteRule(), // const CatchAllDeleteRule(),
]); ]);
static Rules getInstance() => _instance; static Rules getInstance() => _instance;

View File

@ -46,9 +46,12 @@ impl Document {
pub fn format(&mut self, interval: Interval, attribute: Attribute) -> Result<(), OTError> { pub fn format(&mut self, interval: Interval, attribute: Attribute) -> Result<(), OTError> {
log::debug!("format with {} at {}", attribute, interval); log::debug!("format with {} at {}", attribute, interval);
// let format_delta = self
// let format_delta = self.view.format(&self.delta, attribute, interval)?; // .view
// .format(&self.delta, attribute.clone(), interval)
// .unwrap();
// let a = self.delta.compose(&format_delta).unwrap();
// println!("{:?}", a);
self.update_with_attribute(attribute, interval) self.update_with_attribute(attribute, interval)
} }
@ -165,7 +168,10 @@ impl Document {
fn next_rev_id(&self) -> RevId { RevId(self.rev_id_counter) } fn next_rev_id(&self) -> RevId { RevId(self.rev_id_counter) }
fn record_change(&mut self, delta: &Delta) -> Result<Delta, OTError> { fn record_change(&mut self, delta: &Delta) -> Result<Delta, OTError> {
let (composed_delta, mut undo_delta) = self.invert_change(&delta)?; log::debug!("👉invert change {}", delta);
let composed_delta = self.delta.compose(delta)?;
let mut undo_delta = delta.invert(&self.delta);
self.rev_id_counter += 1; self.rev_id_counter += 1;
let now = chrono::Utc::now().timestamp_millis() as usize; let now = chrono::Utc::now().timestamp_millis() as usize;

View File

@ -1,6 +1,16 @@
use crate::{ use crate::{
client::view::FormatExt, client::view::{FormatExt, NEW_LINE},
core::{Attribute, AttributeScope, Attributes, Delta, DeltaBuilder, DeltaIter, Interval}, core::{
Attribute,
AttributeScope,
Attributes,
CharMetric,
Delta,
DeltaBuilder,
DeltaIter,
Interval,
Operation,
},
}; };
pub struct FormatLinkAtCaretPositionExt {} pub struct FormatLinkAtCaretPositionExt {}
@ -8,7 +18,7 @@ pub struct FormatLinkAtCaretPositionExt {}
impl FormatExt for FormatLinkAtCaretPositionExt { impl FormatExt for FormatLinkAtCaretPositionExt {
fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> { fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
let mut iter = DeltaIter::new(delta); let mut iter = DeltaIter::new(delta);
iter.seek(interval.start); iter.seek::<CharMetric>(interval.start);
let (before, after) = (iter.next(), iter.next()); let (before, after) = (iter.next(), iter.next());
let mut start = interval.start; let mut start = interval.start;
let mut retain = 0; let mut retain = 0;
@ -42,7 +52,6 @@ impl FormatExt for FormatLinkAtCaretPositionExt {
} }
pub struct ResolveLineFormatExt {} pub struct ResolveLineFormatExt {}
impl FormatExt for ResolveLineFormatExt { impl FormatExt for ResolveLineFormatExt {
fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> { fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
if attribute.scope != AttributeScope::Block { if attribute.scope != AttributeScope::Block {
@ -53,7 +62,7 @@ impl FormatExt for ResolveLineFormatExt {
new_delta.retain(interval.start, Attributes::default()); new_delta.retain(interval.start, Attributes::default());
let mut iter = DeltaIter::new(delta); let mut iter = DeltaIter::new(delta);
iter.seek(interval.start); iter.seek::<CharMetric>(interval.start);
None None
} }
@ -63,6 +72,54 @@ pub struct ResolveInlineFormatExt {}
impl FormatExt for ResolveInlineFormatExt { impl FormatExt for ResolveInlineFormatExt {
fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> { fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
unimplemented!() if attribute.scope != AttributeScope::Inline {
return None;
}
let mut new_delta = DeltaBuilder::new()
.retain(interval.start, Attributes::default())
.build();
let mut iter = DeltaIter::new(delta);
iter.seek::<CharMetric>(interval.start);
let mut cur = 0;
let len = interval.size();
while cur < len && iter.has_next() {
let some_op = iter.next_op_with_length(len - cur);
if some_op.is_none() {
return Some(new_delta);
}
let op = some_op.unwrap();
if let Operation::Insert(insert) = &op {
let mut s = insert.s.as_str();
match s.find(NEW_LINE) {
None => {
new_delta.retain(op.length(), attribute.clone().into());
},
Some(mut line_break) => {
let mut pos = 0;
let mut some_line_break = Some(line_break);
while some_line_break.is_some() {
let line_break = some_line_break.unwrap();
new_delta.retain(line_break - pos, attribute.clone().into());
new_delta.retain(1, Attributes::default());
pos = line_break + 1;
s = &s[pos..s.len()];
some_line_break = s.find(NEW_LINE);
}
if pos < op.length() {
new_delta.retain(op.length() - pos, attribute.clone().into());
}
},
}
}
cur += op.length();
}
Some(new_delta)
} }
} }

View File

@ -1,9 +1,10 @@
use crate::{ use crate::{
client::view::InsertExt, client::view::InsertExt,
core::{ core::{
attributes_at_index, attributes_with_length,
AttributeKey, AttributeKey,
Attributes, Attributes,
CharMetric,
Delta, Delta,
DeltaBuilder, DeltaBuilder,
DeltaIter, DeltaIter,
@ -13,18 +14,57 @@ use crate::{
pub const NEW_LINE: &'static str = "\n"; pub const NEW_LINE: &'static str = "\n";
pub struct PreserveInlineStyleExt {} pub struct PreserveBlockStyleOnInsertExt {}
impl PreserveInlineStyleExt { impl InsertExt for PreserveBlockStyleOnInsertExt {
pub fn new() -> Self { Self {} } fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
None
}
} }
impl InsertExt for PreserveInlineStyleExt { pub struct PreserveLineStyleOnSplitExt {}
impl InsertExt for PreserveLineStyleOnSplitExt {
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
None
}
}
pub struct AutoExitBlockExt {}
impl InsertExt for AutoExitBlockExt {
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
None
}
}
pub struct InsertEmbedsExt {}
impl InsertExt for InsertEmbedsExt {
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
None
}
}
pub struct ForceNewlineForInsertsAroundEmbedExt {}
impl InsertExt for ForceNewlineForInsertsAroundEmbedExt {
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
None
}
}
pub struct AutoFormatLinksExt {}
impl InsertExt for AutoFormatLinksExt {
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
None
}
}
pub struct PreserveInlineStylesExt {}
impl InsertExt for PreserveInlineStylesExt {
fn apply(&self, delta: &Delta, _replace_len: usize, text: &str, index: usize) -> Option<Delta> { fn apply(&self, delta: &Delta, _replace_len: usize, text: &str, index: usize) -> Option<Delta> {
if text.ends_with(NEW_LINE) { if text.ends_with(NEW_LINE) {
return None; return None;
} }
let probe_index = if index > 1 { index - 1 } else { index };
let attributes = attributes_at_index(delta, index); let attributes = attributes_with_length(delta, probe_index);
let delta = DeltaBuilder::new().insert(text, attributes).build(); let delta = DeltaBuilder::new().insert(text, attributes).build();
Some(delta) Some(delta)
@ -32,11 +72,6 @@ impl InsertExt for PreserveInlineStyleExt {
} }
pub struct ResetLineFormatOnNewLineExt {} pub struct ResetLineFormatOnNewLineExt {}
impl ResetLineFormatOnNewLineExt {
pub fn new() -> Self { Self {} }
}
impl InsertExt for ResetLineFormatOnNewLineExt { impl InsertExt for ResetLineFormatOnNewLineExt {
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> { fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
if text != NEW_LINE { if text != NEW_LINE {
@ -44,7 +79,7 @@ impl InsertExt for ResetLineFormatOnNewLineExt {
} }
let mut iter = DeltaIter::new(delta); let mut iter = DeltaIter::new(delta);
iter.seek(index); iter.seek::<CharMetric>(index);
let maybe_next_op = iter.next(); let maybe_next_op = iter.next();
if maybe_next_op.is_none() { if maybe_next_op.is_none() {
return None; return None;
@ -71,3 +106,15 @@ impl InsertExt for ResetLineFormatOnNewLineExt {
) )
} }
} }
pub struct DefaultInsertExt {}
impl InsertExt for DefaultInsertExt {
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
Some(
DeltaBuilder::new()
.retain(index + replace_len, Attributes::default())
.insert(text, Attributes::default())
.build(),
)
}
}

View File

@ -73,8 +73,15 @@ impl View {
fn construct_insert_exts() -> Vec<InsertExtension> { fn construct_insert_exts() -> Vec<InsertExtension> {
vec![ vec![
Box::new(PreserveInlineStyleExt::new()), Box::new(InsertEmbedsExt {}),
Box::new(ResetLineFormatOnNewLineExt::new()), Box::new(ForceNewlineForInsertsAroundEmbedExt {}),
Box::new(AutoExitBlockExt {}),
Box::new(PreserveBlockStyleOnInsertExt {}),
Box::new(PreserveLineStyleOnSplitExt {}),
Box::new(ResetLineFormatOnNewLineExt {}),
Box::new(AutoFormatLinksExt {}),
Box::new(PreserveInlineStylesExt {}),
Box::new(DefaultInsertExt {}),
] ]
} }

View File

@ -4,153 +4,127 @@ use crate::{
}; };
use std::{cmp::min, slice::Iter}; use std::{cmp::min, slice::Iter};
#[derive(Debug)]
pub struct Cursor<'a> { pub struct Cursor<'a> {
delta: &'a Delta, pub(crate) delta: &'a Delta,
interval: Interval, pub(crate) origin_iv: Interval,
iterator: Iter<'a, Operation>, pub(crate) next_iv: Interval,
char_index: usize, pub(crate) c_index: usize,
op_index: usize, pub(crate) o_index: usize,
current_op: Option<&'a Operation>, iter: Iter<'a, Operation>,
next_op: Option<Operation>,
} }
impl<'a> Cursor<'a> { impl<'a> Cursor<'a> {
pub fn new(delta: &'a Delta, interval: Interval) -> Cursor<'a> { pub fn new(delta: &'a Delta, interval: Interval) -> Cursor<'a> {
let cursor = Self { // debug_assert!(interval.start <= delta.target_len);
let mut cursor = Self {
delta, delta,
interval, origin_iv: interval,
iterator: delta.ops.iter(), next_iv: interval,
char_index: 0, c_index: 0,
op_index: 0, o_index: 0,
current_op: None, iter: delta.ops.iter(),
next_op: None,
}; };
cursor.descend(0);
cursor cursor
} }
pub fn next_op(&mut self) -> Option<Operation> { fn descend(&mut self, index: usize) {
let mut next_op = self.current_op.take(); self.next_iv.start += index;
if next_op.is_none() { if self.c_index >= self.next_iv.start {
next_op = self.iterator.next(); return;
} }
let mut find_op = None; while let Some(op) = self.iter.next() {
while find_op.is_none() && next_op.is_some() { self.o_index += 1;
self.op_index += 1; let start = self.c_index;
let end = start + op.length();
let op = next_op.unwrap(); let intersect = Interval::new(start, end).intersect(self.next_iv);
if self.char_index < self.interval.start { if intersect.is_empty() {
let intersect = Interval::new(self.char_index, self.char_index + op.length()) self.c_index += op.length();
.intersect(self.interval);
if intersect.is_empty() {
self.char_index += op.length();
} else {
if let Some(new_op) = op.shrink(intersect.translate_neg(self.char_index)) {
// shrink the op to fit the intersect range
// ┌──────────────┐
// │ 1 2 3 4 5 6 │
// └───────▲───▲──┘
// │ │
// [3, 5)
// op = "45"
find_op = Some(new_op);
}
self.char_index = intersect.end;
}
} else { } else {
// the interval passed in the shrink function is base on the op not the delta. self.next_op = Some(op.clone());
if let Some(new_op) = op.shrink(self.interval.translate_neg(self.char_index)) { break;
find_op = Some(new_op); }
} }
// for example: extract the ops from three insert ops with interval [2,5). the }
// interval size is larger than the op. Moving the offset to extract each part.
// Each step would be the small value between interval.size() and pub fn next_op_with_length(&mut self, length: Option<usize>) -> Option<Operation> {
// next_op.length(). Checkout the delta_get_ops_in_interval_4 for more details. let mut find_op = None;
// let next_op = self.next_op.take();
// ┌──────┐ ┌──────┐ ┌──────┐ let mut next_op = next_op.as_ref();
// │ 1 2 │ │ 3 4 │ │ 5 6 │ if next_op.is_none() {
// └──────┘ └─▲────┘ └───▲──┘ next_op = self.iter.next();
// │ [2, 5) │ self.o_index += 1;
// }
self.char_index += min(self.interval.size(), op.length());
while find_op.is_none() && next_op.is_some() {
let op = next_op.unwrap();
let start = self.c_index;
let end = match length {
None => self.c_index + op.length(),
Some(length) => self.c_index + min(length, op.length()),
};
let intersect = Interval::new(start, end).intersect(self.next_iv);
let interval = intersect.translate_neg(start);
let op_interval = Interval::new(0, op.length());
let suffix = op_interval.suffix(interval);
find_op = op.shrink(interval);
if !suffix.is_empty() {
self.next_op = op.shrink(suffix);
} }
match find_op { self.c_index = intersect.end;
None => next_op = self.iterator.next(), self.next_iv.start = intersect.end;
Some(_) => self.interval.start = self.char_index,
if find_op.is_none() {
next_op = self.iter.next();
} }
} }
find_op find_op
} }
pub fn seek<M: Metric>(&mut self, index: usize) -> Result<(), OTError> { pub fn next_op(&mut self) -> Option<Operation> { self.next_op_with_length(None) }
self.current_op = M::seek(self, index)?;
Ok(()) pub fn has_next(&self) -> bool { self.c_index < self.next_iv.end }
}
} }
type SeekResult = Result<(), OTError>;
pub trait Metric { pub trait Metric {
fn seek<'a, 'b>( fn seek(cursor: &mut Cursor, index: usize) -> SeekResult;
cursor: &'b mut Cursor<'a>,
index: usize,
) -> Result<Option<&'a Operation>, OTError>;
} }
pub struct OpMetric {} pub struct OpMetric {}
impl Metric for OpMetric { impl Metric for OpMetric {
fn seek<'a, 'b>( fn seek(cursor: &mut Cursor, index: usize) -> SeekResult {
cursor: &'b mut Cursor<'a>, let _ = check_bound(cursor.o_index, index)?;
index: usize, let mut temp_cursor = Cursor::new(cursor.delta, cursor.origin_iv);
) -> Result<Option<&'a Operation>, OTError> { let mut offset = 0;
let _ = check_bound(cursor.op_index, index)?; while let Some(op) = temp_cursor.iter.next() {
offset += op.length();
let mut offset = cursor.op_index; if offset > index {
let mut op_at_index = None;
while let Some(op) = cursor.iterator.next() {
if offset != cursor.op_index {
cursor.char_index += op.length();
cursor.op_index = offset;
}
offset += 1;
op_at_index = Some(op);
if offset >= index {
break; break;
} }
} }
cursor.descend(offset);
Ok(op_at_index) Ok(())
} }
} }
pub struct CharMetric {} pub struct CharMetric {}
impl Metric for CharMetric { impl Metric for CharMetric {
fn seek<'a, 'b>( fn seek(cursor: &mut Cursor, index: usize) -> SeekResult {
cursor: &'b mut Cursor<'a>, let _ = check_bound(cursor.c_index, index)?;
index: usize, let _ = cursor.next_op_with_length(Some(index));
) -> Result<Option<&'a Operation>, OTError> { Ok(())
let _ = check_bound(cursor.char_index, index)?;
let mut offset = cursor.char_index;
let mut op_at_index = None;
while let Some(op) = cursor.iterator.next() {
if offset != cursor.char_index {
cursor.char_index = offset;
cursor.op_index += 1;
}
offset += op.length();
op_at_index = Some(op);
if offset >= index {
break;
}
}
Ok(op_at_index)
} }
} }

View File

@ -12,7 +12,7 @@ pub struct DeltaIter<'a> {
impl<'a> DeltaIter<'a> { impl<'a> DeltaIter<'a> {
pub fn new(delta: &'a Delta) -> Self { pub fn new(delta: &'a Delta) -> Self {
let interval = Interval::new(0, usize::MAX); let interval = Interval::new(0, i32::MAX as usize);
Self::from_interval(delta, interval) Self::from_interval(delta, interval)
} }
@ -23,15 +23,23 @@ impl<'a> DeltaIter<'a> {
pub fn ops(&mut self) -> Vec<Operation> { self.collect::<Vec<_>>() } pub fn ops(&mut self) -> Vec<Operation> { self.collect::<Vec<_>>() }
pub fn seek(&mut self, n_char: usize) -> Result<(), OTError> { pub fn next_op(&mut self) -> Option<Operation> { self.cursor.next_op() }
let _ = self.cursor.seek::<CharMetric>(n_char)?;
pub fn next_op_with_length(&mut self, length: usize) -> Option<Operation> {
self.cursor.next_op_with_length(Some(length))
}
pub fn seek<M: Metric>(&mut self, index: usize) -> Result<(), OTError> {
let _ = M::seek(&mut self.cursor, index)?;
Ok(()) Ok(())
} }
pub fn has_next(&self) -> bool { self.cursor.has_next() }
} }
impl<'a> Iterator for DeltaIter<'a> { impl<'a> Iterator for DeltaIter<'a> {
type Item = Operation; type Item = Operation;
fn next(&mut self) -> Option<Self::Item> { self.cursor.next_op() } fn next(&mut self) -> Option<Self::Item> { self.next_op() }
} }
pub struct AttributesIter<'a> { pub struct AttributesIter<'a> {
@ -100,11 +108,10 @@ impl<'a> Iterator for AttributesIter<'a> {
} }
} }
pub(crate) fn attributes_at_index(delta: &Delta, index: usize) -> Attributes { pub(crate) fn attributes_with_length(delta: &Delta, index: usize) -> Attributes {
let mut iter = AttributesIter::new(delta); let mut iter = AttributesIter::new(delta);
iter.seek(index); iter.seek::<CharMetric>(index);
match iter.next() { match iter.next() {
// None => Attributes::Follow,
None => Attributes::new(), None => Attributes::new(),
Some((_, attributes)) => attributes, Some((_, attributes)) => attributes,
} }

View File

@ -62,6 +62,37 @@ impl Operation {
pub fn is_empty(&self) -> bool { self.length() == 0 } pub fn is_empty(&self) -> bool { self.length() == 0 }
pub fn split(&self, index: usize) -> (Option<Operation>, Option<Operation>) {
debug_assert!(index < self.length());
let mut left = None;
let mut right = None;
match self {
Operation::Delete(n) => {
left = Some(Builder::delete(index).build());
right = Some(Builder::delete(*n - index).build());
},
Operation::Retain(retain) => {
left = Some(Builder::delete(index).build());
right = Some(Builder::delete(retain.n - index).build());
},
Operation::Insert(insert) => {
let attributes = self.get_attributes();
left = Some(
Builder::insert(&insert.s[0..index])
.attributes(attributes.clone())
.build(),
);
right = Some(
Builder::insert(&insert.s[index..insert.num_chars()])
.attributes(attributes)
.build(),
);
},
}
(left, right)
}
pub fn shrink(&self, interval: Interval) -> Option<Operation> { pub fn shrink(&self, interval: Interval) -> Option<Operation> {
let op = match self { let op = match self {
Operation::Delete(n) => Builder::delete(min(*n, interval.size())).build(), Operation::Delete(n) => Builder::delete(min(*n, interval.size())).build(),

View File

@ -60,7 +60,7 @@ impl OpTester {
static INIT: Once = Once::new(); static INIT: Once = Once::new();
INIT.call_once(|| { INIT.call_once(|| {
color_eyre::install().unwrap(); color_eyre::install().unwrap();
std::env::set_var("RUST_LOG", "debug"); std::env::set_var("RUST_LOG", "info");
env_logger::init(); env_logger::init();
}); });

View File

@ -36,6 +36,11 @@ fn delta_get_ops_in_interval_2() {
vec![Builder::insert("12").build()] vec![Builder::insert("12").build()]
); );
assert_eq!(
DeltaIter::from_interval(&delta, Interval::new(1, 3)).ops(),
vec![Builder::insert("23").build()]
);
assert_eq!( assert_eq!(
DeltaIter::from_interval(&delta, Interval::new(0, 3)).ops(), DeltaIter::from_interval(&delta, Interval::new(0, 3)).ops(),
vec![insert_a.clone()] vec![insert_a.clone()]
@ -110,10 +115,10 @@ fn delta_get_ops_in_interval_5() {
vec![Builder::insert("56").build(), Builder::insert("78").build()] vec![Builder::insert("56").build(), Builder::insert("78").build()]
); );
assert_eq!( // assert_eq!(
DeltaIter::from_interval(&delta, Interval::new(8, 9)).ops(), // DeltaIter::from_interval(&delta, Interval::new(8, 9)).ops(),
vec![Builder::insert("9").build()] // vec![Builder::insert("9").build()]
); // );
} }
#[test] #[test]
@ -127,6 +132,91 @@ fn delta_get_ops_in_interval_6() {
); );
} }
#[test]
fn delta_get_ops_in_interval_7() {
let mut delta = Delta::default();
let insert_a = Builder::insert("12345").build();
let retain_a = Builder::retain(3).build();
delta.add(insert_a.clone());
delta.add(retain_a.clone());
let mut iter_1 = DeltaIter::new(&delta);
iter_1.seek::<CharMetric>(2).unwrap();
assert_eq!(iter_1.next_op().unwrap(), Builder::insert("345").build());
assert_eq!(iter_1.next_op().unwrap(), Builder::retain(3).build());
let mut iter_2 = DeltaIter::new(&delta);
assert_eq!(
iter_2.next_op_with_length(2).unwrap(),
Builder::insert("12").build()
);
assert_eq!(iter_2.next_op().unwrap(), Builder::insert("345").build());
assert_eq!(iter_2.next_op().unwrap(), Builder::retain(3).build());
}
#[test]
fn delta_seek_1() {
let mut delta = Delta::default();
let insert_a = Builder::insert("12345").build();
let retain_a = Builder::retain(3).build();
delta.add(insert_a.clone());
delta.add(retain_a.clone());
let mut iter = DeltaIter::new(&delta);
iter.seek::<OpMetric>(1).unwrap();
assert_eq!(iter.next_op().unwrap(), Builder::retain(3).build());
}
#[test]
fn delta_seek_2() {
let mut delta = Delta::default();
delta.add(Builder::insert("12345").build());
let mut iter = DeltaIter::new(&delta);
assert_eq!(
iter.next_op_with_length(1).unwrap(),
Builder::insert("1").build()
);
}
#[test]
fn delta_seek_3() {
let mut delta = Delta::default();
delta.add(Builder::insert("12345").build());
let mut iter = DeltaIter::new(&delta);
assert_eq!(
iter.next_op_with_length(2).unwrap(),
Builder::insert("12").build()
);
assert_eq!(
iter.next_op_with_length(2).unwrap(),
Builder::insert("34").build()
);
assert_eq!(
iter.next_op_with_length(2).unwrap(),
Builder::insert("5").build()
);
assert_eq!(iter.next_op_with_length(1), None);
}
#[test]
fn delta_seek_4() {
let mut delta = Delta::default();
delta.add(Builder::insert("12345").build());
let mut iter = DeltaIter::new(&delta);
iter.seek::<CharMetric>(3);
assert_eq!(
iter.next_op_with_length(2).unwrap(),
Builder::insert("45").build()
);
}
#[test] #[test]
fn lengths() { fn lengths() {
let mut delta = Delta::default(); let mut delta = Delta::default();