diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs index 20bb14c063..cb7bb0a728 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs @@ -40,7 +40,7 @@ fn attributes_insert_text_at_middle() { #[test] fn delta_get_ops_in_interval_1() { - let operations = OperationBuilder::new().insert("123", None).insert("4", None).build(); + let operations = OperationsBuilder::new().insert("123").insert("4").build(); let delta = RichTextDeltaBuilder::from_operations(operations); let mut iterator = DeltaIterator::from_interval(&delta, Interval::new(0, 4)); @@ -50,10 +50,10 @@ fn delta_get_ops_in_interval_1() { #[test] fn delta_get_ops_in_interval_2() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("123").build(); - let insert_b = OperationBuilder::insert("4").build(); - let insert_c = OperationBuilder::insert("5").build(); - let retain_a = OperationBuilder::retain(3).build(); + let insert_a = Operation::insert("123"); + let insert_b = Operation::insert("4"); + let insert_c = Operation::insert("5"); + let retain_a = Operation::retain(3); delta.add(insert_a.clone()); delta.add(retain_a.clone()); @@ -62,12 +62,12 @@ fn delta_get_ops_in_interval_2() { assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(0, 2)).ops(), - vec![OperationBuilder::insert("12").build()] + vec![Operation::insert("12")] ); assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(1, 3)).ops(), - vec![OperationBuilder::insert("23").build()] + vec![Operation::insert("23")] ); assert_eq!( @@ -77,7 +77,7 @@ fn delta_get_ops_in_interval_2() { assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(0, 4)).ops(), - vec![insert_a.clone(), OperationBuilder::retain(1).build()] + vec![insert_a.clone(), Operation::retain(1)] ); assert_eq!( @@ -94,20 +94,20 @@ fn delta_get_ops_in_interval_2() { #[test] fn delta_get_ops_in_interval_3() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("123456").build(); + let insert_a = Operation::insert("123456"); delta.add(insert_a.clone()); assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(3, 5)).ops(), - vec![OperationBuilder::insert("45").build()] + vec![Operation::insert("45")] ); } #[test] fn delta_get_ops_in_interval_4() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("12").build(); - let insert_b = OperationBuilder::insert("34").build(); - let insert_c = OperationBuilder::insert("56").build(); + let insert_a = Operation::insert("12"); + let insert_b = Operation::insert("34"); + let insert_c = Operation::insert("56"); delta.ops.push(insert_a.clone()); delta.ops.push(insert_b.clone()); @@ -128,73 +128,64 @@ fn delta_get_ops_in_interval_4() { assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(2, 5)).ops(), - vec![ - OperationBuilder::insert("34").build(), - OperationBuilder::insert("5").build() - ] + vec![Operation::insert("34"), Operation::insert("5")] ); } #[test] fn delta_get_ops_in_interval_5() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("123456").build(); - let insert_b = OperationBuilder::insert("789").build(); + let insert_a = Operation::insert("123456"); + let insert_b = Operation::insert("789"); delta.ops.push(insert_a.clone()); delta.ops.push(insert_b.clone()); assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(4, 8)).ops(), - vec![ - OperationBuilder::insert("56").build(), - OperationBuilder::insert("78").build() - ] + vec![Operation::insert("56"), Operation::insert("78")] ); // assert_eq!( // DeltaIter::from_interval(&delta, Interval::new(8, 9)).ops(), - // vec![Builder::insert("9").build()] + // vec![Builder::insert("9")] // ); } #[test] fn delta_get_ops_in_interval_6() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("12345678").build(); + let insert_a = Operation::insert("12345678"); delta.add(insert_a.clone()); assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(4, 6)).ops(), - vec![OperationBuilder::insert("56").build()] + vec![Operation::insert("56")] ); } #[test] fn delta_get_ops_in_interval_7() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("12345").build(); - let retain_a = OperationBuilder::retain(3).build(); + let insert_a = Operation::insert("12345"); + let retain_a = Operation::retain(3); delta.add(insert_a.clone()); delta.add(retain_a.clone()); let mut iter_1 = DeltaIterator::from_offset(&delta, 2); - assert_eq!(iter_1.next_op().unwrap(), OperationBuilder::insert("345").build()); - assert_eq!(iter_1.next_op().unwrap(), OperationBuilder::retain(3).build()); + assert_eq!(iter_1.next_op().unwrap(), Operation::insert("345")); + assert_eq!(iter_1.next_op().unwrap(), Operation::retain(3)); let mut iter_2 = DeltaIterator::new(&delta); - assert_eq!( - iter_2.next_op_with_len(2).unwrap(), - OperationBuilder::insert("12").build() - ); - assert_eq!(iter_2.next_op().unwrap(), OperationBuilder::insert("345").build()); + assert_eq!(iter_2.next_op_with_len(2).unwrap(), Operation::insert("12")); + assert_eq!(iter_2.next_op().unwrap(), Operation::insert("345")); - assert_eq!(iter_2.next_op().unwrap(), OperationBuilder::retain(3).build()); + assert_eq!(iter_2.next_op().unwrap(), Operation::retain(3)); } #[test] fn delta_op_seek() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("12345").build(); - let retain_a = OperationBuilder::retain(3).build(); + let insert_a = Operation::insert("12345"); + let retain_a = Operation::retain(3); delta.add(insert_a.clone()); delta.add(retain_a.clone()); let mut iter = DeltaIterator::new(&delta); @@ -205,14 +196,11 @@ fn delta_op_seek() { #[test] fn delta_utf16_code_unit_seek() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("12345").build()); + delta.add(Operation::insert("12345")); let mut iter = DeltaIterator::new(&delta); iter.seek::(3); - assert_eq!( - iter.next_op_with_len(2).unwrap(), - OperationBuilder::insert("45").build() - ); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("45")); } #[test] @@ -223,91 +211,76 @@ fn delta_utf16_code_unit_seek_with_attributes() { .add_attr(RichTextAttribute::Italic(true)) .build(); - delta.add(OperationBuilder::insert("1234").attributes(attributes.clone()).build()); - delta.add(OperationBuilder::insert("\n").build()); + delta.add(Operation::insert_with_attributes("1234", attributes.clone())); + delta.add(Operation::insert("\n")); let mut iter = DeltaIterator::new(&delta); iter.seek::(0); assert_eq!( iter.next_op_with_len(4).unwrap(), - OperationBuilder::insert("1234").attributes(attributes).build(), + Operation::insert_with_attributes("1234", attributes), ); } #[test] fn delta_next_op_len() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("12345").build()); + delta.add(Operation::insert("12345")); let mut iter = DeltaIterator::new(&delta); - assert_eq!( - iter.next_op_with_len(2).unwrap(), - OperationBuilder::insert("12").build() - ); - assert_eq!( - iter.next_op_with_len(2).unwrap(), - OperationBuilder::insert("34").build() - ); - assert_eq!(iter.next_op_with_len(2).unwrap(), OperationBuilder::insert("5").build()); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("12")); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("34")); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("5")); assert_eq!(iter.next_op_with_len(1), None); } #[test] fn delta_next_op_len_with_chinese() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("你好").build()); + delta.add(Operation::insert("你好")); let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 2); - assert_eq!( - iter.next_op_with_len(2).unwrap(), - OperationBuilder::insert("你好").build() - ); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("你好")); } #[test] fn delta_next_op_len_with_english() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("ab").build()); + delta.add(Operation::insert("ab")); let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 2); - assert_eq!( - iter.next_op_with_len(2).unwrap(), - OperationBuilder::insert("ab").build() - ); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("ab")); } #[test] fn delta_next_op_len_after_seek() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("12345").build()); + delta.add(Operation::insert("12345")); let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 5); iter.seek::(3); assert_eq!(iter.next_op_len().unwrap(), 2); - assert_eq!(iter.next_op_with_len(1).unwrap(), OperationBuilder::insert("4").build()); + assert_eq!(iter.next_op_with_len(1).unwrap(), Operation::insert("4")); assert_eq!(iter.next_op_len().unwrap(), 1); - assert_eq!(iter.next_op().unwrap(), OperationBuilder::insert("5").build()); + assert_eq!(iter.next_op().unwrap(), Operation::insert("5")); } #[test] fn delta_next_op_len_none() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("12345").build()); + delta.add(Operation::insert("12345")); let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 5); - assert_eq!( - iter.next_op_with_len(5).unwrap(), - OperationBuilder::insert("12345").build() - ); + assert_eq!(iter.next_op_with_len(5).unwrap(), Operation::insert("12345")); assert_eq!(iter.next_op_len(), None); } #[test] fn delta_next_op_with_len_zero() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("12345").build()); + delta.add(Operation::insert("12345")); let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_with_len(0), None,); assert_eq!(iter.next_op_len().unwrap(), 5); @@ -316,14 +289,14 @@ fn delta_next_op_with_len_zero() { #[test] fn delta_next_op_with_len_cross_op_return_last() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("12345").build()); - delta.add(OperationBuilder::retain(1).build()); - delta.add(OperationBuilder::insert("678").build()); + delta.add(Operation::insert("12345")); + delta.add(Operation::retain(1)); + delta.add(Operation::insert("678")); let mut iter = DeltaIterator::new(&delta); iter.seek::(4); assert_eq!(iter.next_op_len().unwrap(), 1); - assert_eq!(iter.next_op_with_len(2).unwrap(), OperationBuilder::retain(1).build()); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::retain(1)); } #[test] @@ -450,22 +423,22 @@ fn ops_merging() { assert_eq!(delta.ops.len(), 0); delta.retain(2, RichTextAttributes::default()); assert_eq!(delta.ops.len(), 1); - assert_eq!(delta.ops.last(), Some(&OperationBuilder::retain(2).build())); + assert_eq!(delta.ops.last(), Some(&Operation::retain(2))); delta.retain(3, RichTextAttributes::default()); assert_eq!(delta.ops.len(), 1); - assert_eq!(delta.ops.last(), Some(&OperationBuilder::retain(5).build())); + assert_eq!(delta.ops.last(), Some(&Operation::retain(5))); delta.insert("abc", RichTextAttributes::default()); assert_eq!(delta.ops.len(), 2); - assert_eq!(delta.ops.last(), Some(&OperationBuilder::insert("abc").build())); + assert_eq!(delta.ops.last(), Some(&Operation::insert("abc"))); delta.insert("xyz", RichTextAttributes::default()); assert_eq!(delta.ops.len(), 2); - assert_eq!(delta.ops.last(), Some(&OperationBuilder::insert("abcxyz").build())); + assert_eq!(delta.ops.last(), Some(&Operation::insert("abcxyz"))); delta.delete(1); assert_eq!(delta.ops.len(), 3); - assert_eq!(delta.ops.last(), Some(&OperationBuilder::delete(1).build())); + assert_eq!(delta.ops.last(), Some(&Operation::delete(1))); delta.delete(1); assert_eq!(delta.ops.len(), 3); - assert_eq!(delta.ops.last(), Some(&OperationBuilder::delete(2).build())); + assert_eq!(delta.ops.last(), Some(&Operation::delete(2))); } #[test] @@ -618,11 +591,11 @@ fn transform_two_conflict_non_seq_delta() { #[test] fn delta_invert_no_attribute_delta() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("123").build()); + delta.add(Operation::insert("123")); let mut change = RichTextDelta::default(); - change.add(OperationBuilder::retain(3).build()); - change.add(OperationBuilder::insert("456").build()); + change.add(Operation::retain(3)); + change.add(Operation::insert("456")); let undo = change.invert(&delta); let new_delta = delta.compose(&change).unwrap(); diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs index 6c578be6c3..469431c478 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs @@ -11,7 +11,7 @@ fn operation_insert_serialize_test() { .add_attr(RichTextAttribute::Bold(true)) .add_attr(RichTextAttribute::Italic(true)) .build(); - let operation = OperationBuilder::insert("123").attributes(attributes).build(); + let operation = Operation::insert_with_attributes("123", attributes); let json = serde_json::to_string(&operation).unwrap(); eprintln!("{}", json); @@ -42,7 +42,7 @@ fn attributes_serialize_test() { .add_attr(RichTextAttribute::Bold(true)) .add_attr(RichTextAttribute::Italic(true)) .build(); - let retain = OperationBuilder::insert("123").attributes(attributes).build(); + let retain = Operation::insert_with_attributes("123", attributes); let json = serde_json::to_string(&retain).unwrap(); eprintln!("{}", json); @@ -56,7 +56,7 @@ fn delta_serialize_multi_attribute_test() { .add_attr(RichTextAttribute::Bold(true)) .add_attr(RichTextAttribute::Italic(true)) .build(); - let retain = OperationBuilder::insert("123").attributes(attributes).build(); + let retain = Operation::insert_with_attributes("123", attributes); delta.add(retain); delta.add(Operation::Retain(5.into())); diff --git a/shared-lib/lib-ot/src/core/delta/cursor.rs b/shared-lib/lib-ot/src/core/delta/cursor.rs index 2243adb7b3..4c223dfd50 100644 --- a/shared-lib/lib-ot/src/core/delta/cursor.rs +++ b/shared-lib/lib-ot/src/core/delta/cursor.rs @@ -29,11 +29,11 @@ where /// # Examples /// /// ``` - /// use lib_ot::core::{DeltaIterator, Interval, OperationBuilder}; + /// use lib_ot::core::{DeltaIterator, Interval, Operation}; /// use lib_ot::rich_text::RichTextDelta; /// let mut delta = RichTextDelta::default(); - /// let op_1 = OperationBuilder::insert("123").build(); - /// let op_2 = OperationBuilder::insert("4").build(); + /// let op_1 = Operation::insert("123"); + /// let op_2 = Operation::insert("4"); /// delta.add(op_1.clone()); /// delta.add(op_2.clone()); /// assert_eq!(DeltaIterator::from_interval(&delta, Interval::new(0, 3)).ops(), vec![op_1.clone()]); diff --git a/shared-lib/lib-ot/src/core/delta/delta.rs b/shared-lib/lib-ot/src/core/delta/delta.rs index 495d26a8e8..53cdcaac54 100644 --- a/shared-lib/lib-ot/src/core/delta/delta.rs +++ b/shared-lib/lib-ot/src/core/delta/delta.rs @@ -3,7 +3,7 @@ use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use crate::core::delta::{DeltaIterator, MAX_IV_LEN}; use crate::core::flowy_str::FlowyStr; use crate::core::interval::Interval; -use crate::core::operation::{Attributes, Operation, OperationBuilder, OperationTransform, PhantomAttributes}; +use crate::core::operation::{Attributes, Operation, OperationTransform, PhantomAttributes}; use bytes::Bytes; use serde::de::DeserializeOwned; use std::{ @@ -112,7 +112,7 @@ where if let Some(Operation::Delete(n_last)) = self.ops.last_mut() { *n_last += n; } else { - self.ops.push(OperationBuilder::delete(n).build()); + self.ops.push(Operation::delete(n)); } } @@ -135,10 +135,10 @@ where } [.., op_last @ Operation::::Delete(_)] => { let new_last = op_last.clone(); - *op_last = OperationBuilder::::insert(&s).attributes(attributes).build(); + *op_last = Operation::::insert_with_attributes(&s, attributes); Some(new_last) } - _ => Some(OperationBuilder::::insert(&s).attributes(attributes).build()), + _ => Some(Operation::::insert_with_attributes(&s, attributes)), }; match new_last { @@ -160,8 +160,7 @@ where self.ops.push(new_op); } } else { - self.ops - .push(OperationBuilder::::retain(n).attributes(attributes).build()); + self.ops.push(Operation::::retain_with_attributes(n, attributes)); } } @@ -319,10 +318,10 @@ where let op = iter .next_op_with_len(length) - .unwrap_or_else(|| OperationBuilder::retain(length).build()); + .unwrap_or_else(|| Operation::retain(length)); let other_op = other_iter .next_op_with_len(length) - .unwrap_or_else(|| OperationBuilder::retain(length).build()); + .unwrap_or_else(|| Operation::retain(length)); // debug_assert_eq!(op.len(), other_op.len(), "Composing delta failed,"); @@ -330,16 +329,12 @@ where (Operation::Retain(retain), Operation::Retain(other_retain)) => { let composed_attrs = retain.attributes.compose(&other_retain.attributes)?; - new_delta.add(OperationBuilder::retain(retain.n).attributes(composed_attrs).build()) + new_delta.add(Operation::retain_with_attributes(retain.n, composed_attrs)) } (Operation::Insert(insert), Operation::Retain(other_retain)) => { let mut composed_attrs = insert.attributes.compose(&other_retain.attributes)?; composed_attrs.remove_empty(); - new_delta.add( - OperationBuilder::insert(op.get_data()) - .attributes(composed_attrs) - .build(), - ) + new_delta.add(Operation::insert_with_attributes(op.get_data(), composed_attrs)) } (Operation::Retain(_), Operation::Delete(_)) => { new_delta.add(other_op); @@ -402,7 +397,7 @@ where Ordering::Less => { a_prime.retain(retain.n, composed_attrs.clone()); b_prime.retain(retain.n, composed_attrs.clone()); - next_op2 = Some(OperationBuilder::retain(o_retain.n - retain.n).build()); + next_op2 = Some(Operation::retain(o_retain.n - retain.n)); next_op1 = ops1.next(); } Ordering::Equal => { @@ -414,14 +409,14 @@ where Ordering::Greater => { a_prime.retain(o_retain.n, composed_attrs.clone()); b_prime.retain(o_retain.n, composed_attrs.clone()); - next_op1 = Some(OperationBuilder::retain(retain.n - o_retain.n).build()); + next_op1 = Some(Operation::retain(retain.n - o_retain.n)); next_op2 = ops2.next(); } }; } (Some(Operation::Delete(i)), Some(Operation::Delete(j))) => match i.cmp(j) { Ordering::Less => { - next_op2 = Some(OperationBuilder::delete(*j - *i).build()); + next_op2 = Some(Operation::delete(*j - *i)); next_op1 = ops1.next(); } Ordering::Equal => { @@ -429,7 +424,7 @@ where next_op2 = ops2.next(); } Ordering::Greater => { - next_op1 = Some(OperationBuilder::delete(*i - *j).build()); + next_op1 = Some(Operation::delete(*i - *j)); next_op2 = ops2.next(); } }, @@ -437,7 +432,7 @@ where match i.cmp(o_retain) { Ordering::Less => { a_prime.delete(*i); - next_op2 = Some(OperationBuilder::retain(o_retain.n - *i).build()); + next_op2 = Some(Operation::retain(o_retain.n - *i)); next_op1 = ops1.next(); } Ordering::Equal => { @@ -447,7 +442,7 @@ where } Ordering::Greater => { a_prime.delete(o_retain.n); - next_op1 = Some(OperationBuilder::delete(*i - o_retain.n).build()); + next_op1 = Some(Operation::delete(*i - o_retain.n)); next_op2 = ops2.next(); } }; @@ -456,7 +451,7 @@ where match retain.cmp(j) { Ordering::Less => { b_prime.delete(retain.n); - next_op2 = Some(OperationBuilder::delete(*j - retain.n).build()); + next_op2 = Some(Operation::delete(*j - retain.n)); next_op1 = ops1.next(); } Ordering::Equal => { @@ -466,7 +461,7 @@ where } Ordering::Greater => { b_prime.delete(*j); - next_op1 = Some(OperationBuilder::retain(retain.n - *j).build()); + next_op1 = Some(Operation::retain(retain.n - *j)); next_op2 = ops2.next(); } }; diff --git a/shared-lib/lib-ot/src/core/flowy_str.rs b/shared-lib/lib-ot/src/core/flowy_str.rs index 2f5ee9b853..162557f5f3 100644 --- a/shared-lib/lib-ot/src/core/flowy_str.rs +++ b/shared-lib/lib-ot/src/core/flowy_str.rs @@ -30,6 +30,22 @@ impl FlowyStr { Utf16CodeUnitIterator::new(self) } + /// Return a new string with the given [Interval] + /// # Examples + /// + /// ``` + /// use lib_ot::core::{FlowyStr, Interval}; + /// let s: FlowyStr = "你好\n😁".into(); + /// assert_eq!(s.utf16_len(), 5); + /// let output1 = s.sub_str(Interval::new(0, 2)).unwrap(); + /// assert_eq!(output1, "你好"); + /// + /// let output2 = s.sub_str(Interval::new(2, 3)).unwrap(); + /// assert_eq!(output2, "\n"); + /// + /// let output3 = s.sub_str(Interval::new(3, 5)).unwrap(); + /// assert_eq!(output3, "😁"); + /// ``` pub fn sub_str(&self, interval: Interval) -> Option { let mut iter = Utf16CodeUnitIterator::new(self); let mut buf = vec![]; @@ -49,8 +65,28 @@ impl FlowyStr { } } + /// Return a new string with the given [Interval] + /// # Examples + /// + /// ``` + /// use lib_ot::core::FlowyStr; + /// let s: FlowyStr = "👋😁👋".into(); /// + /// let mut iter = s.utf16_code_point_iter(); + /// assert_eq!(iter.next().unwrap(), "👋".to_string()); + /// assert_eq!(iter.next().unwrap(), "😁".to_string()); + /// assert_eq!(iter.next().unwrap(), "👋".to_string()); + /// assert_eq!(iter.next(), None); + /// + /// let s: FlowyStr = "👋12ab一二👋".into(); /// + /// let mut iter = s.utf16_code_point_iter(); + /// assert_eq!(iter.next().unwrap(), "👋".to_string()); + /// assert_eq!(iter.next().unwrap(), "1".to_string()); + /// assert_eq!(iter.next().unwrap(), "2".to_string()); + /// + /// assert_eq!(iter.skip(FlowyStr::from("ab一二").utf16_len()).next().unwrap(), "👋".to_string()); + /// ``` #[allow(dead_code)] - fn utf16_code_point_iter(&self) -> FlowyUtf16CodePointIterator { + pub fn utf16_code_point_iter(&self) -> FlowyUtf16CodePointIterator { FlowyUtf16CodePointIterator::new(self, 0) } } @@ -264,20 +300,6 @@ mod tests { assert_eq!(output, "👋"); } - #[test] - fn flowy_str_sub_str_in_chinese() { - let s: FlowyStr = "你好\n😁".into(); - let size = s.utf16_len(); - assert_eq!(size, 5); - - let output1 = s.sub_str(Interval::new(0, 2)).unwrap(); - let output2 = s.sub_str(Interval::new(2, 3)).unwrap(); - let output3 = s.sub_str(Interval::new(3, 5)).unwrap(); - assert_eq!(output1, "你好"); - assert_eq!(output2, "\n"); - assert_eq!(output3, "😁"); - } - #[test] fn flowy_str_sub_str_in_chinese2() { let s: FlowyStr = "😁 \n".into(); @@ -300,16 +322,6 @@ mod tests { assert_eq!(output, "ab"); } - #[test] - fn flowy_str_utf16_code_point_iter_test1() { - let s: FlowyStr = "👋😁👋".into(); - let mut iter = s.utf16_code_point_iter(); - assert_eq!(iter.next().unwrap(), "👋".to_string()); - assert_eq!(iter.next().unwrap(), "😁".to_string()); - assert_eq!(iter.next().unwrap(), "👋".to_string()); - assert_eq!(iter.next(), None); - } - #[test] fn flowy_str_utf16_code_point_iter_test2() { let s: FlowyStr = "👋😁👋".into(); diff --git a/shared-lib/lib-ot/src/core/operation/builder.rs b/shared-lib/lib-ot/src/core/operation/builder.rs index d1803a8e21..9483d4cae7 100644 --- a/shared-lib/lib-ot/src/core/operation/builder.rs +++ b/shared-lib/lib-ot/src/core/operation/builder.rs @@ -1,51 +1,47 @@ use crate::core::operation::{Attributes, Operation, PhantomAttributes}; use crate::rich_text::RichTextAttributes; -pub type RichTextOpBuilder = OperationBuilder; -pub type PlainTextOpBuilder = OperationBuilder; +pub type RichTextOpBuilder = OperationsBuilder; +pub type PlainTextOpBuilder = OperationsBuilder; -pub struct OperationBuilder { +pub struct OperationsBuilder { operations: Vec>, } -impl OperationBuilder +impl OperationsBuilder where T: Attributes, { - pub fn new() -> OperationBuilder { - OperationBuilder { operations: vec![] } + pub fn new() -> OperationsBuilder { + OperationsBuilder { operations: vec![] } } - pub fn retain(mut self, n: usize) -> OperationBuilder { - let mut retain = Operation::Retain(n.into()); - - if let Some(attributes) = attributes { - if let Operation::Retain(r) = &mut retain { - r.attributes = attributes; - } - } + pub fn retain_with_attributes(mut self, n: usize, attributes: T) -> OperationsBuilder { + let retain = Operation::retain_with_attributes(n.into(), attributes); self.operations.push(retain); self } - pub fn delete(mut self, n: usize) -> OperationBuilder { + pub fn retain(mut self, n: usize) -> OperationsBuilder { + let retain = Operation::retain(n.into()); + self.operations.push(retain); + self + } + + pub fn delete(mut self, n: usize) -> OperationsBuilder { self.operations.push(Operation::Delete(n)); self } - pub fn insert(mut self, s: &str, attributes: Option) -> OperationBuilder { - let mut insert = Operation::Insert(s.into()); - if let Some(attributes) = attributes { - if let Operation::Retain(i) = &mut insert { - i.attributes = attributes; - } - } + pub fn insert_with_attributes(mut self, s: &str, attributes: T) -> OperationsBuilder { + let insert = Operation::insert_with_attributes(s.into(), attributes); self.operations.push(insert); self } - pub fn attributes(mut self, attrs: T) -> OperationBuilder { - self.attrs = attrs; + pub fn insert(mut self, s: &str) -> OperationsBuilder { + let insert = Operation::insert(s.into()); + self.operations.push(insert); self } diff --git a/shared-lib/lib-ot/src/core/operation/operation.rs b/shared-lib/lib-ot/src/core/operation/operation.rs index 9464f91784..7198c38615 100644 --- a/shared-lib/lib-ot/src/core/operation/operation.rs +++ b/shared-lib/lib-ot/src/core/operation/operation.rs @@ -1,6 +1,5 @@ use crate::core::flowy_str::FlowyStr; use crate::core::interval::Interval; -use crate::core::operation::OperationBuilder; use crate::errors::OTError; use serde::{Deserialize, Serialize, __private::Formatter}; use std::fmt::Display; @@ -105,6 +104,40 @@ impl Operation where T: Attributes, { + pub fn delete(n: usize) -> Self { + Self::Delete(n) + } + + /// Create a [Retain] operation with the given attributes + pub fn retain_with_attributes(n: usize, attributes: T) -> Self { + Self::Retain(Retain { n, attributes }) + } + + /// Create a [Retain] operation without attributes + pub fn retain(n: usize) -> Self { + Self::Retain(Retain { + n, + attributes: T::default(), + }) + } + + /// Create a [Insert] operation with the given attributes + pub fn insert_with_attributes(s: &str, attributes: T) -> Self { + Self::Insert(Insert { + s: FlowyStr::from(s), + attributes, + }) + } + + /// Create a [Insert] operation without attributes + pub fn insert(s: &str) -> Self { + Self::Insert(Insert { + s: FlowyStr::from(s), + attributes: T::default(), + }) + } + + /// Return the String if the operation is [Insert] operation, otherwise return the empty string. pub fn get_data(&self) -> &str { match self { Operation::Delete(_) => "", @@ -152,45 +185,58 @@ where let right; match self { Operation::Delete(n) => { - left = Some(OperationBuilder::::delete(index).build()); - right = Some(OperationBuilder::::delete(*n - index).build()); + left = Some(Operation::::delete(index)); + right = Some(Operation::::delete(*n - index)); } Operation::Retain(retain) => { - left = Some(OperationBuilder::::delete(index).build()); - right = Some(OperationBuilder::::delete(retain.n - index).build()); + left = Some(Operation::::delete(index)); + right = Some(Operation::::delete(retain.n - index)); } Operation::Insert(insert) => { let attributes = self.get_attributes(); - left = Some( - OperationBuilder::::insert(&insert.s[0..index]) - .attributes(attributes.clone()) - .build(), - ); - right = Some( - OperationBuilder::::insert(&insert.s[index..insert.utf16_size()]) - .attributes(attributes) - .build(), - ); + left = Some(Operation::::insert_with_attributes( + &insert.s[0..index], + attributes.clone(), + )); + right = Some(Operation::::insert_with_attributes( + &insert.s[index..insert.utf16_size()], + attributes, + )); } } (left, right) } + /// Returns an operation with the specified width. + /// # Arguments + /// + /// * `interval`: Specify the shrink width of the operation. + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::{Interval, Operation, PhantomAttributes}; + /// let operation = Operation::::insert("1234"); + /// + /// let op1 = operation.shrink(Interval::new(0,3)).unwrap(); + /// assert_eq!(op1 , Operation::insert("123")); + /// + /// let op2= operation.shrink(Interval::new(3,4)).unwrap(); + /// assert_eq!(op2, Operation::insert("4")); + /// ``` pub fn shrink(&self, interval: Interval) -> Option> { let op = match self { - Operation::Delete(n) => OperationBuilder::delete(min(*n, interval.size())).build(), - Operation::Retain(retain) => OperationBuilder::retain(min(retain.n, interval.size())) - .attributes(retain.attributes.clone()) - .build(), + Operation::Delete(n) => Operation::delete(min(*n, interval.size())), + Operation::Retain(retain) => { + Operation::retain_with_attributes(min(retain.n, interval.size()), retain.attributes.clone()) + } Operation::Insert(insert) => { if interval.start > insert.utf16_size() { - OperationBuilder::insert("").build() + Operation::insert("") } else { let s = insert.s.sub_str(interval).unwrap_or_else(|| "".to_owned()); - OperationBuilder::insert(&s) - .attributes(insert.attributes.clone()) - .build() + Operation::insert_with_attributes(&s, insert.attributes.clone()) } } }; @@ -287,7 +333,7 @@ where self.n += n; None } else { - Some(OperationBuilder::retain(n).attributes(attributes).build()) + Some(Operation::retain_with_attributes(n, attributes)) } } @@ -368,7 +414,7 @@ where self.s += s; None } else { - Some(OperationBuilder::::insert(s).attributes(attributes).build()) + Some(Operation::::insert_with_attributes(s, attributes)) } }