add format and insert extension

This commit is contained in:
appflowy 2021-08-11 23:34:35 +08:00
parent e4a64fd06a
commit 1ec4655d1b
17 changed files with 386 additions and 236 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

@ -17,6 +17,10 @@ pub struct Document {
impl Document { impl Document {
pub fn new() -> Self { pub fn new() -> Self {
let delta = Delta::new(); let delta = Delta::new();
Self::from_delta(delta)
}
pub fn from_delta(delta: Delta) -> Self {
Document { Document {
delta, delta,
history: History::new(), history: History::new(),
@ -35,7 +39,7 @@ impl Document {
); );
} }
let delta = self.view.handle_insert(&self.delta, text, index); let delta = self.view.insert(&self.delta, text, index)?;
let interval = Interval::new(index, index); let interval = Interval::new(index, index);
self.update_with_op(&delta, interval) self.update_with_op(&delta, interval)
} }
@ -139,7 +143,7 @@ impl Document {
) -> Result<(), OTError> { ) -> Result<(), OTError> {
log::debug!("Update document with attribute: {}", attribute); log::debug!("Update document with attribute: {}", attribute);
let mut attributes = AttrsBuilder::new().add(attribute).build(); let mut attributes = AttrsBuilder::new().add(attribute).build();
let old_attributes = self.delta.get_attributes(interval); let old_attributes = AttributesIter::from_interval(&self.delta, interval).next_or_empty();
log::debug!("combine with old: {:?}", old_attributes); log::debug!("combine with old: {:?}", old_attributes);
attributes.merge(Some(old_attributes)); attributes.merge(Some(old_attributes));
@ -202,17 +206,3 @@ fn split_length_with_interval(length: usize, interval: Interval) -> (Interval, I
let suffix = original_interval.suffix(interval); let suffix = original_interval.suffix(interval);
(prefix, interval, suffix) (prefix, interval, suffix)
} }
pub fn trim(delta: &mut Delta) {
let remove_last = match delta.ops.last() {
None => false,
Some(op) => match op {
Operation::Delete(_) => false,
Operation::Retain(retain) => retain.is_plain(),
Operation::Insert(_) => false,
},
};
if remove_last {
delta.ops.pop();
}
}

View File

@ -1,16 +1,16 @@
use crate::{ use crate::{
client::Document, client::Document,
core::{Attributes, Delta, Interval}, core::{Attribute, Delta, Interval},
}; };
pub trait InsertExt { pub trait InsertExt {
fn apply(&self, delta: &Delta, s: &str, index: usize) -> Delta; fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta>;
} }
pub trait FormatExt { pub trait FormatExt {
fn apply(&self, document: &Document, interval: Interval, attributes: Attributes); fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta>;
} }
pub trait DeleteExt { pub trait DeleteExt {
fn apply(&self, document: &Document, interval: Interval); fn apply(&self, delta: &Delta, interval: Interval) -> Option<Delta>;
} }

View File

@ -0,0 +1,28 @@
use crate::{
client::view::FormatExt,
core::{Attribute, Delta, Interval},
};
pub struct FormatLinkAtCaretPositionExt {}
impl FormatExt for FormatLinkAtCaretPositionExt {
fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
unimplemented!()
}
}
pub struct ResolveLineFormatExt {}
impl FormatExt for ResolveLineFormatExt {
fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
unimplemented!()
}
}
pub struct ResolveInlineFormatExt {}
impl FormatExt for ResolveInlineFormatExt {
fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
unimplemented!()
}
}

View File

@ -1,21 +1,73 @@
use crate::{ use crate::{
client::view::InsertExt, client::view::InsertExt,
core::{attributes_at_index, Attributes, AttributesIter, Builder, Delta, Interval}, core::{
attributes_at_index,
AttributeKey,
Attributes,
Delta,
DeltaBuilder,
DeltaIter,
Operation,
},
}; };
pub struct PreserveInlineStyleExt {} pub const NEW_LINE: &'static str = "\n";
pub struct PreserveInlineStyleExt {}
impl PreserveInlineStyleExt { impl PreserveInlineStyleExt {
pub fn new() -> Self { Self {} } pub fn new() -> Self { Self {} }
} }
impl InsertExt for PreserveInlineStyleExt { impl InsertExt for PreserveInlineStyleExt {
fn apply(&self, delta: &Delta, text: &str, index: usize) -> Delta { fn apply(&self, delta: &Delta, _replace_len: usize, text: &str, index: usize) -> Option<Delta> {
let attributes = attributes_at_index(delta, index); if text.ends_with(NEW_LINE) {
let mut delta = Delta::new(); return None;
let insert = Builder::insert(text).attributes(attributes).build(); }
delta.add(insert);
delta let attributes = attributes_at_index(delta, index);
let delta = DeltaBuilder::new().insert(text, attributes).build();
Some(delta)
}
}
pub struct ResetLineFormatOnNewLineExt {}
impl ResetLineFormatOnNewLineExt {
pub fn new() -> Self { Self {} }
}
impl InsertExt for ResetLineFormatOnNewLineExt {
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
if text != NEW_LINE {
return None;
}
let mut iter = DeltaIter::new(delta);
iter.seek_to(index);
let maybe_next_op = iter.next();
if maybe_next_op.is_none() {
return None;
}
let op = maybe_next_op.unwrap();
if !op.get_data().starts_with(NEW_LINE) {
return None;
}
let mut reset_attribute = Attributes::new();
if op.get_attributes().contains_key(&AttributeKey::Header) {
reset_attribute.add(AttributeKey::Header.with_value(""));
}
let len = index + replace_len;
Some(
DeltaBuilder::new()
.retain(len, Attributes::default())
.insert(NEW_LINE, op.get_attributes())
.retain(1, reset_attribute)
.trim()
.build(),
)
} }
} }

View File

@ -1,7 +1,9 @@
mod extension; mod extension;
mod format_ext;
mod insert_ext; mod insert_ext;
mod view; mod view;
pub use extension::*; pub use extension::*;
pub use format_ext::*;
pub use insert_ext::*; pub use insert_ext::*;
pub use view::*; pub use view::*;

View File

@ -1,32 +1,94 @@
use crate::{ use crate::{
client::view::{InsertExt, PreserveInlineStyleExt}, client::view::{DeleteExt, FormatExt, InsertExt, *},
core::Delta, core::{Attribute, Delta, Interval},
errors::{ErrorBuilder, OTError, OTErrorCode},
}; };
type InsertExtension = Box<dyn InsertExt>; type InsertExtension = Box<dyn InsertExt>;
type FormatExtension = Box<dyn FormatExt>;
type DeleteExtension = Box<dyn DeleteExt>;
pub struct View { pub struct View {
insert_exts: Vec<InsertExtension>, insert_exts: Vec<InsertExtension>,
format_exts: Vec<FormatExtension>,
delete_exts: Vec<DeleteExtension>,
} }
impl View { impl View {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
let insert_exts = construct_insert_exts(); let insert_exts = construct_insert_exts();
Self { insert_exts } let format_exts = construct_format_exts();
let delete_exts = construct_delete_exts();
Self {
insert_exts,
format_exts,
delete_exts,
}
} }
pub(crate) fn handle_insert(&self, delta: &Delta, s: &str, index: usize) -> Delta { pub(crate) fn insert(&self, delta: &Delta, text: &str, index: usize) -> Result<Delta, OTError> {
let mut new_delta = Delta::new(); let mut new_delta = None;
self.insert_exts.iter().for_each(|ext| { for ext in &self.insert_exts {
new_delta = ext.apply(delta, s, index); if let Some(delta) = ext.apply(delta, 0, text, index) {
}); new_delta = Some(delta);
new_delta break;
}
}
match new_delta {
None => Err(ErrorBuilder::new(OTErrorCode::ApplyInsertFail).build()),
Some(new_delta) => Ok(new_delta),
}
}
pub(crate) fn replace(
&self,
delta: &Delta,
text: &str,
interval: Interval,
) -> Result<Delta, OTError> {
unimplemented!()
}
pub(crate) fn format(
&self,
delta: &Delta,
attribute: Attribute,
interval: Interval,
) -> Result<Delta, OTError> {
let mut new_delta = None;
for ext in &self.format_exts {
if let Some(delta) = ext.apply(delta, interval, &attribute) {
new_delta = Some(delta);
break;
}
}
match new_delta {
None => Err(ErrorBuilder::new(OTErrorCode::ApplyFormatFail).build()),
Some(new_delta) => Ok(new_delta),
}
} }
} }
fn construct_insert_exts() -> Vec<InsertExtension> { fn construct_insert_exts() -> Vec<InsertExtension> {
vec![ vec![
//
Box::new(PreserveInlineStyleExt::new()), Box::new(PreserveInlineStyleExt::new()),
Box::new(ResetLineFormatOnNewLineExt::new()),
]
}
fn construct_format_exts() -> Vec<FormatExtension> {
vec![
Box::new(FormatLinkAtCaretPositionExt {}),
Box::new(ResolveLineFormatExt {}),
Box::new(ResolveInlineFormatExt {}),
]
}
fn construct_delete_exts() -> Vec<DeleteExtension> {
vec![
//
] ]
} }

View File

@ -1,5 +1,5 @@
use crate::core::{Attribute, AttributeKey, Operation}; use crate::core::{Attribute, AttributeKey, Operation};
use std::{collections::HashMap, fmt, fmt::Formatter}; use std::{collections::HashMap, fmt};
pub const REMOVE_FLAG: &'static str = ""; pub const REMOVE_FLAG: &'static str = "";
pub(crate) fn should_remove(s: &str) -> bool { s == REMOVE_FLAG } pub(crate) fn should_remove(s: &str) -> bool { s == REMOVE_FLAG }

View File

@ -0,0 +1,44 @@
use crate::core::{Attributes, Delta, Operation};
pub struct DeltaBuilder {
delta: Delta,
}
impl DeltaBuilder {
pub fn new() -> Self {
Self {
delta: Delta::new(),
}
}
pub fn retain(mut self, n: usize, attrs: Attributes) -> Self {
self.delta.retain(n, attrs);
self
}
pub fn insert(mut self, s: &str, attrs: Attributes) -> Self {
self.delta.insert(s, attrs);
self
}
pub fn trim(mut self) -> Self {
trim(&mut self.delta);
self
}
pub fn build(self) -> Delta { self.delta }
}
pub fn trim(delta: &mut Delta) {
let remove_last = match delta.ops.last() {
None => false,
Some(op) => match op {
Operation::Delete(_) => false,
Operation::Retain(retain) => retain.is_plain(),
Operation::Insert(_) => false,
},
};
if remove_last {
delta.ops.pop();
}
}

View File

@ -1,12 +1,8 @@
use crate::{ use crate::{
core::{Attributes, Delta, Interval, Operation}, core::{Delta, Interval, Operation},
errors::{ErrorBuilder, OTError, OTErrorCode}, errors::{ErrorBuilder, OTError, OTErrorCode},
}; };
use std::{ use std::{cmp::min, slice::Iter};
cmp::min,
ops::{Deref, DerefMut},
slice::Iter,
};
pub struct Cursor<'a> { pub struct Cursor<'a> {
delta: &'a Delta, delta: &'a Delta,
@ -111,108 +107,3 @@ impl<'a> Cursor<'a> {
Ok(()) Ok(())
} }
} }
pub struct DeltaIter<'a> {
cursor: Cursor<'a>,
interval: Interval,
}
impl<'a> DeltaIter<'a> {
pub fn new(delta: &'a Delta) -> Self {
let interval = Interval::new(0, usize::MAX);
Self::from_interval(delta, interval)
}
pub fn from_interval(delta: &'a Delta, interval: Interval) -> Self {
let cursor = Cursor::new(delta, interval);
Self { cursor, interval }
}
pub fn ops(&mut self) -> Vec<Operation> { self.collect::<Vec<_>>() }
pub fn seek_to(&mut self, n_char: usize) -> Result<(), OTError> {
let _ = self.cursor.seek_to(n_char)?;
Ok(())
}
}
impl<'a> Iterator for DeltaIter<'a> {
type Item = Operation;
fn next(&mut self) -> Option<Self::Item> { self.cursor.next_op() }
}
pub struct AttributesIter<'a> {
delta_iter: DeltaIter<'a>,
interval: Interval,
}
impl<'a> AttributesIter<'a> {
pub fn new(delta: &'a Delta) -> Self {
let interval = Interval::new(0, usize::MAX);
Self::from_interval(delta, interval)
}
pub fn from_interval(delta: &'a Delta, interval: Interval) -> Self {
let delta_iter = DeltaIter::from_interval(delta, interval);
Self {
delta_iter,
interval,
}
}
}
impl<'a> Deref for AttributesIter<'a> {
type Target = DeltaIter<'a>;
fn deref(&self) -> &Self::Target { &self.delta_iter }
}
impl<'a> DerefMut for AttributesIter<'a> {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.delta_iter }
}
impl<'a> Iterator for AttributesIter<'a> {
type Item = (usize, Attributes);
fn next(&mut self) -> Option<Self::Item> {
let next_op = self.delta_iter.next();
if next_op.is_none() {
return None;
}
let mut length: usize = 0;
let mut attributes = Attributes::new();
match next_op.unwrap() {
Operation::Delete(_n) => {},
Operation::Retain(retain) => {
log::debug!("extend retain attributes with {} ", &retain.attributes);
attributes.extend(retain.attributes.clone());
length = retain.n;
},
Operation::Insert(insert) => {
log::debug!("extend insert attributes with {} ", &insert.attributes);
attributes.extend(insert.attributes.clone());
length = insert.num_chars();
},
}
Some((length, attributes))
}
}
pub(crate) fn attributes_at_index(delta: &Delta, index: usize) -> Attributes {
let mut iter = AttributesIter::new(delta);
iter.seek_to(index);
match iter.next() {
// None => Attributes::Follow,
None => Attributes::new(),
Some((_, attributes)) => attributes,
}
}
#[cfg(test)]
mod tests {
#[test]
fn test() {}
}

View File

@ -525,34 +525,6 @@ impl Delta {
pub fn is_empty(&self) -> bool { self.ops.is_empty() } pub fn is_empty(&self) -> bool { self.ops.is_empty() }
pub fn get_attributes(&self, interval: Interval) -> Attributes {
let mut attributes = Attributes::new();
let mut offset: usize = 0;
log::debug!("Get attributes at {:?}", interval);
self.ops.iter().for_each(|op| match op {
Operation::Delete(_n) => {},
Operation::Retain(retain) => {
if interval.contains_range(offset, offset + retain.n) {
log::debug!("extend retain attributes with {} ", &retain.attributes);
attributes.extend(retain.attributes.clone());
}
offset += retain.n;
},
Operation::Insert(insert) => {
let end = insert.num_chars() as usize;
if interval.contains_range(offset, offset + end) {
log::debug!("extend insert attributes with {} ", &insert.attributes);
attributes.extend(insert.attributes.clone());
}
offset += end;
},
});
log::debug!("Get attributes result: {} ", &attributes);
attributes
}
pub fn to_json(&self) -> String { serde_json::to_string(self).unwrap_or("".to_owned()) } pub fn to_json(&self) -> String { serde_json::to_string(self).unwrap_or("".to_owned()) }
} }

View File

@ -0,0 +1,111 @@
use super::cursor::*;
use crate::{
core::{Attributes, Delta, Interval, Operation},
errors::OTError,
};
use std::ops::{Deref, DerefMut};
pub struct DeltaIter<'a> {
cursor: Cursor<'a>,
interval: Interval,
}
impl<'a> DeltaIter<'a> {
pub fn new(delta: &'a Delta) -> Self {
let interval = Interval::new(0, usize::MAX);
Self::from_interval(delta, interval)
}
pub fn from_interval(delta: &'a Delta, interval: Interval) -> Self {
let cursor = Cursor::new(delta, interval);
Self { cursor, interval }
}
pub fn ops(&mut self) -> Vec<Operation> { self.collect::<Vec<_>>() }
pub fn seek_to(&mut self, n_char: usize) -> Result<(), OTError> {
let _ = self.cursor.seek_to(n_char)?;
Ok(())
}
}
impl<'a> Iterator for DeltaIter<'a> {
type Item = Operation;
fn next(&mut self) -> Option<Self::Item> { self.cursor.next_op() }
}
pub struct AttributesIter<'a> {
delta_iter: DeltaIter<'a>,
interval: Interval,
}
impl<'a> AttributesIter<'a> {
pub fn new(delta: &'a Delta) -> Self {
let interval = Interval::new(0, usize::MAX);
Self::from_interval(delta, interval)
}
pub fn from_interval(delta: &'a Delta, interval: Interval) -> Self {
let delta_iter = DeltaIter::from_interval(delta, interval);
Self {
delta_iter,
interval,
}
}
pub fn next_or_empty(&mut self) -> Attributes {
match self.next() {
None => Attributes::default(),
Some((_, attributes)) => attributes,
}
}
}
impl<'a> Deref for AttributesIter<'a> {
type Target = DeltaIter<'a>;
fn deref(&self) -> &Self::Target { &self.delta_iter }
}
impl<'a> DerefMut for AttributesIter<'a> {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.delta_iter }
}
impl<'a> Iterator for AttributesIter<'a> {
type Item = (usize, Attributes);
fn next(&mut self) -> Option<Self::Item> {
let next_op = self.delta_iter.next();
if next_op.is_none() {
return None;
}
let mut length: usize = 0;
let mut attributes = Attributes::new();
match next_op.unwrap() {
Operation::Delete(_n) => {},
Operation::Retain(retain) => {
log::debug!("extend retain attributes with {} ", &retain.attributes);
attributes.extend(retain.attributes.clone());
length = retain.n;
},
Operation::Insert(insert) => {
log::debug!("extend insert attributes with {} ", &insert.attributes);
attributes.extend(insert.attributes.clone());
length = insert.num_chars();
},
}
Some((length, attributes))
}
}
pub(crate) fn attributes_at_index(delta: &Delta, index: usize) -> Attributes {
let mut iter = AttributesIter::new(delta);
iter.seek_to(index);
match iter.next() {
// None => Attributes::Follow,
None => Attributes::new(),
Some((_, attributes)) => attributes,
}
}

View File

@ -1,5 +1,9 @@
mod builder;
mod cursor; mod cursor;
mod delta; mod delta;
mod iterator;
pub use builder::*;
pub use cursor::*; pub use cursor::*;
pub use delta::*; pub use delta::*;
pub use iterator::*;

View File

@ -16,17 +16,11 @@ pub enum Operation {
} }
impl Operation { impl Operation {
pub fn is_delete(&self) -> bool { pub fn get_data(&self) -> &str {
match self { match self {
Operation::Delete(_) => true, Operation::Delete(_) => "",
_ => false, Operation::Retain(_) => "",
} Operation::Insert(insert) => &insert.s,
}
pub fn is_noop(&self) -> bool {
match self {
Operation::Retain(_) => true,
_ => false,
} }
} }

View File

@ -26,6 +26,8 @@ impl Error for OTError {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum OTErrorCode { pub enum OTErrorCode {
IncompatibleLength, IncompatibleLength,
ApplyInsertFail,
ApplyFormatFail,
UndoFail, UndoFail,
RedoFail, RedoFail,
} }

View File

@ -64,11 +64,7 @@ impl OpTester {
env_logger::init(); env_logger::init();
}); });
let mut documents = Vec::with_capacity(2); Self { documents: vec![] }
for _ in 0..2 {
documents.push(Document::new());
}
Self { documents }
} }
pub fn run_op(&mut self, op: &TestOp) { pub fn run_op(&mut self, op: &TestOp) {
@ -173,6 +169,22 @@ impl OpTester {
} }
pub fn run_script(&mut self, script: Vec<TestOp>) { pub fn run_script(&mut self, script: Vec<TestOp>) {
let delta = Delta::new();
self.run(script, delta);
}
pub fn run_script_with_newline(&mut self, script: Vec<TestOp>) {
let mut delta = Delta::new();
delta.insert("\n", Attributes::default());
self.run(script, delta);
}
fn run(&mut self, script: Vec<TestOp>, delta: Delta) {
let mut documents = Vec::with_capacity(2);
for _ in 0..2 {
documents.push(Document::from_delta(delta.clone()));
}
self.documents = documents;
for (_i, op) in script.iter().enumerate() { for (_i, op) in script.iter().enumerate() {
self.run_op(op); self.run_op(op);
} }

View File

@ -6,18 +6,16 @@ use flowy_ot::{client::RECORD_THRESHOLD, core::Interval};
#[test] #[test]
fn delta_undo_insert() { fn delta_undo_insert() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertOpsJson(0, r#"[{"insert":"\n"}]"#),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
fn delta_undo_insert2() { fn delta_undo_insert2() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Insert(0, "456", 0), Insert(0, "456", 0),
@ -26,13 +24,12 @@ fn delta_undo_insert2() {
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertOpsJson(0, r#"[{"insert":"\n"}]"#),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
fn delta_redo_insert() { fn delta_redo_insert() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), AssertOpsJson(0, r#"[{"insert":"123\n"}]"#),
Undo(0), Undo(0),
@ -40,13 +37,12 @@ fn delta_redo_insert() {
Redo(0), Redo(0),
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), AssertOpsJson(0, r#"[{"insert":"123\n"}]"#),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
fn delta_redo_insert_with_lagging() { fn delta_redo_insert_with_lagging() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Insert(0, "456", 3), Insert(0, "456", 3),
@ -60,38 +56,35 @@ fn delta_redo_insert_with_lagging() {
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), AssertOpsJson(0, r#"[{"insert":"123\n"}]"#),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
fn delta_undo_attributes() { fn delta_undo_attributes() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertOpsJson(0, r#"[{"insert":"\n"}]"#),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
fn delta_undo_attributes_with_lagging() { fn delta_undo_attributes_with_lagging() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), AssertOpsJson(0, r#"[{"insert":"123\n"}]"#),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
fn delta_redo_attributes() { fn delta_redo_attributes() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Undo(0), Undo(0),
@ -102,13 +95,12 @@ fn delta_redo_attributes() {
r#" [{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#, r#" [{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#,
), ),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
fn delta_redo_attributes_with_lagging() { fn delta_redo_attributes_with_lagging() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
@ -120,7 +112,7 @@ fn delta_redo_attributes_with_lagging() {
r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#, r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#,
), ),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
@ -139,7 +131,6 @@ fn delta_undo_delete() {
#[test] #[test]
fn delta_undo_delete2() { fn delta_undo_delete2() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Delete(0, Interval::new(0, 1)), Delete(0, Interval::new(0, 1)),
@ -153,13 +144,12 @@ fn delta_undo_delete2() {
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertOpsJson(0, r#"[{"insert":"\n"}]"#),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
fn delta_undo_delete2_with_lagging() { fn delta_undo_delete2_with_lagging() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
@ -181,13 +171,12 @@ fn delta_undo_delete2_with_lagging() {
"#, "#,
), ),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
fn delta_redo_delete() { fn delta_redo_delete() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Delete(0, Interval::new(0, 3)), Delete(0, Interval::new(0, 3)),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertOpsJson(0, r#"[{"insert":"\n"}]"#),
@ -195,13 +184,12 @@ fn delta_redo_delete() {
Redo(0), Redo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertOpsJson(0, r#"[{"insert":"\n"}]"#),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
fn delta_undo_replace() { fn delta_undo_replace() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Replace(0, Interval::new(0, 2), "ab"), Replace(0, Interval::new(0, 2), "ab"),
@ -215,13 +203,12 @@ fn delta_undo_replace() {
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertOpsJson(0, r#"[{"insert":"\n"}]"#),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
fn delta_undo_replace_with_lagging() { fn delta_undo_replace_with_lagging() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
@ -240,13 +227,12 @@ fn delta_undo_replace_with_lagging() {
r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#, r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#,
), ),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }
#[test] #[test]
fn delta_redo_replace() { fn delta_redo_replace() {
let ops = vec![ let ops = vec![
Insert(0, "\n", 0),
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Replace(0, Interval::new(0, 2), "ab"), Replace(0, Interval::new(0, 2), "ab"),
@ -260,5 +246,5 @@ fn delta_redo_replace() {
"#, "#,
), ),
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script_with_newline(ops);
} }