diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index 356ff15897..8850024f25 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -215,7 +215,7 @@ impl DefaultFolderBuilder { for app in workspace_rev.apps.iter() { for (index, view) in app.belongings.iter().enumerate() { let view_data = if index == 0 { - initial_read_me().to_delta_str() + initial_read_me().to_json_str() } else { initial_quill_delta_string() }; diff --git a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs index b69b303fa1..6fb0ebf565 100644 --- a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs +++ b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs @@ -10,7 +10,7 @@ use flowy_sync::{ entities::{revision::Revision, ws_data::ServerRevisionWSData}, }; use lib_infra::future::FutureResult; -use lib_ot::core::PlainTextAttributes; +use lib_ot::core::PhantomAttributes; use parking_lot::RwLock; use std::sync::Arc; @@ -80,7 +80,7 @@ impl FolderEditor { pub(crate) fn apply_change(&self, change: FolderChange) -> FlowyResult<()> { let FolderChange { delta, md5 } = change; let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); - let delta_data = delta.to_delta_bytes(); + let delta_data = delta.to_json_bytes(); let revision = Revision::new( &self.rev_manager.object_id, base_rev_id, @@ -132,7 +132,7 @@ impl FolderEditor { pub struct FolderRevisionCompactor(); impl RevisionCompactor for FolderRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> { - let delta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?; - Ok(delta.to_delta_bytes()) + let delta = make_delta_from_revisions::<PhantomAttributes>(revisions)?; + Ok(delta.to_json_bytes()) } } diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs index 5676db54da..ee930bd6ff 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs @@ -110,7 +110,7 @@ impl FolderPersistence { pub async fn save_folder(&self, user_id: &str, folder_id: &FolderId, folder: FolderPad) -> FlowyResult<()> { let pool = self.database.db_pool()?; let json = folder.to_json()?; - let delta_data = PlainTextDeltaBuilder::new().insert(&json).build().to_delta_bytes(); + let delta_data = PlainTextDeltaBuilder::new().insert(&json).build().to_json_bytes(); let revision = Revision::initial_revision(user_id, folder_id.as_ref(), delta_data); let record = RevisionRecord { revision, diff --git a/frontend/rust-lib/flowy-folder/src/services/web_socket.rs b/frontend/rust-lib/flowy-folder/src/services/web_socket.rs index 75db905d63..eac429dc1f 100644 --- a/frontend/rust-lib/flowy-folder/src/services/web_socket.rs +++ b/frontend/rust-lib/flowy-folder/src/services/web_socket.rs @@ -10,7 +10,7 @@ use flowy_sync::{ }, }; use lib_infra::future::{BoxResultFuture, FutureResult}; -use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta}; +use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta}; use parking_lot::RwLock; use std::{sync::Arc, time::Duration}; @@ -24,7 +24,7 @@ pub(crate) async fn make_folder_ws_manager( ) -> Arc<RevisionWebSocketManager> { let ws_data_provider = Arc::new(WSDataProvider::new(folder_id, Arc::new(rev_manager.clone()))); let resolver = Arc::new(FolderConflictResolver { folder_pad }); - let conflict_controller = ConflictController::<PlainTextAttributes>::new( + let conflict_controller = ConflictController::<PhantomAttributes>::new( user_id, resolver, Arc::new(ws_data_provider.clone()), @@ -55,7 +55,7 @@ struct FolderConflictResolver { folder_pad: Arc<RwLock<FolderPad>>, } -impl ConflictResolver<PlainTextAttributes> for FolderConflictResolver { +impl ConflictResolver<PhantomAttributes> for FolderConflictResolver { fn compose_delta(&self, delta: PlainTextDelta) -> BoxResultFuture<DeltaMD5, FlowyError> { let folder_pad = self.folder_pad.clone(); Box::pin(async move { @@ -67,7 +67,7 @@ impl ConflictResolver<PlainTextAttributes> for FolderConflictResolver { fn transform_delta( &self, delta: PlainTextDelta, - ) -> BoxResultFuture<TransformDeltas<PlainTextAttributes>, FlowyError> { + ) -> BoxResultFuture<TransformDeltas<PhantomAttributes>, FlowyError> { let folder_pad = self.folder_pad.clone(); Box::pin(async move { let read_guard = folder_pad.read(); diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs index 320f18b560..eadd1e47fd 100644 --- a/frontend/rust-lib/flowy-grid/src/manager.rs +++ b/frontend/rust-lib/flowy-grid/src/manager.rs @@ -192,7 +192,7 @@ pub async fn make_grid_view_data( // Create grid's block let grid_block_delta = make_grid_block_delta(block_meta_data); - let block_delta_data = grid_block_delta.to_delta_bytes(); + let block_delta_data = grid_block_delta.to_json_bytes(); let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, block_id, block_delta_data).into(); let _ = grid_manager.create_grid_block(&block_id, repeated_revision).await?; @@ -202,7 +202,7 @@ pub async fn make_grid_view_data( // Create grid let grid_meta_delta = make_grid_delta(&grid_rev); - let grid_delta_data = grid_meta_delta.to_delta_bytes(); + let grid_delta_data = grid_meta_delta.to_json_bytes(); let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, view_id, grid_delta_data.clone()).into(); let _ = grid_manager.create_grid(view_id, repeated_revision).await?; diff --git a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs index f74075ec6e..19f3a885cb 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs @@ -7,7 +7,7 @@ use flowy_sync::client_grid::{GridBlockMetaChange, GridBlockRevisionPad}; use flowy_sync::entities::revision::Revision; use flowy_sync::util::make_delta_from_revisions; use lib_infra::future::FutureResult; -use lib_ot::core::PlainTextAttributes; +use lib_ot::core::PhantomAttributes; use std::borrow::Cow; use std::sync::Arc; use tokio::sync::RwLock; @@ -161,7 +161,7 @@ impl GridBlockRevisionEditor { let GridBlockMetaChange { delta, md5 } = change; let user_id = self.user_id.clone(); let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); - let delta_data = delta.to_delta_bytes(); + let delta_data = delta.to_json_bytes(); let revision = Revision::new( &self.rev_manager.object_id, base_rev_id, @@ -200,7 +200,7 @@ impl RevisionObjectBuilder for GridBlockMetaPadBuilder { pub struct GridBlockRevisionCompactor(); impl RevisionCompactor for GridBlockRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> { - let delta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?; - Ok(delta.to_delta_bytes()) + let delta = make_delta_from_revisions::<PhantomAttributes>(revisions)?; + Ok(delta.to_json_bytes()) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs index 11d8b8f09e..ddd1ba049d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod tests { use crate::entities::FieldType; - use crate::services::cell::{CellDataOperation}; + use crate::services::cell::CellDataOperation; use crate::services::field::type_options::checkbox_type_option::*; use crate::services::field::FieldBuilder; use flowy_grid_data_model::revision::FieldRevision; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs index 87e4efa4a8..1229a8f5e1 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod tests { use crate::entities::FieldType; - use crate::services::cell::{CellDataOperation}; + use crate::services::cell::CellDataOperation; use crate::services::field::*; // use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat}; use flowy_grid_data_model::revision::FieldRevision; diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index 5c7436022e..e4d17e9883 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -21,7 +21,7 @@ use flowy_sync::entities::revision::Revision; use flowy_sync::errors::CollaborateResult; use flowy_sync::util::make_delta_from_revisions; use lib_infra::future::FutureResult; -use lib_ot::core::PlainTextAttributes; +use lib_ot::core::PhantomAttributes; use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; @@ -573,7 +573,7 @@ impl GridRevisionEditor { let GridChangeset { delta, md5 } = change; let user_id = self.user.user_id()?; let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); - let delta_data = delta.to_delta_bytes(); + let delta_data = delta.to_json_bytes(); let revision = Revision::new( &self.rev_manager.object_id, base_rev_id, @@ -664,8 +664,8 @@ impl RevisionCloudService for GridRevisionCloudService { pub struct GridRevisionCompactor(); impl RevisionCompactor for GridRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> { - let delta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?; - Ok(delta.to_delta_bytes()) + let delta = make_delta_from_revisions::<PhantomAttributes>(revisions)?; + Ok(delta.to_json_bytes()) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs index 026ba3bc20..9b24d03fda 100644 --- a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs +++ b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs @@ -48,7 +48,7 @@ impl GridMigration { let pool = self.database.db_pool()?; let grid_rev_pad = self.get_grid_revision_pad(grid_id).await?; let json = grid_rev_pad.json_str()?; - let delta_data = PlainTextDeltaBuilder::new().insert(&json).build().to_delta_bytes(); + let delta_data = PlainTextDeltaBuilder::new().insert(&json).build().to_json_bytes(); let revision = Revision::initial_revision(&user_id, grid_id, delta_data); let record = RevisionRecord::new(revision); // diff --git a/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs b/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs index 0a63f37f3e..5e89e7db32 100644 --- a/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs +++ b/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs @@ -9,7 +9,7 @@ use flowy_sync::{ util::make_delta_from_revisions, }; use lib_infra::future::BoxResultFuture; -use lib_ot::core::{Attributes, Delta, PlainTextAttributes}; +use lib_ot::core::{Attributes, Delta, PhantomAttributes}; use lib_ot::rich_text::RichTextAttributes; use serde::de::DeserializeOwned; use std::{convert::TryFrom, sync::Arc}; @@ -31,7 +31,7 @@ pub trait ConflictRevisionSink: Send + Sync + 'static { } pub type RichTextConflictController = ConflictController<RichTextAttributes>; -pub type PlainTextConflictController = ConflictController<PlainTextAttributes>; +pub type PlainTextConflictController = ConflictController<PhantomAttributes>; pub struct ConflictController<T> where @@ -154,7 +154,7 @@ where &rev_manager.object_id, base_rev_id, rev_id, - client_delta.to_delta_bytes(), + client_delta.to_json_bytes(), user_id, md5.clone(), ); @@ -166,7 +166,7 @@ where &rev_manager.object_id, base_rev_id, rev_id, - server_delta.to_delta_bytes(), + server_delta.to_json_bytes(), user_id, md5, ); diff --git a/frontend/rust-lib/flowy-text-block/src/editor.rs b/frontend/rust-lib/flowy-text-block/src/editor.rs index 6fed85c913..2a52f43778 100644 --- a/frontend/rust-lib/flowy-text-block/src/editor.rs +++ b/frontend/rust-lib/flowy-text-block/src/editor.rs @@ -238,7 +238,7 @@ impl RevisionObjectBuilder for TextBlockInfoBuilder { Result::<DocumentPB, FlowyError>::Ok(DocumentPB { block_id: object_id.to_owned(), - text: delta.to_delta_str(), + text: delta.to_json_str(), rev_id, base_rev_id, }) diff --git a/frontend/rust-lib/flowy-text-block/src/queue.rs b/frontend/rust-lib/flowy-text-block/src/queue.rs index 343ad11e7b..072c810d9d 100644 --- a/frontend/rust-lib/flowy-text-block/src/queue.rs +++ b/frontend/rust-lib/flowy-text-block/src/queue.rs @@ -175,7 +175,7 @@ impl EditBlockQueue { } async fn save_local_delta(&self, delta: RichTextDelta, md5: String) -> Result<RevId, FlowyError> { - let delta_data = delta.to_delta_bytes(); + let delta_data = delta.to_json_bytes(); let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); let user_id = self.user.user_id()?; let revision = Revision::new( @@ -195,7 +195,7 @@ pub(crate) struct TextBlockRevisionCompactor(); impl RevisionCompactor for TextBlockRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> { let delta = make_delta_from_revisions::<RichTextAttributes>(revisions)?; - Ok(delta.to_delta_bytes()) + Ok(delta.to_json_bytes()) } } diff --git a/frontend/rust-lib/flowy-text-block/tests/document/script.rs b/frontend/rust-lib/flowy-text-block/tests/document/script.rs index 1722724c3f..b3ce1cb9bd 100644 --- a/frontend/rust-lib/flowy-text-block/tests/document/script.rs +++ b/frontend/rust-lib/flowy-text-block/tests/document/script.rs @@ -75,7 +75,7 @@ impl TextBlockEditorTest { let delta = self.editor.text_block_delta().await.unwrap(); if expected_delta != delta { eprintln!("✅ expect: {}", expected,); - eprintln!("❌ receive: {}", delta.to_delta_str()); + eprintln!("❌ receive: {}", delta.to_json_str()); } assert_eq!(expected_delta, delta); } diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs index 037b36970b..6dcd372d47 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs @@ -762,19 +762,19 @@ fn attributes_preserve_list_format_on_merge() { #[test] fn delta_compose() { - let mut delta = RichTextDelta::from_delta_str(r#"[{"insert":"\n"}]"#).unwrap(); + let mut delta = RichTextDelta::from_json_str(r#"[{"insert":"\n"}]"#).unwrap(); let deltas = vec![ - RichTextDelta::from_delta_str(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(), - RichTextDelta::from_delta_str(r#"[{"insert":"a"}]"#).unwrap(), - RichTextDelta::from_delta_str(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(), - RichTextDelta::from_delta_str(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(), + RichTextDelta::from_json_str(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(), + RichTextDelta::from_json_str(r#"[{"insert":"a"}]"#).unwrap(), + RichTextDelta::from_json_str(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(), + RichTextDelta::from_json_str(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(), ]; for d in deltas { delta = delta.compose(&d).unwrap(); } assert_eq!( - delta.to_delta_str(), + delta.to_json_str(), r#"[{"insert":"a"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"\n"}]"# ); diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs index 676b9a1cb0..a6b58ab39b 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs @@ -108,20 +108,20 @@ impl TestBuilder { TestOp::Insert(delta_i, s, index) => { let document = &mut self.documents[*delta_i]; let delta = document.insert(*index, s).unwrap(); - tracing::debug!("Insert delta: {}", delta.to_delta_str()); + tracing::debug!("Insert delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Delete(delta_i, iv) => { let document = &mut self.documents[*delta_i]; let delta = document.replace(*iv, "").unwrap(); - tracing::trace!("Delete delta: {}", delta.to_delta_str()); + tracing::trace!("Delete delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Replace(delta_i, iv, s) => { let document = &mut self.documents[*delta_i]; let delta = document.replace(*iv, s).unwrap(); - tracing::trace!("Replace delta: {}", delta.to_delta_str()); + tracing::trace!("Replace delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::InsertBold(delta_i, s, iv) => { @@ -133,7 +133,7 @@ impl TestBuilder { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Bold(*enable); let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Bold delta: {}", delta.to_delta_str()); + tracing::trace!("Bold delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Italic(delta_i, iv, enable) => { @@ -143,28 +143,28 @@ impl TestBuilder { false => RichTextAttribute::Italic(false), }; let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Italic delta: {}", delta.to_delta_str()); + tracing::trace!("Italic delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Header(delta_i, iv, level) => { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Header(*level); let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Header delta: {}", delta.to_delta_str()); + tracing::trace!("Header delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Link(delta_i, iv, link) => { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Link(link.to_owned()); let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Link delta: {}", delta.to_delta_str()); + tracing::trace!("Link delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Bullet(delta_i, iv, enable) => { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Bullet(*enable); let delta = document.format(*iv, attribute).unwrap(); - tracing::debug!("Bullet delta: {}", delta.to_delta_str()); + tracing::debug!("Bullet delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } @@ -194,15 +194,15 @@ impl TestBuilder { let delta_a = &self.documents[*delta_a_i].delta(); let delta_b = &self.documents[*delta_b_i].delta(); tracing::debug!("Invert: "); - tracing::debug!("a: {}", delta_a.to_delta_str()); - tracing::debug!("b: {}", delta_b.to_delta_str()); + tracing::debug!("a: {}", delta_a.to_json_str()); + tracing::debug!("b: {}", delta_b.to_json_str()); let (_, b_prime) = delta_a.transform(delta_b).unwrap(); let undo = b_prime.invert(delta_a); let new_delta = delta_a.compose(&b_prime).unwrap(); - tracing::debug!("new delta: {}", new_delta.to_delta_str()); - tracing::debug!("undo delta: {}", undo.to_delta_str()); + tracing::debug!("new delta: {}", new_delta.to_json_str()); + tracing::debug!("undo delta: {}", undo.to_json_str()); let new_delta_after_undo = new_delta.compose(&undo).unwrap(); @@ -238,7 +238,7 @@ impl TestBuilder { } TestOp::AssertPrimeJson(doc_i, expected) => { - let prime_json = self.primes[*doc_i].as_ref().unwrap().to_delta_str(); + let prime_json = self.primes[*doc_i].as_ref().unwrap().to_json_str(); let expected_prime: RichTextDelta = serde_json::from_str(expected).unwrap(); let target_prime: RichTextDelta = serde_json::from_str(&prime_json).unwrap(); 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 3f174fa3bc..f32e70942f 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 @@ -2,6 +2,7 @@ use crate::editor::{Rng, TestBuilder, TestOp::*}; use flowy_sync::client_document::{NewlineDoc, PlainDoc}; use lib_ot::{ + core::Interval, core::*, rich_text::{AttributeBuilder, RichTextAttribute, RichTextAttributes, RichTextDelta}, }; @@ -39,23 +40,23 @@ fn attributes_insert_text_at_middle() { #[test] fn delta_get_ops_in_interval_1() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("123").build(); - let insert_b = OpBuilder::insert("4").build(); + let insert_a = OperationBuilder::insert("123").build(); + let insert_b = OperationBuilder::insert("4").build(); delta.add(insert_a.clone()); delta.add(insert_b.clone()); - let mut iterator = DeltaIter::from_interval(&delta, Interval::new(0, 4)); + let mut iterator = DeltaIterator::from_interval(&delta, Interval::new(0, 4)); assert_eq!(iterator.ops(), delta.ops); } #[test] fn delta_get_ops_in_interval_2() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("123").build(); - let insert_b = OpBuilder::insert("4").build(); - let insert_c = OpBuilder::insert("5").build(); - let retain_a = OpBuilder::retain(3).build(); + 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(); delta.add(insert_a.clone()); delta.add(retain_a.clone()); @@ -63,32 +64,32 @@ fn delta_get_ops_in_interval_2() { delta.add(insert_c.clone()); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(0, 2)).ops(), - vec![OpBuilder::insert("12").build()] + DeltaIterator::from_interval(&delta, Interval::new(0, 2)).ops(), + vec![OperationBuilder::insert("12").build()] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(1, 3)).ops(), - vec![OpBuilder::insert("23").build()] + DeltaIterator::from_interval(&delta, Interval::new(1, 3)).ops(), + vec![OperationBuilder::insert("23").build()] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(0, 3)).ops(), + DeltaIterator::from_interval(&delta, Interval::new(0, 3)).ops(), vec![insert_a.clone()] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(0, 4)).ops(), - vec![insert_a.clone(), OpBuilder::retain(1).build()] + DeltaIterator::from_interval(&delta, Interval::new(0, 4)).ops(), + vec![insert_a.clone(), OperationBuilder::retain(1).build()] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(0, 6)).ops(), + DeltaIterator::from_interval(&delta, Interval::new(0, 6)).ops(), vec![insert_a.clone(), retain_a.clone()] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(0, 7)).ops(), + DeltaIterator::from_interval(&delta, Interval::new(0, 7)).ops(), vec![insert_a.clone(), retain_a.clone(), insert_b.clone()] ); } @@ -96,54 +97,60 @@ fn delta_get_ops_in_interval_2() { #[test] fn delta_get_ops_in_interval_3() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("123456").build(); + let insert_a = OperationBuilder::insert("123456").build(); delta.add(insert_a.clone()); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(3, 5)).ops(), - vec![OpBuilder::insert("45").build()] + DeltaIterator::from_interval(&delta, Interval::new(3, 5)).ops(), + vec![OperationBuilder::insert("45").build()] ); } #[test] fn delta_get_ops_in_interval_4() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("12").build(); - let insert_b = OpBuilder::insert("34").build(); - let insert_c = OpBuilder::insert("56").build(); + let insert_a = OperationBuilder::insert("12").build(); + let insert_b = OperationBuilder::insert("34").build(); + let insert_c = OperationBuilder::insert("56").build(); delta.ops.push(insert_a.clone()); delta.ops.push(insert_b.clone()); delta.ops.push(insert_c.clone()); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(0, 2)).ops(), + DeltaIterator::from_interval(&delta, Interval::new(0, 2)).ops(), vec![insert_a] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(2, 4)).ops(), + DeltaIterator::from_interval(&delta, Interval::new(2, 4)).ops(), vec![insert_b] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(4, 6)).ops(), + DeltaIterator::from_interval(&delta, Interval::new(4, 6)).ops(), vec![insert_c] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(2, 5)).ops(), - vec![OpBuilder::insert("34").build(), OpBuilder::insert("5").build()] + DeltaIterator::from_interval(&delta, Interval::new(2, 5)).ops(), + vec![ + OperationBuilder::insert("34").build(), + OperationBuilder::insert("5").build() + ] ); } #[test] fn delta_get_ops_in_interval_5() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("123456").build(); - let insert_b = OpBuilder::insert("789").build(); + let insert_a = OperationBuilder::insert("123456").build(); + let insert_b = OperationBuilder::insert("789").build(); delta.ops.push(insert_a.clone()); delta.ops.push(insert_b.clone()); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(4, 8)).ops(), - vec![OpBuilder::insert("56").build(), OpBuilder::insert("78").build()] + DeltaIterator::from_interval(&delta, Interval::new(4, 8)).ops(), + vec![ + OperationBuilder::insert("56").build(), + OperationBuilder::insert("78").build() + ] ); // assert_eq!( @@ -155,54 +162,60 @@ fn delta_get_ops_in_interval_5() { #[test] fn delta_get_ops_in_interval_6() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("12345678").build(); + let insert_a = OperationBuilder::insert("12345678").build(); delta.add(insert_a.clone()); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(4, 6)).ops(), - vec![OpBuilder::insert("56").build()] + DeltaIterator::from_interval(&delta, Interval::new(4, 6)).ops(), + vec![OperationBuilder::insert("56").build()] ); } #[test] fn delta_get_ops_in_interval_7() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("12345").build(); - let retain_a = OpBuilder::retain(3).build(); + let insert_a = OperationBuilder::insert("12345").build(); + let retain_a = OperationBuilder::retain(3).build(); delta.add(insert_a.clone()); delta.add(retain_a.clone()); - let mut iter_1 = DeltaIter::from_offset(&delta, 2); - assert_eq!(iter_1.next_op().unwrap(), OpBuilder::insert("345").build()); - assert_eq!(iter_1.next_op().unwrap(), OpBuilder::retain(3).build()); + 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()); - let mut iter_2 = DeltaIter::new(&delta); - assert_eq!(iter_2.next_op_with_len(2).unwrap(), OpBuilder::insert("12").build()); - assert_eq!(iter_2.next_op().unwrap(), OpBuilder::insert("345").build()); + 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().unwrap(), OpBuilder::retain(3).build()); + assert_eq!(iter_2.next_op().unwrap(), OperationBuilder::retain(3).build()); } #[test] fn delta_op_seek() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("12345").build(); - let retain_a = OpBuilder::retain(3).build(); + let insert_a = OperationBuilder::insert("12345").build(); + let retain_a = OperationBuilder::retain(3).build(); delta.add(insert_a.clone()); delta.add(retain_a.clone()); - let mut iter = DeltaIter::new(&delta); + let mut iter = DeltaIterator::new(&delta); iter.seek::<OpMetric>(1); - assert_eq!(iter.next_op().unwrap(), OpBuilder::retain(3).build()); + assert_eq!(iter.next_op().unwrap(), retain_a); } #[test] fn delta_utf16_code_unit_seek() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("12345").build()); + delta.add(OperationBuilder::insert("12345").build()); - let mut iter = DeltaIter::new(&delta); + let mut iter = DeltaIterator::new(&delta); iter.seek::<Utf16CodeUnitMetric>(3); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("45").build()); + assert_eq!( + iter.next_op_with_len(2).unwrap(), + OperationBuilder::insert("45").build() + ); } #[test] @@ -213,77 +226,92 @@ fn delta_utf16_code_unit_seek_with_attributes() { .add_attr(RichTextAttribute::Italic(true)) .build(); - delta.add(OpBuilder::insert("1234").attributes(attributes.clone()).build()); - delta.add(OpBuilder::insert("\n").build()); + delta.add(OperationBuilder::insert("1234").attributes(attributes.clone()).build()); + delta.add(OperationBuilder::insert("\n").build()); - let mut iter = DeltaIter::new(&delta); + let mut iter = DeltaIterator::new(&delta); iter.seek::<Utf16CodeUnitMetric>(0); assert_eq!( iter.next_op_with_len(4).unwrap(), - OpBuilder::insert("1234").attributes(attributes).build(), + OperationBuilder::insert("1234").attributes(attributes).build(), ); } #[test] fn delta_next_op_len() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("12345").build()); - let mut iter = DeltaIter::new(&delta); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("12").build()); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("34").build()); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("5").build()); + delta.add(OperationBuilder::insert("12345").build()); + 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(1), None); } #[test] fn delta_next_op_len_with_chinese() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("你好").build()); + delta.add(OperationBuilder::insert("你好").build()); - let mut iter = DeltaIter::new(&delta); + let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 2); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("你好").build()); + assert_eq!( + iter.next_op_with_len(2).unwrap(), + OperationBuilder::insert("你好").build() + ); } #[test] fn delta_next_op_len_with_english() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("ab").build()); - let mut iter = DeltaIter::new(&delta); + delta.add(OperationBuilder::insert("ab").build()); + let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 2); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("ab").build()); + assert_eq!( + iter.next_op_with_len(2).unwrap(), + OperationBuilder::insert("ab").build() + ); } #[test] fn delta_next_op_len_after_seek() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("12345").build()); - let mut iter = DeltaIter::new(&delta); + delta.add(OperationBuilder::insert("12345").build()); + let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 5); iter.seek::<Utf16CodeUnitMetric>(3); assert_eq!(iter.next_op_len().unwrap(), 2); - assert_eq!(iter.next_op_with_len(1).unwrap(), OpBuilder::insert("4").build()); + assert_eq!(iter.next_op_with_len(1).unwrap(), OperationBuilder::insert("4").build()); assert_eq!(iter.next_op_len().unwrap(), 1); - assert_eq!(iter.next_op().unwrap(), OpBuilder::insert("5").build()); + assert_eq!(iter.next_op().unwrap(), OperationBuilder::insert("5").build()); } #[test] fn delta_next_op_len_none() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("12345").build()); - let mut iter = DeltaIter::new(&delta); + delta.add(OperationBuilder::insert("12345").build()); + let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 5); - assert_eq!(iter.next_op_with_len(5).unwrap(), OpBuilder::insert("12345").build()); + assert_eq!( + iter.next_op_with_len(5).unwrap(), + OperationBuilder::insert("12345").build() + ); assert_eq!(iter.next_op_len(), None); } #[test] fn delta_next_op_with_len_zero() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("12345").build()); - let mut iter = DeltaIter::new(&delta); + delta.add(OperationBuilder::insert("12345").build()); + let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_with_len(0), None,); assert_eq!(iter.next_op_len().unwrap(), 5); } @@ -291,14 +319,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(OpBuilder::insert("12345").build()); - delta.add(OpBuilder::retain(1).build()); - delta.add(OpBuilder::insert("678").build()); + delta.add(OperationBuilder::insert("12345").build()); + delta.add(OperationBuilder::retain(1).build()); + delta.add(OperationBuilder::insert("678").build()); - let mut iter = DeltaIter::new(&delta); + let mut iter = DeltaIterator::new(&delta); iter.seek::<Utf16CodeUnitMetric>(4); assert_eq!(iter.next_op_len().unwrap(), 1); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::retain(1).build()); + assert_eq!(iter.next_op_with_len(2).unwrap(), OperationBuilder::retain(1).build()); } #[test] @@ -342,18 +370,17 @@ fn apply_1000() { } #[test] -fn apply() { - let s = "hello world,".to_owned(); - let mut delta_a = RichTextDelta::default(); - delta_a.insert(&s, RichTextAttributes::default()); +fn apply_test() { + let s = "hello"; + let delta_a = PlainTextDeltaBuilder::new().insert(s).build(); + let delta_b = PlainTextDeltaBuilder::new() + .retain(s.len()) + .insert(", AppFlowy") + .build(); - let mut delta_b = RichTextDelta::default(); - delta_b.retain(s.len(), RichTextAttributes::default()); - delta_b.insert("appflowy", RichTextAttributes::default()); - - let after_a = delta_a.apply("").unwrap(); + let after_a = delta_a.content_str().unwrap(); let after_b = delta_b.apply(&after_a).unwrap(); - assert_eq!("hello world,appflowy", &after_b); + assert_eq!("hello, AppFlowy", &after_b); } #[test] @@ -384,6 +411,17 @@ fn invert() { } } +#[test] +fn invert_test() { + let s = "hello world"; + let delta = PlainTextDeltaBuilder::new().insert(s).build(); + let invert_delta = delta.invert_str(""); + assert_eq!(delta.utf16_base_len, invert_delta.utf16_target_len); + assert_eq!(delta.utf16_target_len, invert_delta.utf16_base_len); + + assert_eq!(invert_delta.apply(s).unwrap(), "") +} + #[test] fn empty_ops() { let mut delta = RichTextDelta::default(); @@ -415,23 +453,24 @@ 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(&OpBuilder::retain(2).build())); + assert_eq!(delta.ops.last(), Some(&OperationBuilder::retain(2).build())); delta.retain(3, RichTextAttributes::default()); assert_eq!(delta.ops.len(), 1); - assert_eq!(delta.ops.last(), Some(&OpBuilder::retain(5).build())); + assert_eq!(delta.ops.last(), Some(&OperationBuilder::retain(5).build())); delta.insert("abc", RichTextAttributes::default()); assert_eq!(delta.ops.len(), 2); - assert_eq!(delta.ops.last(), Some(&OpBuilder::insert("abc").build())); + assert_eq!(delta.ops.last(), Some(&OperationBuilder::insert("abc").build())); delta.insert("xyz", RichTextAttributes::default()); assert_eq!(delta.ops.len(), 2); - assert_eq!(delta.ops.last(), Some(&OpBuilder::insert("abcxyz").build())); + assert_eq!(delta.ops.last(), Some(&OperationBuilder::insert("abcxyz").build())); delta.delete(1); assert_eq!(delta.ops.len(), 3); - assert_eq!(delta.ops.last(), Some(&OpBuilder::delete(1).build())); + assert_eq!(delta.ops.last(), Some(&OperationBuilder::delete(1).build())); delta.delete(1); assert_eq!(delta.ops.len(), 3); - assert_eq!(delta.ops.last(), Some(&OpBuilder::delete(2).build())); + assert_eq!(delta.ops.last(), Some(&OperationBuilder::delete(2).build())); } + #[test] fn is_noop() { let mut delta = RichTextDelta::default(); @@ -582,11 +621,11 @@ fn transform_two_conflict_non_seq_delta() { #[test] fn delta_invert_no_attribute_delta() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("123").build()); + delta.add(OperationBuilder::insert("123").build()); let mut change = RichTextDelta::default(); - change.add(OpBuilder::retain(3).build()); - change.add(OpBuilder::insert("456").build()); + change.add(OperationBuilder::retain(3).build()); + change.add(OperationBuilder::insert("456").build()); 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 87d425901b..6c578be6c3 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 = OpBuilder::insert("123").attributes(attributes).build(); + let operation = OperationBuilder::insert("123").attributes(attributes).build(); 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 = OpBuilder::insert("123").attributes(attributes).build(); + let retain = OperationBuilder::insert("123").attributes(attributes).build(); 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 = OpBuilder::insert("123").attributes(attributes).build(); + let retain = OperationBuilder::insert("123").attributes(attributes).build(); delta.add(retain); delta.add(Operation::Retain(5.into())); @@ -65,7 +65,7 @@ fn delta_serialize_multi_attribute_test() { let json = serde_json::to_string(&delta).unwrap(); eprintln!("{}", json); - let delta_from_json = Delta::from_delta_str(&json).unwrap(); + let delta_from_json = Delta::from_json_str(&json).unwrap(); assert_eq!(delta_from_json, delta); } @@ -77,7 +77,7 @@ fn delta_deserialize_test() { {"retain":2,"attributes":{"italic":"true","bold":"true"}}, {"retain":2,"attributes":{"italic":true,"bold":true}} ]"#; - let delta = RichTextDelta::from_delta_str(json).unwrap(); + let delta = RichTextDelta::from_json_str(json).unwrap(); eprintln!("{}", delta); } @@ -86,13 +86,13 @@ fn delta_deserialize_null_test() { let json = r#"[ {"retain":7,"attributes":{"bold":null}} ]"#; - let delta1 = RichTextDelta::from_delta_str(json).unwrap(); + let delta1 = RichTextDelta::from_json_str(json).unwrap(); let mut attribute = RichTextAttribute::Bold(true); attribute.value = RichTextAttributeValue(None); let delta2 = DeltaBuilder::new().retain_with_attributes(7, attribute.into()).build(); - assert_eq!(delta2.to_delta_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); + assert_eq!(delta2.to_json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); assert_eq!(delta1, delta2); } diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/undo_redo_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/undo_redo_test.rs index e6ea9200ab..78aa034744 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/undo_redo_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/undo_redo_test.rs @@ -108,6 +108,7 @@ fn history_bold_redo_with_lagging() { fn history_delete_undo() { let ops = vec![ Insert(0, "123", 0), + Wait(RECORD_THRESHOLD), AssertDocJson(0, r#"[{"insert":"123"}]"#), Delete(0, Interval::new(0, 3)), AssertDocJson(0, r#"[]"#), diff --git a/shared-lib/flowy-sync/src/client_document/default/mod.rs b/shared-lib/flowy-sync/src/client_document/default/mod.rs index f5fb180571..582e3eac2e 100644 --- a/shared-lib/flowy-sync/src/client_document/default/mod.rs +++ b/shared-lib/flowy-sync/src/client_document/default/mod.rs @@ -7,13 +7,13 @@ pub fn initial_quill_delta() -> RichTextDelta { #[inline] pub fn initial_quill_delta_string() -> String { - initial_quill_delta().to_delta_str() + initial_quill_delta().to_json_str() } #[inline] pub fn initial_read_me() -> RichTextDelta { let json = include_str!("READ_ME.json"); - RichTextDelta::from_delta_str(json).unwrap() + RichTextDelta::from_json_str(json).unwrap() } #[cfg(test)] @@ -22,6 +22,6 @@ mod tests { #[test] fn load_read_me() { - println!("{}", initial_read_me().to_delta_str()); + println!("{}", initial_read_me().to_json_str()); } } diff --git a/shared-lib/flowy-sync/src/client_document/document_pad.rs b/shared-lib/flowy-sync/src/client_document/document_pad.rs index 72b52f6415..d63d2194ad 100644 --- a/shared-lib/flowy-sync/src/client_document/document_pad.rs +++ b/shared-lib/flowy-sync/src/client_document/document_pad.rs @@ -55,16 +55,16 @@ impl ClientDocument { } pub fn from_json(json: &str) -> Result<Self, CollaborateError> { - let delta = RichTextDelta::from_delta_str(json)?; + let delta = RichTextDelta::from_json_str(json)?; Ok(Self::from_delta(delta)) } pub fn delta_str(&self) -> String { - self.delta.to_delta_str() + self.delta.to_json_str() } pub fn to_bytes(&self) -> Bytes { - self.delta.to_delta_bytes() + self.delta.to_json_bytes() } pub fn to_plain_string(&self) -> String { @@ -85,7 +85,7 @@ impl ClientDocument { } pub fn set_delta(&mut self, data: RichTextDelta) { - tracing::trace!("document: {}", data.to_delta_str()); + tracing::trace!("document: {}", data.to_json_str()); self.delta = data; match &self.notify { @@ -97,7 +97,7 @@ impl ClientDocument { } pub fn compose_delta(&mut self, delta: RichTextDelta) -> Result<(), CollaborateError> { - tracing::trace!("{} compose {}", &self.delta.to_delta_str(), delta.to_delta_str()); + tracing::trace!("{} compose {}", &self.delta.to_json_str(), delta.to_json_str()); let composed_delta = self.delta.compose(&delta)?; let mut undo_delta = delta.invert(&self.delta); diff --git a/shared-lib/flowy-sync/src/client_document/extensions/delete/preserve_line_format_merge.rs b/shared-lib/flowy-sync/src/client_document/extensions/delete/preserve_line_format_merge.rs index 4da15e5f06..6c7283e4c7 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/delete/preserve_line_format_merge.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/delete/preserve_line_format_merge.rs @@ -1,6 +1,6 @@ use crate::{client_document::DeleteExt, util::is_newline}; use lib_ot::{ - core::{Attributes, DeltaBuilder, DeltaIter, Interval, Utf16CodeUnitMetric, NEW_LINE}, + core::{Attributes, DeltaBuilder, DeltaIterator, Interval, Utf16CodeUnitMetric, NEW_LINE}, rich_text::{plain_attributes, RichTextDelta}, }; @@ -16,7 +16,7 @@ impl DeleteExt for PreserveLineFormatOnMerge { } // seek to the interval start pos. e.g. You backspace enter pos - let mut iter = DeltaIter::from_offset(delta, interval.start); + let mut iter = DeltaIterator::from_offset(delta, interval.start); // op will be the "\n" let newline_op = iter.next_op_with_len(1)?; diff --git a/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs index 46a0e0290d..4a4c00a19d 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs @@ -1,5 +1,5 @@ use lib_ot::{ - core::{DeltaBuilder, DeltaIter, Interval}, + core::{DeltaBuilder, DeltaIterator, Interval}, rich_text::{plain_attributes, AttributeScope, RichTextAttribute, RichTextDelta}, }; @@ -20,7 +20,7 @@ impl FormatExt for ResolveBlockFormat { } let mut new_delta = DeltaBuilder::new().retain(interval.start).build(); - let mut iter = DeltaIter::from_offset(delta, interval.start); + let mut iter = DeltaIterator::from_offset(delta, interval.start); let mut start = 0; let end = interval.size(); while start < end && iter.has_next() { diff --git a/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs index 383b780aca..567d06d6f2 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs @@ -1,5 +1,5 @@ use lib_ot::{ - core::{DeltaBuilder, DeltaIter, Interval}, + core::{DeltaBuilder, DeltaIterator, Interval}, rich_text::{AttributeScope, RichTextAttribute, RichTextDelta}, }; @@ -19,7 +19,7 @@ impl FormatExt for ResolveInlineFormat { return None; } let mut new_delta = DeltaBuilder::new().retain(interval.start).build(); - let mut iter = DeltaIter::from_offset(delta, interval.start); + let mut iter = DeltaIterator::from_offset(delta, interval.start); let mut start = 0; let end = interval.size(); diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs index e41470b9eb..253833d255 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs @@ -1,8 +1,6 @@ use crate::{client_document::InsertExt, util::is_newline}; -use lib_ot::{ - core::{is_empty_line_at_index, DeltaBuilder, DeltaIter}, - rich_text::{attributes_except_header, RichTextAttributeKey, RichTextDelta}, -}; +use lib_ot::core::{is_empty_line_at_index, DeltaBuilder, DeltaIterator}; +use lib_ot::rich_text::{attributes_except_header, RichTextAttributeKey, RichTextDelta}; pub struct AutoExitBlock {} @@ -21,7 +19,7 @@ impl InsertExt for AutoExitBlock { return None; } - let mut iter = DeltaIter::from_offset(delta, index); + let mut iter = DeltaIterator::from_offset(delta, index); let next = iter.next_op()?; let mut attributes = next.get_attributes(); diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs index d7f1da4f89..4c7cd642c2 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs @@ -1,6 +1,6 @@ use crate::{client_document::InsertExt, util::is_whitespace}; use lib_ot::{ - core::{count_utf16_code_units, DeltaBuilder, DeltaIter}, + core::{count_utf16_code_units, DeltaBuilder, DeltaIterator}, rich_text::{plain_attributes, RichTextAttribute, RichTextAttributes, RichTextDelta}, }; use std::cmp::min; @@ -17,7 +17,7 @@ impl InsertExt for AutoFormatExt { if !is_whitespace(text) { return None; } - let mut iter = DeltaIter::new(delta); + let mut iter = DeltaIterator::new(delta); if let Some(prev) = iter.next_op_with_len(index) { match AutoFormat::parse(prev.get_data()) { None => {} diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs index 628d55cb24..c165985493 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs @@ -1,6 +1,6 @@ use crate::client_document::InsertExt; use lib_ot::{ - core::{Attributes, DeltaBuilder, DeltaIter, NEW_LINE}, + core::{Attributes, DeltaBuilder, DeltaIterator, NEW_LINE}, rich_text::{RichTextAttributeKey, RichTextAttributes, RichTextDelta}, }; @@ -11,7 +11,7 @@ impl InsertExt for DefaultInsertAttribute { } fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> { - let iter = DeltaIter::new(delta); + let iter = DeltaIterator::new(delta); let mut attributes = RichTextAttributes::new(); // Enable each line split by "\n" remains the block attributes. for example: diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs index 2c0ceae111..03c9723d7b 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs @@ -1,6 +1,6 @@ use crate::{client_document::InsertExt, util::is_newline}; use lib_ot::{ - core::{DeltaBuilder, DeltaIter, NEW_LINE}, + core::{DeltaBuilder, DeltaIterator, NEW_LINE}, rich_text::{ attributes_except_header, plain_attributes, RichTextAttribute, RichTextAttributeKey, RichTextAttributes, RichTextDelta, @@ -18,7 +18,7 @@ impl InsertExt for PreserveBlockFormatOnInsert { return None; } - let mut iter = DeltaIter::from_offset(delta, index); + let mut iter = DeltaIterator::from_offset(delta, index); match iter.next_op_with_newline() { None => {} Some((newline_op, offset)) => { diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs index 37b31e3d26..b0de6451aa 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs @@ -3,7 +3,7 @@ use crate::{ util::{contain_newline, is_newline}, }; use lib_ot::{ - core::{DeltaBuilder, DeltaIter, OpNewline, NEW_LINE}, + core::{DeltaBuilder, DeltaIterator, OpNewline, NEW_LINE}, rich_text::{plain_attributes, RichTextAttributeKey, RichTextDelta}, }; @@ -18,7 +18,7 @@ impl InsertExt for PreserveInlineFormat { return None; } - let mut iter = DeltaIter::new(delta); + let mut iter = DeltaIterator::new(delta); let prev = iter.next_op_with_len(index)?; if OpNewline::parse(&prev).is_contain() { return None; @@ -64,7 +64,7 @@ impl InsertExt for PreserveLineFormatOnSplit { return None; } - let mut iter = DeltaIter::new(delta); + let mut iter = DeltaIterator::new(delta); let prev = iter.next_op_with_len(index)?; if OpNewline::parse(&prev).is_end() { return None; diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs index f63bf9bddf..8671049ee7 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs @@ -1,6 +1,6 @@ use crate::{client_document::InsertExt, util::is_newline}; use lib_ot::{ - core::{DeltaBuilder, DeltaIter, Utf16CodeUnitMetric, NEW_LINE}, + core::{DeltaBuilder, DeltaIterator, Utf16CodeUnitMetric, NEW_LINE}, rich_text::{RichTextAttributeKey, RichTextAttributes, RichTextDelta}, }; @@ -15,7 +15,7 @@ impl InsertExt for ResetLineFormatOnNewLine { return None; } - let mut iter = DeltaIter::new(delta); + let mut iter = DeltaIterator::new(delta); iter.seek::<Utf16CodeUnitMetric>(index); let next_op = iter.next_op()?; if !next_op.get_data().starts_with(NEW_LINE) { diff --git a/shared-lib/flowy-sync/src/client_folder/builder.rs b/shared-lib/flowy-sync/src/client_folder/builder.rs index 4c27f278f5..b055f91fb8 100644 --- a/shared-lib/flowy-sync/src/client_folder/builder.rs +++ b/shared-lib/flowy-sync/src/client_folder/builder.rs @@ -7,7 +7,7 @@ use crate::{ }; use flowy_folder_data_model::revision::{TrashRevision, WorkspaceRevision}; -use lib_ot::core::{PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use lib_ot::core::{PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -41,9 +41,9 @@ impl FolderPadBuilder { } // TODO: Reconvert from history if delta.to_str() failed. - let folder_json = delta.to_str()?; - let mut folder: FolderPad = serde_json::from_str(&folder_json).map_err(|e| { - tracing::error!("Deserialize folder from json failed: {}", folder_json); + let content = delta.content_str()?; + let mut folder: FolderPad = serde_json::from_str(&content).map_err(|e| { + tracing::error!("Deserialize folder from {} failed", content); return CollaborateError::internal().context(format!("Deserialize delta to folder failed: {}", e)); })?; folder.delta = delta; @@ -51,7 +51,7 @@ impl FolderPadBuilder { } pub(crate) fn build_with_revisions(self, revisions: Vec<Revision>) -> CollaborateResult<FolderPad> { - let folder_delta: FolderDelta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?; + let folder_delta: FolderDelta = make_delta_from_revisions::<PhantomAttributes>(revisions)?; self.build_with_delta(folder_delta) } diff --git a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs index f821c03e6f..0cbc33598e 100644 --- a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs @@ -295,7 +295,7 @@ impl FolderPad { } pub fn md5(&self) -> String { - md5(&self.delta.to_delta_bytes()) + md5(&self.delta.to_json_bytes()) } pub fn to_json(&self) -> CollaborateResult<String> { @@ -315,7 +315,7 @@ impl FolderPad { Some(_) => { let old = cloned_self.to_json()?; let new = self.to_json()?; - match cal_diff::<PlainTextAttributes>(old, new) { + match cal_diff::<PhantomAttributes>(old, new) { None => Ok(None), Some(delta) => { self.delta = self.delta.compose(&delta)?; @@ -350,7 +350,7 @@ impl FolderPad { Some(_) => { let old = cloned_self.to_json()?; let new = self.to_json()?; - match cal_diff::<PlainTextAttributes>(old, new) { + match cal_diff::<PhantomAttributes>(old, new) { None => Ok(None), Some(delta) => { self.delta = self.delta.compose(&delta)?; diff --git a/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs index 16b98dc7fc..cea6d7fd03 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs @@ -4,7 +4,7 @@ use crate::util::{cal_diff, make_delta_from_revisions}; use flowy_grid_data_model::revision::{ gen_block_id, gen_row_id, CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision, }; -use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use std::borrow::Cow; use std::collections::HashMap; use std::sync::Arc; @@ -46,7 +46,7 @@ impl GridBlockRevisionPad { } pub fn from_delta(delta: GridBlockRevisionDelta) -> CollaborateResult<Self> { - let s = delta.to_str()?; + let s = delta.content_str()?; let block_revision: GridBlockRevision = serde_json::from_str(&s).map_err(|e| { let msg = format!("Deserialize delta to block meta failed: {}", e); tracing::error!("{}", s); @@ -56,7 +56,7 @@ impl GridBlockRevisionPad { } pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> { - let block_delta: GridBlockRevisionDelta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?; + let block_delta: GridBlockRevisionDelta = make_delta_from_revisions::<PhantomAttributes>(revisions)?; Self::from_delta(block_delta) } @@ -195,10 +195,10 @@ impl GridBlockRevisionPad { Some(_) => { let old = cloned_self.to_json()?; let new = self.to_json()?; - match cal_diff::<PlainTextAttributes>(old, new) { + match cal_diff::<PhantomAttributes>(old, new) { None => Ok(None), Some(delta) => { - tracing::trace!("[GridBlockMeta] Composing delta {}", delta.to_delta_str()); + tracing::trace!("[GridBlockMeta] Composing delta {}", delta.to_json_str()); // tracing::debug!( // "[GridBlockMeta] current delta: {}", // self.delta.to_str().unwrap_or_else(|_| "".to_string()) @@ -231,11 +231,11 @@ impl GridBlockRevisionPad { } pub fn md5(&self) -> String { - md5(&self.delta.to_delta_bytes()) + md5(&self.delta.to_json_bytes()) } pub fn delta_str(&self) -> String { - self.delta.to_delta_str() + self.delta.to_json_str() } } @@ -252,7 +252,7 @@ pub fn make_grid_block_delta(block_rev: &GridBlockRevision) -> GridBlockRevision pub fn make_grid_block_revisions(user_id: &str, grid_block_meta_data: &GridBlockRevision) -> RepeatedRevision { let delta = make_grid_block_delta(grid_block_meta_data); - let bytes = delta.to_delta_bytes(); + let bytes = delta.to_json_bytes(); let revision = Revision::initial_revision(user_id, &grid_block_meta_data.block_id, bytes); revision.into() } @@ -289,7 +289,7 @@ mod tests { let change = pad.add_row_rev(row.clone(), None).unwrap().unwrap(); assert_eq!(pad.rows.first().unwrap().as_ref(), &row); assert_eq!( - change.delta.to_delta_str(), + change.delta.to_json_str(), r#"[{"retain":24},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); } @@ -303,19 +303,19 @@ mod tests { let change = pad.add_row_rev(row_1.clone(), None).unwrap().unwrap(); assert_eq!( - change.delta.to_delta_str(), + change.delta.to_json_str(), r#"[{"retain":24},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); let change = pad.add_row_rev(row_2.clone(), None).unwrap().unwrap(); assert_eq!( - change.delta.to_delta_str(), + change.delta.to_json_str(), r#"[{"retain":90},{"insert":",{\"id\":\"2\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); let change = pad.add_row_rev(row_3.clone(), Some("2".to_string())).unwrap().unwrap(); assert_eq!( - change.delta.to_delta_str(), + change.delta.to_json_str(), r#"[{"retain":157},{"insert":",{\"id\":\"3\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); @@ -381,7 +381,7 @@ mod tests { let _ = pad.add_row_rev(row.clone(), None).unwrap().unwrap(); let change = pad.delete_rows(vec![Cow::Borrowed(&row.id)]).unwrap().unwrap(); assert_eq!( - change.delta.to_delta_str(), + change.delta.to_json_str(), r#"[{"retain":24},{"delete":66},{"retain":2}]"# ); @@ -410,7 +410,7 @@ mod tests { let change = pad.update_row(changeset).unwrap().unwrap(); assert_eq!( - change.delta.to_delta_str(), + change.delta.to_json_str(), r#"[{"retain":69},{"insert":"10"},{"retain":15},{"insert":"tru"},{"delete":4},{"retain":4}]"# ); @@ -422,7 +422,7 @@ mod tests { fn test_pad() -> GridBlockRevisionPad { let delta = - GridBlockRevisionDelta::from_delta_str(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap(); + GridBlockRevisionDelta::from_json_str(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap(); GridBlockRevisionPad::from_delta(delta).unwrap() } } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs index eaa6f1823a..d1232a261d 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs @@ -9,7 +9,7 @@ use flowy_grid_data_model::revision::{ GridLayoutRevision, GridRevision, GridSettingRevision, GridSortRevision, }; use lib_infra::util::move_vec_element; -use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use std::collections::HashMap; use std::sync::Arc; @@ -52,8 +52,8 @@ impl GridRevisionPad { } pub fn from_delta(delta: GridRevisionDelta) -> CollaborateResult<Self> { - let s = delta.to_str()?; - let grid: GridRevision = serde_json::from_str(&s) + let content = delta.content_str()?; + let grid: GridRevision = serde_json::from_str(&content) .map_err(|e| CollaborateError::internal().context(format!("Deserialize delta to grid failed: {}", e)))?; Ok(Self { @@ -63,7 +63,7 @@ impl GridRevisionPad { } pub fn from_revisions(revisions: Vec<Revision>) -> CollaborateResult<Self> { - let grid_delta: GridRevisionDelta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?; + let grid_delta: GridRevisionDelta = make_delta_from_revisions::<PhantomAttributes>(revisions)?; Self::from_delta(grid_delta) } @@ -457,15 +457,15 @@ impl GridRevisionPad { } pub fn md5(&self) -> String { - md5(&self.delta.to_delta_bytes()) + md5(&self.delta.to_json_bytes()) } pub fn delta_str(&self) -> String { - self.delta.to_delta_str() + self.delta.to_json_str() } pub fn delta_bytes(&self) -> Bytes { - self.delta.to_delta_bytes() + self.delta.to_json_bytes() } pub fn fields(&self) -> &[Arc<FieldRevision>] { @@ -482,7 +482,7 @@ impl GridRevisionPad { Some(_) => { let old = make_grid_rev_json_str(&cloned_grid)?; let new = self.json_str()?; - match cal_diff::<PlainTextAttributes>(old, new) { + match cal_diff::<PhantomAttributes>(old, new) { None => Ok(None), Some(delta) => { self.delta = self.delta.compose(&delta)?; @@ -553,7 +553,7 @@ pub fn make_grid_delta(grid_rev: &GridRevision) -> GridRevisionDelta { pub fn make_grid_revisions(user_id: &str, grid_rev: &GridRevision) -> RepeatedRevision { let delta = make_grid_delta(grid_rev); - let bytes = delta.to_delta_bytes(); + let bytes = delta.to_json_bytes(); let revision = Revision::initial_revision(user_id, &grid_rev.grid_id, bytes); revision.into() } diff --git a/shared-lib/flowy-sync/src/entities/revision.rs b/shared-lib/flowy-sync/src/entities/revision.rs index d909efa3d5..408026607c 100644 --- a/shared-lib/flowy-sync/src/entities/revision.rs +++ b/shared-lib/flowy-sync/src/entities/revision.rs @@ -89,7 +89,7 @@ impl std::fmt::Debug for Revision { let _ = f.write_fmt(format_args!("rev_id {}, ", self.rev_id))?; match RichTextDelta::from_bytes(&self.delta_data) { Ok(delta) => { - let _ = f.write_fmt(format_args!("delta {:?}", delta.to_delta_str()))?; + let _ = f.write_fmt(format_args!("delta {:?}", delta.to_json_str()))?; } Err(e) => { let _ = f.write_fmt(format_args!("delta {:?}", e))?; diff --git a/shared-lib/flowy-sync/src/entities/text_block.rs b/shared-lib/flowy-sync/src/entities/text_block.rs index 8753103369..91ff7e65c4 100644 --- a/shared-lib/flowy-sync/src/entities/text_block.rs +++ b/shared-lib/flowy-sync/src/entities/text_block.rs @@ -46,7 +46,7 @@ impl std::convert::TryFrom<Revision> for DocumentPB { } let delta = RichTextDelta::from_bytes(&revision.delta_data)?; - let doc_json = delta.to_delta_str(); + let doc_json = delta.to_json_str(); Ok(DocumentPB { block_id: revision.object_id, diff --git a/shared-lib/flowy-sync/src/server_document/document_pad.rs b/shared-lib/flowy-sync/src/server_document/document_pad.rs index 1f4fa7bda1..d51919f048 100644 --- a/shared-lib/flowy-sync/src/server_document/document_pad.rs +++ b/shared-lib/flowy-sync/src/server_document/document_pad.rs @@ -39,7 +39,7 @@ impl RevisionSyncObject<RichTextAttributes> for ServerDocument { } fn to_json(&self) -> String { - self.delta.to_delta_str() + self.delta.to_json_str() } fn set_delta(&mut self, new_delta: Delta<RichTextAttributes>) { diff --git a/shared-lib/flowy-sync/src/server_folder/folder_manager.rs b/shared-lib/flowy-sync/src/server_folder/folder_manager.rs index 16b753f50b..95e3c2330f 100644 --- a/shared-lib/flowy-sync/src/server_folder/folder_manager.rs +++ b/shared-lib/flowy-sync/src/server_folder/folder_manager.rs @@ -13,7 +13,7 @@ use crate::{ use async_stream::stream; use futures::stream::StreamExt; use lib_infra::future::BoxResultFuture; -use lib_ot::core::PlainTextAttributes; +use lib_ot::core::PhantomAttributes; use std::{collections::HashMap, fmt::Debug, sync::Arc}; use tokio::{ sync::{mpsc, oneshot, RwLock}, @@ -188,7 +188,7 @@ impl ServerFolderManager { } } -type FolderRevisionSynchronizer = RevisionSynchronizer<PlainTextAttributes>; +type FolderRevisionSynchronizer = RevisionSynchronizer<PhantomAttributes>; struct OpenFolderHandler { folder_id: String, diff --git a/shared-lib/flowy-sync/src/server_folder/folder_pad.rs b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs index 09b4c9d048..29457eb65e 100644 --- a/shared-lib/flowy-sync/src/server_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs @@ -1,5 +1,5 @@ use crate::{entities::folder::FolderDelta, errors::CollaborateError, synchronizer::RevisionSyncObject}; -use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta}; +use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta}; pub struct ServerFolder { folder_id: String, @@ -15,7 +15,7 @@ impl ServerFolder { } } -impl RevisionSyncObject<PlainTextAttributes> for ServerFolder { +impl RevisionSyncObject<PhantomAttributes> for ServerFolder { fn id(&self) -> &str { &self.folder_id } @@ -32,7 +32,7 @@ impl RevisionSyncObject<PlainTextAttributes> for ServerFolder { } fn to_json(&self) -> String { - self.delta.to_delta_str() + self.delta.to_json_str() } fn set_delta(&mut self, new_delta: PlainTextDelta) { diff --git a/shared-lib/flowy-sync/src/util.rs b/shared-lib/flowy-sync/src/util.rs index c4504a806a..b845550137 100644 --- a/shared-lib/flowy-sync/src/util.rs +++ b/shared-lib/flowy-sync/src/util.rs @@ -149,7 +149,7 @@ pub fn make_folder_from_revisions_pb( folder_delta = folder_delta.compose(&delta)?; } - let text = folder_delta.to_delta_str(); + let text = folder_delta.to_json_str(); Ok(Some(FolderInfo { folder_id: folder_id.to_string(), text, @@ -183,7 +183,7 @@ pub fn make_document_from_revision_pbs( delta = delta.compose(&new_delta)?; } - let text = delta.to_delta_str(); + let text = delta.to_json_str(); Ok(Some(DocumentPB { block_id: doc_id.to_owned(), diff --git a/shared-lib/lib-ot/src/core/delta/builder.rs b/shared-lib/lib-ot/src/core/delta/builder.rs index b065b645af..44e4d4dbac 100644 --- a/shared-lib/lib-ot/src/core/delta/builder.rs +++ b/shared-lib/lib-ot/src/core/delta/builder.rs @@ -1,7 +1,12 @@ -use crate::core::{trim, Attributes, Delta, PlainTextAttributes}; +use crate::core::delta::{trim, Delta}; +use crate::core::operation::{Attributes, PhantomAttributes}; -pub type PlainTextDeltaBuilder = DeltaBuilder<PlainTextAttributes>; +pub type PlainTextDeltaBuilder = DeltaBuilder<PhantomAttributes>; +/// A builder for creating new [Delta] objects. +/// +/// Note that all edit operations must be sorted; the start point of each +/// interval must be no less than the end point of the previous one. pub struct DeltaBuilder<T: Attributes> { delta: Delta<T>, } @@ -23,6 +28,8 @@ where DeltaBuilder::default() } + /// Retain the 'n' characters with the attributes. Use 'retain' instead if you don't + /// need any attributes. pub fn retain_with_attributes(mut self, n: usize, attrs: T) -> Self { self.delta.retain(n, attrs); self @@ -33,11 +40,14 @@ where self } + /// Deletes the given interval. Panics if interval is not properly sorted. pub fn delete(mut self, n: usize) -> Self { self.delta.delete(n); self } + /// Inserts the string with attributes. Use 'insert' instead if you don't + /// need any attributes. pub fn insert_with_attributes(mut self, s: &str, attrs: T) -> Self { self.delta.insert(s, attrs); self @@ -53,6 +63,7 @@ where self } + /// Builds the `Delta` pub fn build(self) -> Delta<T> { self.delta } diff --git a/shared-lib/lib-ot/src/core/delta/cursor.rs b/shared-lib/lib-ot/src/core/delta/cursor.rs index d6ebb8b3cc..2243adb7b3 100644 --- a/shared-lib/lib-ot/src/core/delta/cursor.rs +++ b/shared-lib/lib-ot/src/core/delta/cursor.rs @@ -1,33 +1,51 @@ #![allow(clippy::while_let_on_iterator)] -use crate::{ - core::{Attributes, Delta, Interval, Operation}, - errors::{ErrorBuilder, OTError, OTErrorCode}, -}; +use crate::core::delta::Delta; +use crate::core::interval::Interval; +use crate::core::operation::{Attributes, Operation}; +use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use std::{cmp::min, iter::Enumerate, slice::Iter}; +/// A [DeltaCursor] is used to iterate the delta and return the corresponding delta. #[derive(Debug)] -pub struct OpCursor<'a, T: Attributes> { +pub struct DeltaCursor<'a, T: Attributes> { pub(crate) delta: &'a Delta<T>, pub(crate) origin_iv: Interval, pub(crate) consume_iv: Interval, pub(crate) consume_count: usize, - pub(crate) op_index: usize, + pub(crate) op_offset: usize, iter: Enumerate<Iter<'a, Operation<T>>>, next_op: Option<Operation<T>>, } -impl<'a, T> OpCursor<'a, T> +impl<'a, T> DeltaCursor<'a, T> where T: Attributes, { - pub fn new(delta: &'a Delta<T>, interval: Interval) -> OpCursor<'a, T> { + /// # Arguments + /// + /// * `delta`: The delta you want to iterate over. + /// * `interval`: The range for the cursor movement. + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::{DeltaIterator, Interval, OperationBuilder}; + /// 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(); + /// 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()]); + /// ``` + pub fn new(delta: &'a Delta<T>, interval: Interval) -> DeltaCursor<'a, T> { // debug_assert!(interval.start <= delta.target_len); let mut cursor = Self { delta, origin_iv: interval, consume_iv: interval, consume_count: 0, - op_index: 0, + op_offset: 0, iter: delta.ops.iter().enumerate(), next_op: None, }; @@ -35,17 +53,37 @@ where cursor } - // get the next operation interval + /// Returns the next operation interval pub fn next_iv(&self) -> Interval { self.next_iv_with_len(None).unwrap_or_else(|| Interval::new(0, 0)) } - pub fn next_op(&mut self) -> Option<Operation<T>> { + /// Returns the next operation + pub fn get_next_op(&mut self) -> Option<Operation<T>> { self.next_with_len(None) } - // get the last operation before the end. - // checkout the delta_next_op_with_len_cross_op_return_last test for more detail + /// Returns the reference of the next operation + pub fn next_op(&self) -> Option<&Operation<T>> { + let mut next_op = self.next_op.as_ref(); + if next_op.is_none() { + let mut offset = 0; + for op in &self.delta.ops { + offset += op.len(); + if offset > self.consume_count { + next_op = Some(op); + break; + } + } + } + next_op + } + + /// # Arguments + /// + /// * `expected_len`: Return the next operation with the specified length. + /// + /// pub fn next_with_len(&mut self, expected_len: Option<usize>) -> Option<Operation<T>> { let mut find_op = None; let holder = self.next_op.clone(); @@ -97,17 +135,24 @@ where } pub fn has_next(&self) -> bool { - self.next_iter_op().is_some() + self.next_op().is_some() } - fn descend(&mut self, index: usize) { - self.consume_iv.start += index; + /// Finds the op within the current offset. + /// This function sets the start of the consume_iv to the offset, updates the consume_count + /// and the next_op reference. + /// + /// # Arguments + /// + /// * `offset`: Represents the offset of the delta string, in Utf16CodeUnit unit. + fn descend(&mut self, offset: usize) { + self.consume_iv.start += offset; if self.consume_count >= self.consume_iv.start { return; } while let Some((o_index, op)) = self.iter.next() { - self.op_index = o_index; + self.op_offset = o_index; let start = self.consume_count; let end = start + op.len(); let intersect = Interval::new(start, end).intersect(self.consume_iv); @@ -121,7 +166,7 @@ where } fn next_iv_with_len(&self, expected_len: Option<usize>) -> Option<Interval> { - let op = self.next_iter_op()?; + let op = self.next_op()?; let start = self.consume_count; let end = match expected_len { None => self.consume_count + op.len(), @@ -132,31 +177,16 @@ where let interval = intersect.translate_neg(start); Some(interval) } - - pub fn next_iter_op(&self) -> Option<&Operation<T>> { - let mut next_op = self.next_op.as_ref(); - if next_op.is_none() { - let mut offset = 0; - for op in &self.delta.ops { - offset += op.len(); - if offset > self.consume_count { - next_op = Some(op); - break; - } - } - } - next_op - } } -fn find_next<'a, T>(cursor: &mut OpCursor<'a, T>) -> Option<&'a Operation<T>> +fn find_next<'a, T>(cursor: &mut DeltaCursor<'a, T>) -> Option<&'a Operation<T>> where T: Attributes, { match cursor.iter.next() { None => None, Some((o_index, op)) => { - cursor.op_index = o_index; + cursor.op_offset = o_index; Some(op) } } @@ -164,31 +194,34 @@ where type SeekResult = Result<(), OTError>; pub trait Metric { - fn seek<T: Attributes>(cursor: &mut OpCursor<T>, offset: usize) -> SeekResult; + fn seek<T: Attributes>(cursor: &mut DeltaCursor<T>, offset: usize) -> SeekResult; } +/// [OpMetric] is used by [DeltaIterator] for seeking operations +/// The unit of the movement is Operation pub struct OpMetric(); impl Metric for OpMetric { - fn seek<T: Attributes>(cursor: &mut OpCursor<T>, offset: usize) -> SeekResult { - let _ = check_bound(cursor.op_index, offset)?; - let mut seek_cursor = OpCursor::new(cursor.delta, cursor.origin_iv); - let mut cur_offset = 0; + fn seek<T: Attributes>(cursor: &mut DeltaCursor<T>, op_offset: usize) -> SeekResult { + let _ = check_bound(cursor.op_offset, op_offset)?; + let mut seek_cursor = DeltaCursor::new(cursor.delta, cursor.origin_iv); + while let Some((_, op)) = seek_cursor.iter.next() { - cur_offset += op.len(); - if cur_offset > offset { + cursor.descend(op.len()); + if cursor.op_offset >= op_offset { break; } } - cursor.descend(cur_offset); Ok(()) } } +/// [Utf16CodeUnitMetric] is used by [DeltaIterator] for seeking operations. +/// The unit of the movement is Utf16CodeUnit pub struct Utf16CodeUnitMetric(); impl Metric for Utf16CodeUnitMetric { - fn seek<T: Attributes>(cursor: &mut OpCursor<T>, offset: usize) -> SeekResult { + fn seek<T: Attributes>(cursor: &mut DeltaCursor<T>, offset: usize) -> SeekResult { if offset > 0 { let _ = check_bound(cursor.consume_count, offset)?; let _ = cursor.next_with_len(Some(offset)); diff --git a/shared-lib/lib-ot/src/core/delta/delta.rs b/shared-lib/lib-ot/src/core/delta/delta.rs index 29fd424dcb..2bff1a3edc 100644 --- a/shared-lib/lib-ot/src/core/delta/delta.rs +++ b/shared-lib/lib-ot/src/core/delta/delta.rs @@ -1,8 +1,9 @@ -use crate::{ - core::{operation::*, DeltaIter, FlowyStr, Interval, OperationTransformable, MAX_IV_LEN}, - errors::{ErrorBuilder, OTError, OTErrorCode}, -}; +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, OperationTransformable, PhantomAttributes}; use bytes::Bytes; use serde::de::DeserializeOwned; use std::{ @@ -13,13 +14,25 @@ use std::{ str::FromStr, }; -pub type PlainTextDelta = Delta<PlainTextAttributes>; +pub type PlainTextDelta = Delta<PhantomAttributes>; -// TODO: optimize the memory usage with Arc::make_mut or Cow +/// A [Delta] contains list of operations that consists of 'Retain', 'Delete' and 'Insert' operation. +/// Check out the [Operation] for more details. It describes the document as a sequence of +/// operations. +/// +/// If the [T] supports 'serde', that will enable delta to serialize to JSON or deserialize from +/// a JSON string. +/// #[derive(Clone, Debug, PartialEq, Eq)] pub struct Delta<T: Attributes> { pub ops: Vec<Operation<T>>, + + /// 'Delete' and 'Retain' operation will update the [utf16_base_len] + /// Transforming the other delta, it requires the utf16_base_len must be equal. pub utf16_base_len: usize, + + /// Represents the current len of the delta. + /// 'Insert' and 'Retain' operation will update the [utf16_target_len] pub utf16_target_len: usize, } @@ -81,6 +94,7 @@ where } } + /// Adding an operation. It will be added in sequence. pub fn add(&mut self, op: Operation<T>) { match op { Operation::Delete(i) => self.delete(i), @@ -89,6 +103,7 @@ where } } + /// Creating a [Delete] operation with len [n] pub fn delete(&mut self, n: usize) { if n == 0 { return; @@ -97,10 +112,11 @@ where if let Some(Operation::Delete(n_last)) = self.ops.last_mut() { *n_last += n; } else { - self.ops.push(OpBuilder::delete(n).build()); + self.ops.push(OperationBuilder::delete(n).build()); } } + /// Creating a [Insert] operation with string, [s]. pub fn insert(&mut self, s: &str, attributes: T) { let s: FlowyStr = s.into(); if s.is_empty() { @@ -119,10 +135,10 @@ where } [.., op_last @ Operation::<T>::Delete(_)] => { let new_last = op_last.clone(); - *op_last = OpBuilder::<T>::insert(&s).attributes(attributes).build(); + *op_last = OperationBuilder::<T>::insert(&s).attributes(attributes).build(); Some(new_last) } - _ => Some(OpBuilder::<T>::insert(&s).attributes(attributes).build()), + _ => Some(OperationBuilder::<T>::insert(&s).attributes(attributes).build()), }; match new_last { @@ -131,6 +147,7 @@ where } } + /// Creating a [Retain] operation with len, [n]. pub fn retain(&mut self, n: usize, attributes: T) { if n == 0 { return; @@ -143,24 +160,48 @@ where self.ops.push(new_op); } } else { - self.ops.push(OpBuilder::<T>::retain(n).attributes(attributes).build()); + self.ops + .push(OperationBuilder::<T>::retain(n).attributes(attributes).build()); } } - /// Applies an operation to a string, returning a new string. - pub fn apply(&self, s: &str) -> Result<String, OTError> { - let s: FlowyStr = s.into(); - if s.utf16_size() != self.utf16_base_len { + /// Return the a new string described by this delta. The new string will contains the input string. + /// The length of the [applied_str] must be equal to the the [utf16_base_len]. + /// + /// # Arguments + /// + /// * `applied_str`: A string represents the utf16_base_len content. it will be consumed by the [retain] + /// or [delete] operations. + /// + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::PlainTextDeltaBuilder; + /// let s = "hello"; + /// let delta_a = PlainTextDeltaBuilder::new().insert(s).build(); + /// let delta_b = PlainTextDeltaBuilder::new() + /// .retain(s.len()) + /// .insert(", AppFlowy") + /// .build(); + /// + /// let after_a = delta_a.content_str().unwrap(); + /// let after_b = delta_b.apply(&after_a).unwrap(); + /// assert_eq!("hello, AppFlowy", &after_b); + /// ``` + pub fn apply(&self, applied_str: &str) -> Result<String, OTError> { + let applied_str: FlowyStr = applied_str.into(); + if applied_str.utf16_size() != self.utf16_base_len { return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength) .msg(format!( - "Expected: {}, received: {}", + "Expected: {}, but received: {}", self.utf16_base_len, - s.utf16_size() + applied_str.utf16_size() )) .build()); } let mut new_s = String::new(); - let code_point_iter = &mut s.utf16_code_unit_iter(); + let code_point_iter = &mut applied_str.utf16_code_unit_iter(); for op in &self.ops { match &op { Operation::Retain(retain) => { @@ -181,34 +222,60 @@ where Ok(new_s) } - /// Computes the inverse of an operation. The inverse of an operation is the - /// operation that reverts the effects of the operation - pub fn invert_str(&self, s: &str) -> Self { + /// Computes the inverse [Delta]. The inverse of an operation is the + /// operation that reverts the effects of the operation + /// # Arguments + /// + /// * `inverted_s`: A string represents the utf16_base_len content. The len of [inverted_s] + /// must equal to the [utf16_base_len], it will be consumed by the [retain] or [delete] operations. + /// + /// If the delta's operations just contain a insert operation. The inverted_s must be empty string. + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::PlainTextDeltaBuilder; + /// let s = "hello world"; + /// let delta = PlainTextDeltaBuilder::new().insert(s).build(); + /// let invert_delta = delta.invert_str(s); + /// assert_eq!(delta.utf16_base_len, invert_delta.utf16_target_len); + /// assert_eq!(delta.utf16_target_len, invert_delta.utf16_base_len); + /// + /// assert_eq!(invert_delta.apply(s).unwrap(), "") + /// + /// ``` + /// + pub fn invert_str(&self, inverted_s: &str) -> Self { let mut inverted = Delta::default(); - let chars = &mut s.chars(); + let inverted_s: FlowyStr = inverted_s.into(); + let code_point_iter = &mut inverted_s.utf16_code_unit_iter(); + for op in &self.ops { match &op { Operation::Retain(retain) => { inverted.retain(retain.n, T::default()); - // TODO: use advance_by instead, but it's unstable now - // chars.advance_by(retain.num) for _ in 0..retain.n { - chars.next(); + code_point_iter.next(); } } Operation::Insert(insert) => { inverted.delete(insert.utf16_size()); } Operation::Delete(delete) => { - inverted.insert(&chars.take(*delete as usize).collect::<String>(), op.get_attributes()); + let bytes = code_point_iter + .take(*delete as usize) + .into_iter() + .flat_map(|a| str::from_utf8(a.0).ok()) + .collect::<String>(); + + inverted.insert(&bytes, op.get_attributes()); } } } inverted } - /// Checks if this operation has no effect. - #[inline] + /// Return true if the delta doesn't contain any [Insert] or [Delete] operations. pub fn is_noop(&self) -> bool { matches!(self.ops.as_slice(), [] | [Operation::Retain(_)]) } @@ -231,8 +298,8 @@ where Self: Sized, { let mut new_delta = Delta::default(); - let mut iter = DeltaIter::new(self); - let mut other_iter = DeltaIter::new(other); + let mut iter = DeltaIterator::new(self); + let mut other_iter = DeltaIterator::new(other); while iter.has_next() || other_iter.has_next() { if other_iter.is_next_insert() { @@ -252,10 +319,10 @@ where let op = iter .next_op_with_len(length) - .unwrap_or_else(|| OpBuilder::retain(length).build()); + .unwrap_or_else(|| OperationBuilder::retain(length).build()); let other_op = other_iter .next_op_with_len(length) - .unwrap_or_else(|| OpBuilder::retain(length).build()); + .unwrap_or_else(|| OperationBuilder::retain(length).build()); // debug_assert_eq!(op.len(), other_op.len(), "Composing delta failed,"); @@ -263,12 +330,16 @@ where (Operation::Retain(retain), Operation::Retain(other_retain)) => { let composed_attrs = retain.attributes.compose(&other_retain.attributes)?; - new_delta.add(OpBuilder::retain(retain.n).attributes(composed_attrs).build()) + new_delta.add(OperationBuilder::retain(retain.n).attributes(composed_attrs).build()) } (Operation::Insert(insert), Operation::Retain(other_retain)) => { let mut composed_attrs = insert.attributes.compose(&other_retain.attributes)?; composed_attrs.remove_empty(); - new_delta.add(OpBuilder::insert(op.get_data()).attributes(composed_attrs).build()) + new_delta.add( + OperationBuilder::insert(op.get_data()) + .attributes(composed_attrs) + .build(), + ) } (Operation::Retain(_), Operation::Delete(_)) => { new_delta.add(other_op); @@ -331,7 +402,7 @@ where Ordering::Less => { a_prime.retain(retain.n, composed_attrs.clone()); b_prime.retain(retain.n, composed_attrs.clone()); - next_op2 = Some(OpBuilder::retain(o_retain.n - retain.n).build()); + next_op2 = Some(OperationBuilder::retain(o_retain.n - retain.n).build()); next_op1 = ops1.next(); } Ordering::Equal => { @@ -343,14 +414,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(OpBuilder::retain(retain.n - o_retain.n).build()); + next_op1 = Some(OperationBuilder::retain(retain.n - o_retain.n).build()); next_op2 = ops2.next(); } }; } (Some(Operation::Delete(i)), Some(Operation::Delete(j))) => match i.cmp(j) { Ordering::Less => { - next_op2 = Some(OpBuilder::delete(*j - *i).build()); + next_op2 = Some(OperationBuilder::delete(*j - *i).build()); next_op1 = ops1.next(); } Ordering::Equal => { @@ -358,7 +429,7 @@ where next_op2 = ops2.next(); } Ordering::Greater => { - next_op1 = Some(OpBuilder::delete(*i - *j).build()); + next_op1 = Some(OperationBuilder::delete(*i - *j).build()); next_op2 = ops2.next(); } }, @@ -366,7 +437,7 @@ where match i.cmp(o_retain) { Ordering::Less => { a_prime.delete(*i); - next_op2 = Some(OpBuilder::retain(o_retain.n - *i).build()); + next_op2 = Some(OperationBuilder::retain(o_retain.n - *i).build()); next_op1 = ops1.next(); } Ordering::Equal => { @@ -376,7 +447,7 @@ where } Ordering::Greater => { a_prime.delete(o_retain.n); - next_op1 = Some(OpBuilder::delete(*i - o_retain.n).build()); + next_op1 = Some(OperationBuilder::delete(*i - o_retain.n).build()); next_op2 = ops2.next(); } }; @@ -385,7 +456,7 @@ where match retain.cmp(j) { Ordering::Less => { b_prime.delete(retain.n); - next_op2 = Some(OpBuilder::delete(*j - retain.n).build()); + next_op2 = Some(OperationBuilder::delete(*j - retain.n).build()); next_op1 = ops1.next(); } Ordering::Equal => { @@ -395,7 +466,7 @@ where } Ordering::Greater => { b_prime.delete(*j); - next_op1 = Some(OpBuilder::retain(retain.n - *j).build()); + next_op1 = Some(OperationBuilder::retain(retain.n - *j).build()); next_op2 = ops2.next(); } }; @@ -407,21 +478,17 @@ where fn invert(&self, other: &Self) -> Self { let mut inverted = Delta::default(); - if other.is_empty() { - return inverted; - } - let mut index = 0; for op in &self.ops { let len: usize = op.len() as usize; match op { Operation::Delete(n) => { - invert_from_other(&mut inverted, other, op, index, index + *n); + invert_other(&mut inverted, other, op, index, index + *n); index += len; } Operation::Retain(_) => { match op.has_attribute() { - true => invert_from_other(&mut inverted, other, op, index, index + len), + true => invert_other(&mut inverted, other, op, index, index + len), false => { // tracing::trace!("invert retain: {} by retain {} {}", op, len, // op.get_attributes()); @@ -452,7 +519,7 @@ where } } -fn invert_from_other<T: Attributes>( +fn invert_other<T: Attributes>( base: &mut Delta<T>, other: &Delta<T>, operation: &Operation<T>, @@ -460,7 +527,7 @@ fn invert_from_other<T: Attributes>( end: usize, ) { tracing::trace!("invert op: {} [{}:{}]", operation, start, end); - let other_ops = DeltaIter::from_interval(other, Interval::new(start, end)).ops(); + let other_ops = DeltaIterator::from_interval(other, Interval::new(start, end)).ops(); other_ops.into_iter().for_each(|other_op| match operation { Operation::Delete(_n) => { // tracing::trace!("invert delete: {} by add {}", n, other_op); @@ -501,7 +568,7 @@ impl<T> Delta<T> where T: Attributes + DeserializeOwned, { - pub fn from_delta_str(json: &str) -> Result<Self, OTError> { + pub fn from_json_str(json: &str) -> Result<Self, OTError> { let delta = serde_json::from_str(json).map_err(|e| { tracing::trace!("Deserialize failed: {:?}", e); tracing::trace!("{:?}", json); @@ -512,7 +579,7 @@ where pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<Self, OTError> { let json = str::from_utf8(bytes.as_ref())?.to_owned(); - let val = Self::from_delta_str(&json)?; + let val = Self::from_json_str(&json)?; Ok(val) } } @@ -521,16 +588,16 @@ impl<T> Delta<T> where T: Attributes + serde::Serialize, { - pub fn to_delta_str(&self) -> String { + pub fn to_json_str(&self) -> String { serde_json::to_string(self).unwrap_or_else(|_| "".to_owned()) } - pub fn to_str(&self) -> Result<String, OTError> { + pub fn content_str(&self) -> Result<String, OTError> { self.apply("") } - pub fn to_delta_bytes(&self) -> Bytes { - let json = self.to_delta_str(); + pub fn to_json_bytes(&self) -> Bytes { + let json = self.to_json_str(); Bytes::from(json.into_bytes()) } } diff --git a/shared-lib/lib-ot/src/core/delta/delta_serde.rs b/shared-lib/lib-ot/src/core/delta/delta_serde.rs index ceac31ee58..7dff063211 100644 --- a/shared-lib/lib-ot/src/core/delta/delta_serde.rs +++ b/shared-lib/lib-ot/src/core/delta/delta_serde.rs @@ -1,4 +1,5 @@ -use crate::core::{Attributes, Delta}; +use crate::core::delta::Delta; +use crate::core::operation::Attributes; use serde::{ de::{SeqAccess, Visitor}, ser::SerializeSeq, diff --git a/shared-lib/lib-ot/src/core/delta/iterator.rs b/shared-lib/lib-ot/src/core/delta/iterator.rs index ccad56845d..ba9db58428 100644 --- a/shared-lib/lib-ot/src/core/delta/iterator.rs +++ b/shared-lib/lib-ot/src/core/delta/iterator.rs @@ -1,17 +1,17 @@ use super::cursor::*; -use crate::{ - core::{Attributes, Delta, Interval, Operation, NEW_LINE}, - rich_text::RichTextAttributes, -}; +use crate::core::delta::{Delta, NEW_LINE}; +use crate::core::interval::Interval; +use crate::core::operation::{Attributes, Operation}; +use crate::rich_text::RichTextAttributes; use std::ops::{Deref, DerefMut}; pub(crate) const MAX_IV_LEN: usize = i32::MAX as usize; -pub struct DeltaIter<'a, T: Attributes> { - cursor: OpCursor<'a, T>, +pub struct DeltaIterator<'a, T: Attributes> { + cursor: DeltaCursor<'a, T>, } -impl<'a, T> DeltaIter<'a, T> +impl<'a, T> DeltaIterator<'a, T> where T: Attributes, { @@ -28,7 +28,7 @@ where } pub fn from_interval(delta: &'a Delta<T>, interval: Interval) -> Self { - let cursor = OpCursor::new(delta, interval); + let cursor = DeltaCursor::new(delta, interval); Self { cursor } } @@ -46,7 +46,7 @@ where } pub fn next_op(&mut self) -> Option<Operation<T>> { - self.cursor.next_op() + self.cursor.get_next_op() } pub fn next_op_with_len(&mut self, len: usize) -> Option<Operation<T>> { @@ -80,28 +80,28 @@ where } pub fn is_next_insert(&self) -> bool { - match self.cursor.next_iter_op() { + match self.cursor.next_op() { None => false, Some(op) => op.is_insert(), } } pub fn is_next_retain(&self) -> bool { - match self.cursor.next_iter_op() { + match self.cursor.next_op() { None => false, Some(op) => op.is_retain(), } } pub fn is_next_delete(&self) -> bool { - match self.cursor.next_iter_op() { + match self.cursor.next_op() { None => false, Some(op) => op.is_delete(), } } } -impl<'a, T> Iterator for DeltaIter<'a, T> +impl<'a, T> Iterator for DeltaIterator<'a, T> where T: Attributes, { @@ -112,7 +112,7 @@ where } pub fn is_empty_line_at_index(delta: &Delta<RichTextAttributes>, index: usize) -> bool { - let mut iter = DeltaIter::new(delta); + let mut iter = DeltaIterator::new(delta); let (prev, next) = (iter.next_op_with_len(index), iter.next_op()); if prev.is_none() { return true; @@ -128,7 +128,7 @@ pub fn is_empty_line_at_index(delta: &Delta<RichTextAttributes>, index: usize) - } pub struct AttributesIter<'a, T: Attributes> { - delta_iter: DeltaIter<'a, T>, + delta_iter: DeltaIterator<'a, T>, } impl<'a, T> AttributesIter<'a, T> @@ -141,7 +141,7 @@ where } pub fn from_interval(delta: &'a Delta<T>, interval: Interval) -> Self { - let delta_iter = DeltaIter::from_interval(delta, interval); + let delta_iter = DeltaIterator::from_interval(delta, interval); Self { delta_iter } } @@ -157,7 +157,7 @@ impl<'a, T> Deref for AttributesIter<'a, T> where T: Attributes, { - type Target = DeltaIter<'a, T>; + type Target = DeltaIterator<'a, T>; fn deref(&self) -> &Self::Target { &self.delta_iter diff --git a/shared-lib/lib-ot/src/core/flowy_str.rs b/shared-lib/lib-ot/src/core/flowy_str.rs index 95cc1735cc..9e503672eb 100644 --- a/shared-lib/lib-ot/src/core/flowy_str.rs +++ b/shared-lib/lib-ot/src/core/flowy_str.rs @@ -177,7 +177,7 @@ impl<'a> FlowyUtf16CodePointIterator<'a> { } } -use crate::core::Interval; +use crate::core::interval::Interval; use std::str; impl<'a> Iterator for FlowyUtf16CodePointIterator<'a> { @@ -226,7 +226,8 @@ pub fn len_utf8_from_first_byte(b: u8) -> usize { #[cfg(test)] mod tests { - use crate::core::{FlowyStr, Interval}; + use crate::core::flowy_str::FlowyStr; + use crate::core::interval::Interval; #[test] fn flowy_str_code_unit() { diff --git a/shared-lib/lib-ot/src/core/interval.rs b/shared-lib/lib-ot/src/core/interval.rs index a6f3131b6a..cc907ec3ea 100644 --- a/shared-lib/lib-ot/src/core/interval.rs +++ b/shared-lib/lib-ot/src/core/interval.rs @@ -157,7 +157,7 @@ impl From<RangeToInclusive<usize>> for Interval { #[cfg(test)] mod tests { - use crate::core::Interval; + use crate::core::interval::Interval; #[test] fn contains() { diff --git a/shared-lib/lib-ot/src/core/mod.rs b/shared-lib/lib-ot/src/core/mod.rs index b5bc594246..72a6dd9b74 100644 --- a/shared-lib/lib-ot/src/core/mod.rs +++ b/shared-lib/lib-ot/src/core/mod.rs @@ -3,28 +3,7 @@ mod flowy_str; mod interval; mod operation; -use crate::errors::OTError; pub use delta::*; pub use flowy_str::*; pub use interval::*; pub use operation::*; - -pub trait OperationTransformable { - /// Merges the operation with `other` into one operation while preserving - /// the changes of both. - fn compose(&self, other: &Self) -> Result<Self, OTError> - where - Self: Sized; - /// Transforms two operations a and b that happened concurrently and - /// produces two operations a' and b'. - /// (a', b') = a.transform(b) - /// a.compose(b') = b.compose(a') - fn transform(&self, other: &Self) -> Result<(Self, Self), OTError> - where - Self: Sized; - /// Inverts the operation with `other` to produces undo operation. - /// undo = a.invert(b) - /// new_b = b.compose(a) - /// b = new_b.compose(undo) - fn invert(&self, other: &Self) -> Self; -} diff --git a/shared-lib/lib-ot/src/core/operation/builder.rs b/shared-lib/lib-ot/src/core/operation/builder.rs index dc7b6dd7d9..c2cf774617 100644 --- a/shared-lib/lib-ot/src/core/operation/builder.rs +++ b/shared-lib/lib-ot/src/core/operation/builder.rs @@ -1,40 +1,38 @@ -use crate::{ - core::{Attributes, Operation, PlainTextAttributes}, - rich_text::RichTextAttributes, -}; +use crate::core::operation::{Attributes, Operation, PhantomAttributes}; +use crate::rich_text::RichTextAttributes; -pub type RichTextOpBuilder = OpBuilder<RichTextAttributes>; -pub type PlainTextOpBuilder = OpBuilder<PlainTextAttributes>; +pub type RichTextOpBuilder = OperationBuilder<RichTextAttributes>; +pub type PlainTextOpBuilder = OperationBuilder<PhantomAttributes>; -pub struct OpBuilder<T: Attributes> { +pub struct OperationBuilder<T: Attributes> { ty: Operation<T>, attrs: T, } -impl<T> OpBuilder<T> +impl<T> OperationBuilder<T> where T: Attributes, { - pub fn new(ty: Operation<T>) -> OpBuilder<T> { - OpBuilder { + pub fn new(ty: Operation<T>) -> OperationBuilder<T> { + OperationBuilder { ty, attrs: T::default(), } } - pub fn retain(n: usize) -> OpBuilder<T> { - OpBuilder::new(Operation::Retain(n.into())) + pub fn retain(n: usize) -> OperationBuilder<T> { + OperationBuilder::new(Operation::Retain(n.into())) } - pub fn delete(n: usize) -> OpBuilder<T> { - OpBuilder::new(Operation::Delete(n)) + pub fn delete(n: usize) -> OperationBuilder<T> { + OperationBuilder::new(Operation::Delete(n)) } - pub fn insert(s: &str) -> OpBuilder<T> { - OpBuilder::new(Operation::Insert(s.into())) + pub fn insert(s: &str) -> OperationBuilder<T> { + OperationBuilder::new(Operation::Insert(s.into())) } - pub fn attributes(mut self, attrs: T) -> OpBuilder<T> { + pub fn attributes(mut self, attrs: T) -> OperationBuilder<T> { self.attrs = attrs; self } diff --git a/shared-lib/lib-ot/src/core/operation/operation.rs b/shared-lib/lib-ot/src/core/operation/operation.rs index 82228c19fc..26ac7650ec 100644 --- a/shared-lib/lib-ot/src/core/operation/operation.rs +++ b/shared-lib/lib-ot/src/core/operation/operation.rs @@ -1,8 +1,9 @@ -use crate::{ - core::{FlowyStr, Interval, OpBuilder, OperationTransformable}, - errors::OTError, -}; +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; use std::{ cmp::min, fmt, @@ -10,15 +11,89 @@ use std::{ ops::{Deref, DerefMut}, }; -pub trait Attributes: fmt::Display + Eq + PartialEq + Default + Clone + Debug + OperationTransformable { - fn is_empty(&self) -> bool; +pub trait OperationTransformable { + /// Merges the operation with `other` into one operation while preserving + /// the changes of both. + /// + /// # Arguments + /// + /// * `other`: The delta gonna to merge. + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::{OperationTransformable, PlainTextDeltaBuilder}; + /// let document = PlainTextDeltaBuilder::new().build(); + /// let delta = PlainTextDeltaBuilder::new().insert("abc").build(); + /// let new_document = document.compose(&delta).unwrap(); + /// assert_eq!(new_document.content_str().unwrap(), "abc".to_owned()); + /// ``` + fn compose(&self, other: &Self) -> Result<Self, OTError> + where + Self: Sized; - // Remove the empty attribute which value is None. - fn remove_empty(&mut self); + /// Transforms two operations a and b that happened concurrently and + /// produces two operations a' and b'. + /// (a', b') = a.transform(b) + /// a.compose(b') = b.compose(a') + /// + fn transform(&self, other: &Self) -> Result<(Self, Self), OTError> + where + Self: Sized; - fn extend_other(&mut self, other: Self); + /// Returns the invert delta from the other. It can be used to do the undo operation. + /// + /// # Arguments + /// + /// * `other`: Generate the undo delta for [Other]. [Other] can compose the undo delta to return + /// to the previous state. + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::{OperationTransformable, PlainTextDeltaBuilder}; + /// let original_document = PlainTextDeltaBuilder::new().build(); + /// let delta = PlainTextDeltaBuilder::new().insert("abc").build(); + /// + /// let undo_delta = delta.invert(&original_document); + /// let new_document = original_document.compose(&delta).unwrap(); + /// let document = new_document.compose(&undo_delta).unwrap(); + /// + /// assert_eq!(original_document, document); + /// + /// ``` + fn invert(&self, other: &Self) -> Self; } +/// Each operation can carry attributes. For example, the [RichTextAttributes] has a list of key/value attributes. +/// Such as { bold: true, italic: true }. +/// +/// Because [Operation] is generic over the T, so you must specify the T. For example, the [PlainTextDelta]. It use +/// use [PhantomAttributes] as the T. [PhantomAttributes] does nothing, just a phantom. +/// +pub trait Attributes: Default + Display + Eq + PartialEq + Clone + Debug + OperationTransformable { + fn is_empty(&self) -> bool { + true + } + + /// Remove the empty attribute which value is None. + fn remove_empty(&mut self) { + // Do nothing + } + + fn extend_other(&mut self, _other: Self) { + // Do nothing + } +} + +/// [Operation] consists of three types. +/// * Delete +/// * Retain +/// * Insert +/// +/// The [T] should support serde if you want to serialize/deserialize the operation +/// to json string. You could check out the operation_serde.rs for more information. +/// #[derive(Debug, Clone, Eq, PartialEq)] pub enum Operation<T: Attributes> { Delete(usize), @@ -77,22 +152,22 @@ where let right; match self { Operation::Delete(n) => { - left = Some(OpBuilder::<T>::delete(index).build()); - right = Some(OpBuilder::<T>::delete(*n - index).build()); + left = Some(OperationBuilder::<T>::delete(index).build()); + right = Some(OperationBuilder::<T>::delete(*n - index).build()); } Operation::Retain(retain) => { - left = Some(OpBuilder::<T>::delete(index).build()); - right = Some(OpBuilder::<T>::delete(retain.n - index).build()); + left = Some(OperationBuilder::<T>::delete(index).build()); + right = Some(OperationBuilder::<T>::delete(retain.n - index).build()); } Operation::Insert(insert) => { let attributes = self.get_attributes(); left = Some( - OpBuilder::<T>::insert(&insert.s[0..index]) + OperationBuilder::<T>::insert(&insert.s[0..index]) .attributes(attributes.clone()) .build(), ); right = Some( - OpBuilder::<T>::insert(&insert.s[index..insert.utf16_size()]) + OperationBuilder::<T>::insert(&insert.s[index..insert.utf16_size()]) .attributes(attributes) .build(), ); @@ -104,16 +179,18 @@ where pub fn shrink(&self, interval: Interval) -> Option<Operation<T>> { let op = match self { - Operation::Delete(n) => OpBuilder::delete(min(*n, interval.size())).build(), - Operation::Retain(retain) => OpBuilder::retain(min(retain.n, interval.size())) + 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::Insert(insert) => { if interval.start > insert.utf16_size() { - OpBuilder::insert("").build() + OperationBuilder::insert("").build() } else { let s = insert.s.sub_str(interval).unwrap_or_else(|| "".to_owned()); - OpBuilder::insert(&s).attributes(insert.attributes.clone()).build() + OperationBuilder::insert(&s) + .attributes(insert.attributes.clone()) + .build() } } }; @@ -178,9 +255,7 @@ where #[derive(Clone, Debug, Eq, PartialEq)] pub struct Retain<T: Attributes> { - // #[serde(rename(serialize = "retain", deserialize = "retain"))] pub n: usize, - // #[serde(skip_serializing_if = "is_empty")] pub attributes: T, } @@ -212,7 +287,7 @@ where self.n += n; None } else { - Some(OpBuilder::retain(n).attributes(attributes).build()) + Some(OperationBuilder::retain(n).attributes(attributes).build()) } } @@ -255,10 +330,7 @@ where #[derive(Clone, Debug, Eq, PartialEq)] pub struct Insert<T: Attributes> { - // #[serde(rename(serialize = "insert", deserialize = "insert"))] pub s: FlowyStr, - - // #[serde(skip_serializing_if = "is_empty")] pub attributes: T, } @@ -296,7 +368,7 @@ where self.s += s; None } else { - Some(OpBuilder::<T>::insert(s).attributes(attributes).build()) + Some(OperationBuilder::<T>::insert(s).attributes(attributes).build()) } } @@ -339,24 +411,16 @@ where } #[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)] -pub struct PlainTextAttributes(); -impl fmt::Display for PlainTextAttributes { +pub struct PhantomAttributes(); +impl fmt::Display for PhantomAttributes { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("PlainAttributes") + f.write_str("PhantomAttributes") } } -impl Attributes for PlainTextAttributes { - fn is_empty(&self) -> bool { - true - } +impl Attributes for PhantomAttributes {} - fn remove_empty(&mut self) {} - - fn extend_other(&mut self, _other: Self) {} -} - -impl OperationTransformable for PlainTextAttributes { +impl OperationTransformable for PhantomAttributes { fn compose(&self, _other: &Self) -> Result<Self, OTError> { Ok(self.clone()) } diff --git a/shared-lib/lib-ot/src/core/operation/operation_serde.rs b/shared-lib/lib-ot/src/core/operation/operation_serde.rs index aefb909d0a..d029fb0e16 100644 --- a/shared-lib/lib-ot/src/core/operation/operation_serde.rs +++ b/shared-lib/lib-ot/src/core/operation/operation_serde.rs @@ -1,4 +1,5 @@ -use crate::core::{Attributes, FlowyStr, Insert, Operation, Retain}; +use crate::core::flowy_str::FlowyStr; +use crate::core::operation::{Attributes, Insert, Operation, Retain}; use serde::{ de, de::{MapAccess, SeqAccess, Visitor}, diff --git a/shared-lib/lib-ot/src/rich_text/attributes.rs b/shared-lib/lib-ot/src/rich_text/attributes.rs index d70e23228b..05d37317d2 100644 --- a/shared-lib/lib-ot/src/rich_text/attributes.rs +++ b/shared-lib/lib-ot/src/rich_text/attributes.rs @@ -1,10 +1,6 @@ #![allow(non_snake_case)] -use crate::{ - block_attribute, - core::{Attributes, Operation, OperationTransformable}, - errors::OTError, - ignore_attribute, inline_attribute, list_attribute, -}; +use crate::core::{Attributes, Operation, OperationTransformable}; +use crate::{block_attribute, errors::OTError, ignore_attribute, inline_attribute, list_attribute}; use lazy_static::lazy_static; use std::{ collections::{HashMap, HashSet}, diff --git a/shared-lib/lib-ot/src/rich_text/delta.rs b/shared-lib/lib-ot/src/rich_text/delta.rs index 99cb35f2bc..3a60cf7b02 100644 --- a/shared-lib/lib-ot/src/rich_text/delta.rs +++ b/shared-lib/lib-ot/src/rich_text/delta.rs @@ -1,7 +1,5 @@ -use crate::{ - core::{Delta, DeltaBuilder}, - rich_text::RichTextAttributes, -}; +use crate::core::{Delta, DeltaBuilder}; +use crate::rich_text::RichTextAttributes; pub type RichTextDelta = Delta<RichTextAttributes>; pub type RichTextDeltaBuilder = DeltaBuilder<RichTextAttributes>;