From 1ec4655d1ba284a34bdc860f643800719e451174 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 11 Aug 2021 23:34:35 +0800 Subject: [PATCH] add format and insert extension --- .../lib/src/model/heuristic/rule.dart | 30 ++--- rust-lib/flowy-ot/src/client/document.rs | 22 +--- .../flowy-ot/src/client/view/extension.rs | 8 +- .../flowy-ot/src/client/view/format_ext.rs | 28 +++++ .../flowy-ot/src/client/view/insert_ext.rs | 68 +++++++++-- rust-lib/flowy-ot/src/client/view/mod.rs | 2 + rust-lib/flowy-ot/src/client/view/view.rs | 82 +++++++++++-- .../src/core/attributes/attributes.rs | 2 +- rust-lib/flowy-ot/src/core/delta/builder.rs | 44 +++++++ rust-lib/flowy-ot/src/core/delta/cursor.rs | 113 +----------------- rust-lib/flowy-ot/src/core/delta/delta.rs | 28 ----- rust-lib/flowy-ot/src/core/delta/iterator.rs | 111 +++++++++++++++++ rust-lib/flowy-ot/src/core/delta/mod.rs | 4 + .../flowy-ot/src/core/operation/operation.rs | 14 +-- rust-lib/flowy-ot/src/errors.rs | 2 + rust-lib/flowy-ot/tests/helper/mod.rs | 22 +++- rust-lib/flowy-ot/tests/undo_redo_test.rs | 42 +++---- 17 files changed, 386 insertions(+), 236 deletions(-) create mode 100644 rust-lib/flowy-ot/src/client/view/format_ext.rs create mode 100644 rust-lib/flowy-ot/src/core/delta/builder.rs create mode 100644 rust-lib/flowy-ot/src/core/delta/iterator.rs diff --git a/app_flowy/packages/flowy_editor/lib/src/model/heuristic/rule.dart b/app_flowy/packages/flowy_editor/lib/src/model/heuristic/rule.dart index 5c96b0c15c..8dad3fa964 100644 --- a/app_flowy/packages/flowy_editor/lib/src/model/heuristic/rule.dart +++ b/app_flowy/packages/flowy_editor/lib/src/model/heuristic/rule.dart @@ -40,21 +40,21 @@ class Rules { final List _rules; static final Rules _instance = Rules([ - // const FormatLinkAtCaretPositionRule(), - // const ResolveLineFormatRule(), - // const ResolveInlineFormatRule(), - // const InsertEmbedsRule(), - // const ForceNewlineForInsertsAroundEmbedRule(), - // const AutoExitBlockRule(), - // const PreserveBlockStyleOnInsertRule(), - // const PreserveLineStyleOnSplitRule(), - // const ResetLineFormatOnNewLineRule(), - // const AutoFormatLinksRule(), - // const PreserveInlineStylesRule(), - // const CatchAllInsertRule(), - // const EnsureEmbedLineRule(), - // const PreserveLineStyleOnMergeRule(), - // const CatchAllDeleteRule(), + const FormatLinkAtCaretPositionRule(), + const ResolveLineFormatRule(), + const ResolveInlineFormatRule(), + const InsertEmbedsRule(), + const ForceNewlineForInsertsAroundEmbedRule(), + const AutoExitBlockRule(), + const PreserveBlockStyleOnInsertRule(), + const PreserveLineStyleOnSplitRule(), + const ResetLineFormatOnNewLineRule(), + const AutoFormatLinksRule(), + const PreserveInlineStylesRule(), + const CatchAllInsertRule(), + const EnsureEmbedLineRule(), + const PreserveLineStyleOnMergeRule(), + const CatchAllDeleteRule(), ]); static Rules getInstance() => _instance; diff --git a/rust-lib/flowy-ot/src/client/document.rs b/rust-lib/flowy-ot/src/client/document.rs index 759f7ebc96..640f5eb007 100644 --- a/rust-lib/flowy-ot/src/client/document.rs +++ b/rust-lib/flowy-ot/src/client/document.rs @@ -17,6 +17,10 @@ pub struct Document { impl Document { pub fn new() -> Self { let delta = Delta::new(); + Self::from_delta(delta) + } + + pub fn from_delta(delta: Delta) -> Self { Document { delta, 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); self.update_with_op(&delta, interval) } @@ -139,7 +143,7 @@ impl Document { ) -> Result<(), OTError> { log::debug!("Update document with attribute: {}", attribute); 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); 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); (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(); - } -} diff --git a/rust-lib/flowy-ot/src/client/view/extension.rs b/rust-lib/flowy-ot/src/client/view/extension.rs index 6ca5460d84..27f9be9bf5 100644 --- a/rust-lib/flowy-ot/src/client/view/extension.rs +++ b/rust-lib/flowy-ot/src/client/view/extension.rs @@ -1,16 +1,16 @@ use crate::{ client::Document, - core::{Attributes, Delta, Interval}, + core::{Attribute, Delta, Interval}, }; 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; } pub trait FormatExt { - fn apply(&self, document: &Document, interval: Interval, attributes: Attributes); + fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option; } pub trait DeleteExt { - fn apply(&self, document: &Document, interval: Interval); + fn apply(&self, delta: &Delta, interval: Interval) -> Option; } diff --git a/rust-lib/flowy-ot/src/client/view/format_ext.rs b/rust-lib/flowy-ot/src/client/view/format_ext.rs new file mode 100644 index 0000000000..bbbd786418 --- /dev/null +++ b/rust-lib/flowy-ot/src/client/view/format_ext.rs @@ -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 { + unimplemented!() + } +} + +pub struct ResolveLineFormatExt {} + +impl FormatExt for ResolveLineFormatExt { + fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option { + unimplemented!() + } +} + +pub struct ResolveInlineFormatExt {} + +impl FormatExt for ResolveInlineFormatExt { + fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option { + unimplemented!() + } +} diff --git a/rust-lib/flowy-ot/src/client/view/insert_ext.rs b/rust-lib/flowy-ot/src/client/view/insert_ext.rs index dd79700ea8..78fac0c6b7 100644 --- a/rust-lib/flowy-ot/src/client/view/insert_ext.rs +++ b/rust-lib/flowy-ot/src/client/view/insert_ext.rs @@ -1,21 +1,73 @@ use crate::{ 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 { pub fn new() -> Self { Self {} } } impl InsertExt for PreserveInlineStyleExt { - fn apply(&self, delta: &Delta, text: &str, index: usize) -> Delta { - let attributes = attributes_at_index(delta, index); - let mut delta = Delta::new(); - let insert = Builder::insert(text).attributes(attributes).build(); - delta.add(insert); + fn apply(&self, delta: &Delta, _replace_len: usize, text: &str, index: usize) -> Option { + if text.ends_with(NEW_LINE) { + return None; + } - 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 { + 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(), + ) } } diff --git a/rust-lib/flowy-ot/src/client/view/mod.rs b/rust-lib/flowy-ot/src/client/view/mod.rs index 6a5a4b14d0..2b8d8f9951 100644 --- a/rust-lib/flowy-ot/src/client/view/mod.rs +++ b/rust-lib/flowy-ot/src/client/view/mod.rs @@ -1,7 +1,9 @@ mod extension; +mod format_ext; mod insert_ext; mod view; pub use extension::*; +pub use format_ext::*; pub use insert_ext::*; pub use view::*; diff --git a/rust-lib/flowy-ot/src/client/view/view.rs b/rust-lib/flowy-ot/src/client/view/view.rs index 8bb73e123a..98bbad39ce 100644 --- a/rust-lib/flowy-ot/src/client/view/view.rs +++ b/rust-lib/flowy-ot/src/client/view/view.rs @@ -1,32 +1,94 @@ use crate::{ - client::view::{InsertExt, PreserveInlineStyleExt}, - core::Delta, + client::view::{DeleteExt, FormatExt, InsertExt, *}, + core::{Attribute, Delta, Interval}, + errors::{ErrorBuilder, OTError, OTErrorCode}, }; type InsertExtension = Box; +type FormatExtension = Box; +type DeleteExtension = Box; pub struct View { insert_exts: Vec, + format_exts: Vec, + delete_exts: Vec, } impl View { pub(crate) fn new() -> Self { 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 { - let mut new_delta = Delta::new(); - self.insert_exts.iter().for_each(|ext| { - new_delta = ext.apply(delta, s, index); - }); - new_delta + pub(crate) fn insert(&self, delta: &Delta, text: &str, index: usize) -> Result { + let mut new_delta = None; + for ext in &self.insert_exts { + if let Some(delta) = ext.apply(delta, 0, text, index) { + new_delta = Some(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 { + unimplemented!() + } + + pub(crate) fn format( + &self, + delta: &Delta, + attribute: Attribute, + interval: Interval, + ) -> Result { + 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 { vec![ - // Box::new(PreserveInlineStyleExt::new()), + Box::new(ResetLineFormatOnNewLineExt::new()), + ] +} + +fn construct_format_exts() -> Vec { + vec![ + Box::new(FormatLinkAtCaretPositionExt {}), + Box::new(ResolveLineFormatExt {}), + Box::new(ResolveInlineFormatExt {}), + ] +} + +fn construct_delete_exts() -> Vec { + vec![ + // + ] } diff --git a/rust-lib/flowy-ot/src/core/attributes/attributes.rs b/rust-lib/flowy-ot/src/core/attributes/attributes.rs index 56a92dab45..881c9001cb 100644 --- a/rust-lib/flowy-ot/src/core/attributes/attributes.rs +++ b/rust-lib/flowy-ot/src/core/attributes/attributes.rs @@ -1,5 +1,5 @@ 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(crate) fn should_remove(s: &str) -> bool { s == REMOVE_FLAG } diff --git a/rust-lib/flowy-ot/src/core/delta/builder.rs b/rust-lib/flowy-ot/src/core/delta/builder.rs new file mode 100644 index 0000000000..04d9b63a93 --- /dev/null +++ b/rust-lib/flowy-ot/src/core/delta/builder.rs @@ -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(); + } +} diff --git a/rust-lib/flowy-ot/src/core/delta/cursor.rs b/rust-lib/flowy-ot/src/core/delta/cursor.rs index 578f5d3ea9..d1f0c6dd75 100644 --- a/rust-lib/flowy-ot/src/core/delta/cursor.rs +++ b/rust-lib/flowy-ot/src/core/delta/cursor.rs @@ -1,12 +1,8 @@ use crate::{ - core::{Attributes, Delta, Interval, Operation}, + core::{Delta, Interval, Operation}, errors::{ErrorBuilder, OTError, OTErrorCode}, }; -use std::{ - cmp::min, - ops::{Deref, DerefMut}, - slice::Iter, -}; +use std::{cmp::min, slice::Iter}; pub struct Cursor<'a> { delta: &'a Delta, @@ -111,108 +107,3 @@ impl<'a> Cursor<'a> { 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 { self.collect::>() } - - 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.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 { - 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() {} -} diff --git a/rust-lib/flowy-ot/src/core/delta/delta.rs b/rust-lib/flowy-ot/src/core/delta/delta.rs index 06722aa300..b98f6bc598 100644 --- a/rust-lib/flowy-ot/src/core/delta/delta.rs +++ b/rust-lib/flowy-ot/src/core/delta/delta.rs @@ -525,34 +525,6 @@ impl Delta { 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()) } } diff --git a/rust-lib/flowy-ot/src/core/delta/iterator.rs b/rust-lib/flowy-ot/src/core/delta/iterator.rs new file mode 100644 index 0000000000..a72a3ce882 --- /dev/null +++ b/rust-lib/flowy-ot/src/core/delta/iterator.rs @@ -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 { self.collect::>() } + + 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.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 { + 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, + } +} diff --git a/rust-lib/flowy-ot/src/core/delta/mod.rs b/rust-lib/flowy-ot/src/core/delta/mod.rs index 03037fb79f..18b2df0264 100644 --- a/rust-lib/flowy-ot/src/core/delta/mod.rs +++ b/rust-lib/flowy-ot/src/core/delta/mod.rs @@ -1,5 +1,9 @@ +mod builder; mod cursor; mod delta; +mod iterator; +pub use builder::*; pub use cursor::*; pub use delta::*; +pub use iterator::*; diff --git a/rust-lib/flowy-ot/src/core/operation/operation.rs b/rust-lib/flowy-ot/src/core/operation/operation.rs index d59ff19658..7de196f991 100644 --- a/rust-lib/flowy-ot/src/core/operation/operation.rs +++ b/rust-lib/flowy-ot/src/core/operation/operation.rs @@ -16,17 +16,11 @@ pub enum Operation { } impl Operation { - pub fn is_delete(&self) -> bool { + pub fn get_data(&self) -> &str { match self { - Operation::Delete(_) => true, - _ => false, - } - } - - pub fn is_noop(&self) -> bool { - match self { - Operation::Retain(_) => true, - _ => false, + Operation::Delete(_) => "", + Operation::Retain(_) => "", + Operation::Insert(insert) => &insert.s, } } diff --git a/rust-lib/flowy-ot/src/errors.rs b/rust-lib/flowy-ot/src/errors.rs index 7a74d44e46..252b0f3f73 100644 --- a/rust-lib/flowy-ot/src/errors.rs +++ b/rust-lib/flowy-ot/src/errors.rs @@ -26,6 +26,8 @@ impl Error for OTError { #[derive(Debug, Clone)] pub enum OTErrorCode { IncompatibleLength, + ApplyInsertFail, + ApplyFormatFail, UndoFail, RedoFail, } diff --git a/rust-lib/flowy-ot/tests/helper/mod.rs b/rust-lib/flowy-ot/tests/helper/mod.rs index 43eb29f857..cba10dc041 100644 --- a/rust-lib/flowy-ot/tests/helper/mod.rs +++ b/rust-lib/flowy-ot/tests/helper/mod.rs @@ -64,11 +64,7 @@ impl OpTester { env_logger::init(); }); - let mut documents = Vec::with_capacity(2); - for _ in 0..2 { - documents.push(Document::new()); - } - Self { documents } + Self { documents: vec![] } } pub fn run_op(&mut self, op: &TestOp) { @@ -173,6 +169,22 @@ impl OpTester { } pub fn run_script(&mut self, script: Vec) { + let delta = Delta::new(); + self.run(script, delta); + } + + pub fn run_script_with_newline(&mut self, script: Vec) { + let mut delta = Delta::new(); + delta.insert("\n", Attributes::default()); + self.run(script, delta); + } + + fn run(&mut self, script: Vec, 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() { self.run_op(op); } diff --git a/rust-lib/flowy-ot/tests/undo_redo_test.rs b/rust-lib/flowy-ot/tests/undo_redo_test.rs index 8cdef33b84..3ca2bd2d1a 100644 --- a/rust-lib/flowy-ot/tests/undo_redo_test.rs +++ b/rust-lib/flowy-ot/tests/undo_redo_test.rs @@ -6,18 +6,16 @@ use flowy_ot::{client::RECORD_THRESHOLD, core::Interval}; #[test] fn delta_undo_insert() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Undo(0), AssertOpsJson(0, r#"[{"insert":"\n"}]"#), ]; - OpTester::new().run_script(ops); + OpTester::new().run_script_with_newline(ops); } #[test] fn delta_undo_insert2() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Wait(RECORD_THRESHOLD), Insert(0, "456", 0), @@ -26,13 +24,12 @@ fn delta_undo_insert2() { Undo(0), AssertOpsJson(0, r#"[{"insert":"\n"}]"#), ]; - OpTester::new().run_script(ops); + OpTester::new().run_script_with_newline(ops); } #[test] fn delta_redo_insert() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), Undo(0), @@ -40,13 +37,12 @@ fn delta_redo_insert() { Redo(0), AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), ]; - OpTester::new().run_script(ops); + OpTester::new().run_script_with_newline(ops); } #[test] fn delta_redo_insert_with_lagging() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Wait(RECORD_THRESHOLD), Insert(0, "456", 3), @@ -60,38 +56,35 @@ fn delta_redo_insert_with_lagging() { Undo(0), AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), ]; - OpTester::new().run_script(ops); + OpTester::new().run_script_with_newline(ops); } #[test] fn delta_undo_attributes() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Bold(0, Interval::new(0, 3), true), Undo(0), AssertOpsJson(0, r#"[{"insert":"\n"}]"#), ]; - OpTester::new().run_script(ops); + OpTester::new().run_script_with_newline(ops); } #[test] fn delta_undo_attributes_with_lagging() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Wait(RECORD_THRESHOLD), Bold(0, Interval::new(0, 3), true), Undo(0), AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), ]; - OpTester::new().run_script(ops); + OpTester::new().run_script_with_newline(ops); } #[test] fn delta_redo_attributes() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Bold(0, Interval::new(0, 3), true), Undo(0), @@ -102,13 +95,12 @@ fn delta_redo_attributes() { r#" [{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#, ), ]; - OpTester::new().run_script(ops); + OpTester::new().run_script_with_newline(ops); } #[test] fn delta_redo_attributes_with_lagging() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Wait(RECORD_THRESHOLD), 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"}]"#, ), ]; - OpTester::new().run_script(ops); + OpTester::new().run_script_with_newline(ops); } #[test] @@ -139,7 +131,6 @@ fn delta_undo_delete() { #[test] fn delta_undo_delete2() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Bold(0, Interval::new(0, 3), true), Delete(0, Interval::new(0, 1)), @@ -153,13 +144,12 @@ fn delta_undo_delete2() { Undo(0), AssertOpsJson(0, r#"[{"insert":"\n"}]"#), ]; - OpTester::new().run_script(ops); + OpTester::new().run_script_with_newline(ops); } #[test] fn delta_undo_delete2_with_lagging() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Wait(RECORD_THRESHOLD), 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] fn delta_redo_delete() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Delete(0, Interval::new(0, 3)), AssertOpsJson(0, r#"[{"insert":"\n"}]"#), @@ -195,13 +184,12 @@ fn delta_redo_delete() { Redo(0), AssertOpsJson(0, r#"[{"insert":"\n"}]"#), ]; - OpTester::new().run_script(ops); + OpTester::new().run_script_with_newline(ops); } #[test] fn delta_undo_replace() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Bold(0, Interval::new(0, 3), true), Replace(0, Interval::new(0, 2), "ab"), @@ -215,13 +203,12 @@ fn delta_undo_replace() { Undo(0), AssertOpsJson(0, r#"[{"insert":"\n"}]"#), ]; - OpTester::new().run_script(ops); + OpTester::new().run_script_with_newline(ops); } #[test] fn delta_undo_replace_with_lagging() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Wait(RECORD_THRESHOLD), 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"}]"#, ), ]; - OpTester::new().run_script(ops); + OpTester::new().run_script_with_newline(ops); } #[test] fn delta_redo_replace() { let ops = vec![ - Insert(0, "\n", 0), Insert(0, "123", 0), Bold(0, Interval::new(0, 3), true), 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); }